killbill-memoizeit
Changes
account/src/main/java/org/killbill/billing/account/api/svcs/DefaultAccountInternalApi.java 38(+10 -28)
account/src/main/java/org/killbill/billing/account/api/svcs/DefaultImmutableAccountInternalApi.java 103(+103 -0)
account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountChangeEvent.java 57(+33 -24)
account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java 10(+5 -5)
account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java 6(+3 -3)
beatrix/pom.xml 6(+6 -0)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModuleNoDB.java 38(+38 -0)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java 4(+2 -2)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueWithSubscriptionCancellation.java 9(+4 -5)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java 19(+6 -13)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java 2(+1 -1)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithDifferentBillingPeriods.java 10(+5 -5)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java 26(+13 -13)
catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java 17(+9 -8)
entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java 28(+15 -13)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java 26(+13 -13)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementContext.java 4(+2 -2)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java 17(+7 -10)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java 14(+9 -5)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionEvent.java 23(+12 -11)
entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java 34(+14 -20)
entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java 30(+16 -14)
entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java 21(+10 -11)
entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java 6(+3 -3)
entitlement/src/main/java/org/killbill/billing/entitlement/dao/DefaultBlockingStateDao.java 5(+3 -2)
entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java 5(+3 -2)
entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java 8(+5 -3)
entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java 6(+3 -3)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java 16(+8 -8)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java 35(+18 -17)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java 12(+6 -6)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java 50(+27 -23)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java 48(+14 -34)
entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java 5(+1 -4)
entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java 28(+19 -9)
entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java 17(+17 -0)
invoice/src/main/java/org/killbill/billing/invoice/api/migration/DefaultInvoiceMigrationApi.java 38(+14 -24)
invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java 55(+49 -6)
invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java 34(+11 -23)
invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java 46(+23 -23)
invoice/src/test/java/org/killbill/billing/invoice/generator/TestFixedAndRecurringInvoiceItemGenerator.java 11(+5 -6)
invoice/src/test/java/org/killbill/billing/invoice/usage/TestSubscriptionConsumableInArrear.java 2(+1 -1)
junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java 13(+7 -6)
junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java 18(+8 -10)
junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEventSet.java 24(+9 -15)
junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java 11(+5 -6)
junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java 17(+17 -0)
junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java 6(+2 -4)
overdue/src/main/java/org/killbill/billing/overdue/notification/DefaultOverduePosterBase.java 11(+6 -5)
overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusPoster.java 11(+6 -5)
overdue/src/test/java/org/killbill/billing/overdue/notification/TestDefaultOverdueCheckPoster.java 2(+1 -1)
payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java 10(+5 -5)
payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentProviderPlugin.java 39(+25 -14)
pom.xml 2(+1 -1)
profiles/killbill/src/test/java/org/killbill/billing/server/security/TestKillbillJdbcTenantRealm.java 8(+5 -3)
subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java 9(+5 -4)
subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java 8(+4 -4)
subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java 10(+6 -4)
subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoSql.java 10(+7 -3)
subscription/src/test/java/org/killbill/billing/subscription/glue/TestDefaultSubscriptionModuleNoDB.java 4(+2 -2)
subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java 8(+6 -2)
subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java 19(+18 -1)
tenant/src/test/java/org/killbill/billing/tenant/dao/TestNoCachingTenantBroadcastDao.java 32(+11 -21)
util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java 71(+49 -22)
util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java 12(+8 -4)
util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java 12(+8 -4)
util/src/main/java/org/killbill/billing/util/glue/NoCachingInternalCallContextFactoryProvider.java 42(+42 -0)
Details
diff --git a/account/src/main/java/org/killbill/billing/account/api/DefaultChangedField.java b/account/src/main/java/org/killbill/billing/account/api/DefaultChangedField.java
index 7ee0e32..8b11cfb 100644
--- a/account/src/main/java/org/killbill/billing/account/api/DefaultChangedField.java
+++ b/account/src/main/java/org/killbill/billing/account/api/DefaultChangedField.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -17,7 +19,6 @@
package org.killbill.billing.account.api;
import org.joda.time.DateTime;
-
import org.killbill.billing.events.ChangedField;
import com.fasterxml.jackson.annotation.JsonCreator;
@@ -41,12 +42,6 @@ public class DefaultChangedField implements ChangedField {
this.newValue = newValue;
}
- public DefaultChangedField(final String fieldName,
- final String oldValue,
- final String newValue) {
- this(fieldName, oldValue, newValue, new DateTime());
- }
-
@Override
public String getFieldName() {
return fieldName;
@@ -124,5 +119,4 @@ public class DefaultChangedField implements ChangedField {
}
return true;
}
-
}
diff --git a/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultAccountInternalApi.java b/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultAccountInternalApi.java
index 0903c13..57203fc 100644
--- a/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultAccountInternalApi.java
+++ b/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultAccountInternalApi.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -28,9 +30,9 @@ import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountEmail;
import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.account.api.DefaultAccountEmail;
-import org.killbill.billing.account.api.DefaultImmutableAccountData;
import org.killbill.billing.account.api.DefaultMutableAccountData;
import org.killbill.billing.account.api.ImmutableAccountData;
+import org.killbill.billing.account.api.ImmutableAccountInternalApi;
import org.killbill.billing.account.api.MutableAccountData;
import org.killbill.billing.account.api.user.DefaultAccountApiBase;
import org.killbill.billing.account.dao.AccountDao;
@@ -43,7 +45,6 @@ import org.killbill.billing.util.cache.Cachable.CacheType;
import org.killbill.billing.util.cache.CacheController;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.cache.CacheLoaderArgument;
-import org.killbill.billing.util.cache.ImmutableAccountCacheLoader.LoaderCallback;
import org.killbill.billing.util.dao.NonEntityDao;
import com.google.common.base.Function;
@@ -52,21 +53,18 @@ import com.google.common.collect.ImmutableList;
public class DefaultAccountInternalApi extends DefaultAccountApiBase implements AccountInternalApi {
+ private final ImmutableAccountInternalApi immutableAccountInternalApi;
private final AccountDao accountDao;
- private final CacheControllerDispatcher cacheControllerDispatcher;
- private final CacheController accountCacheController;
private final CacheController bcdCacheController;
- private final NonEntityDao nonEntityDao;
@Inject
- public DefaultAccountInternalApi(final AccountDao accountDao,
+ public DefaultAccountInternalApi(final ImmutableAccountInternalApi immutableAccountInternalApi,
+ final AccountDao accountDao,
final NonEntityDao nonEntityDao,
final CacheControllerDispatcher cacheControllerDispatcher) {
super(accountDao, nonEntityDao, cacheControllerDispatcher);
+ this.immutableAccountInternalApi = immutableAccountInternalApi;
this.accountDao = accountDao;
- this.nonEntityDao = nonEntityDao;
- this.cacheControllerDispatcher = cacheControllerDispatcher;
- this.accountCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_IMMUTABLE);
this.bcdCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_BCD);
}
@@ -142,14 +140,12 @@ public class DefaultAccountInternalApi extends DefaultAccountApiBase implements
@Override
public ImmutableAccountData getImmutableAccountDataById(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
- final Long recordId = nonEntityDao.retrieveRecordIdFromObject(accountId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
- return getImmutableAccountDataByRecordId(recordId, context);
+ return immutableAccountInternalApi.getImmutableAccountDataById(accountId, context);
}
@Override
public ImmutableAccountData getImmutableAccountDataByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
- final CacheLoaderArgument arg = createImmutableAccountCacheLoaderArgument(context);
- return (ImmutableAccountData) accountCacheController.get(recordId, arg);
+ return immutableAccountInternalApi.getImmutableAccountDataByRecordId(recordId, context);
}
private AccountModelDao getAccountModelDaoByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
@@ -165,20 +161,6 @@ public class DefaultAccountInternalApi extends DefaultAccountApiBase implements
return bcd != null ? bcd : DefaultMutableAccountData.DEFAULT_BILLING_CYCLE_DAY_LOCAL;
}
- private CacheLoaderArgument createImmutableAccountCacheLoaderArgument(final InternalTenantContext context) {
- final LoaderCallback loaderCallback = new LoaderCallback() {
- @Override
- public Object loadAccount(final Long recordId, final InternalTenantContext context) {
- final Account account = getAccountByRecordIdInternal(recordId, context);
- return account != null ? new DefaultImmutableAccountData(account) : null;
- }
- };
- final Object[] args = new Object[1];
- args[0] = loaderCallback;
- final ObjectType irrelevant = null;
- return new CacheLoaderArgument(irrelevant, args, context);
- }
-
private CacheLoaderArgument createBCDCacheLoaderArgument(final InternalTenantContext context) {
final AccountBCDCacheLoader.LoaderCallback loaderCallback = new AccountBCDCacheLoader.LoaderCallback() {
@Override
diff --git a/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultImmutableAccountInternalApi.java b/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultImmutableAccountInternalApi.java
new file mode 100644
index 0000000..250d47a
--- /dev/null
+++ b/account/src/main/java/org/killbill/billing/account/api/svcs/DefaultImmutableAccountInternalApi.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.account.api.svcs;
+
+import java.util.UUID;
+
+import org.killbill.billing.ObjectType;
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.AccountApiException;
+import org.killbill.billing.account.api.DefaultAccount;
+import org.killbill.billing.account.api.DefaultImmutableAccountData;
+import org.killbill.billing.account.api.ImmutableAccountData;
+import org.killbill.billing.account.api.ImmutableAccountInternalApi;
+import org.killbill.billing.account.dao.AccountModelDao;
+import org.killbill.billing.account.dao.AccountSqlDao;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+import org.killbill.billing.util.cache.CacheController;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.cache.CacheLoaderArgument;
+import org.killbill.billing.util.cache.ImmutableAccountCacheLoader.LoaderCallback;
+import org.killbill.billing.util.dao.NonEntityDao;
+import org.killbill.billing.util.entity.dao.EntitySqlDao;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
+import org.killbill.clock.Clock;
+import org.skife.jdbi.v2.IDBI;
+
+import com.google.inject.Inject;
+
+public class DefaultImmutableAccountInternalApi implements ImmutableAccountInternalApi {
+
+ private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
+ private final NonEntityDao nonEntityDao;
+ private final CacheControllerDispatcher cacheControllerDispatcher;
+ private final CacheController accountCacheController;
+
+ @Inject
+ public DefaultImmutableAccountInternalApi(final IDBI dbi,
+ final Clock clock,
+ final NonEntityDao nonEntityDao,
+ final CacheControllerDispatcher cacheControllerDispatcher) {
+ // This API will directly issue queries instead of relying on the DAO (introduced to avoid Guice circular dependencies with InternalCallContextFactory)
+ this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, null);
+ this.nonEntityDao = nonEntityDao;
+ this.cacheControllerDispatcher = cacheControllerDispatcher;
+ this.accountCacheController = cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_IMMUTABLE);
+ }
+
+ @Override
+ public ImmutableAccountData getImmutableAccountDataById(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
+ final Long recordId = nonEntityDao.retrieveRecordIdFromObject(accountId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
+ return getImmutableAccountDataByRecordId(recordId, context);
+ }
+
+ @Override
+ public ImmutableAccountData getImmutableAccountDataByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
+ final CacheLoaderArgument arg = createImmutableAccountCacheLoaderArgument(context);
+ return (ImmutableAccountData) accountCacheController.get(recordId, arg);
+ }
+
+ private CacheLoaderArgument createImmutableAccountCacheLoaderArgument(final InternalTenantContext context) {
+ final LoaderCallback loaderCallback = new LoaderCallback() {
+ @Override
+ public Object loadAccount(final Long recordId, final InternalTenantContext context) {
+ final Account account = getAccountByRecordIdInternal(recordId, context);
+ return account != null ? new DefaultImmutableAccountData(account) : null;
+ }
+ };
+
+ final Object[] args = {loaderCallback};
+ return new CacheLoaderArgument(null, args, context);
+ }
+
+ private Account getAccountByRecordIdInternal(final Long recordId, final InternalTenantContext context) {
+ final AccountModelDao accountModelDao = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<AccountModelDao>() {
+
+ @Override
+ public AccountModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+ final EntitySqlDao<AccountModelDao, Account> transactional = entitySqlDaoWrapperFactory.become(AccountSqlDao.class);
+ return transactional.getByRecordId(recordId, context);
+ }
+ });
+
+ return accountModelDao != null ? new DefaultAccount(accountModelDao) : null;
+ }
+}
diff --git a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountChangeEvent.java b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountChangeEvent.java
index 9ee7111..d68f0dc 100644
--- a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountChangeEvent.java
+++ b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountChangeEvent.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -17,9 +19,11 @@
package org.killbill.billing.account.api.user;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.UUID;
+import org.joda.time.DateTime;
import org.killbill.billing.account.api.DefaultChangedField;
import org.killbill.billing.account.dao.AccountModelDao;
import org.killbill.billing.events.AccountChangeInternalEvent;
@@ -47,10 +51,16 @@ public class DefaultAccountChangeEvent extends BusEventBase implements AccountCh
this.changedFields = changedFields;
}
- public DefaultAccountChangeEvent(final UUID id, final AccountModelDao oldData, final AccountModelDao newData, final Long searchKey1, final Long searchKey2, final UUID userToken) {
+ public DefaultAccountChangeEvent(final UUID id,
+ final AccountModelDao oldData,
+ final AccountModelDao newData,
+ final Long searchKey1,
+ final Long searchKey2,
+ final UUID userToken,
+ final DateTime changeDate) {
super(searchKey1, searchKey2, userToken);
this.accountId = id;
- this.changedFields = calculateChangedFields(oldData, newData);
+ this.changedFields = calculateChangedFields(oldData, newData, changeDate);
}
@JsonIgnore
@@ -73,7 +83,7 @@ public class DefaultAccountChangeEvent extends BusEventBase implements AccountCh
@JsonIgnore
@Override
public boolean hasChanges() {
- return (changedFields.size() > 0);
+ return (!changedFields.isEmpty());
}
@Override
@@ -116,57 +126,56 @@ public class DefaultAccountChangeEvent extends BusEventBase implements AccountCh
return true;
}
- private List<ChangedField> calculateChangedFields(final AccountModelDao oldData, final AccountModelDao newData) {
-
+ private List<ChangedField> calculateChangedFields(final AccountModelDao oldData, final AccountModelDao newData, final DateTime changeDate) {
final List<ChangedField> tmpChangedFields = new ArrayList<ChangedField>();
addIfValueChanged(tmpChangedFields, "externalKey",
- oldData.getExternalKey(), newData.getExternalKey());
+ oldData.getExternalKey(), newData.getExternalKey(), changeDate);
addIfValueChanged(tmpChangedFields, "email",
- oldData.getEmail(), newData.getEmail());
+ oldData.getEmail(), newData.getEmail(), changeDate);
addIfValueChanged(tmpChangedFields, "firstName",
- oldData.getName(), newData.getName());
+ oldData.getName(), newData.getName(), changeDate);
addIfValueChanged(tmpChangedFields, "currency",
(oldData.getCurrency() != null) ? oldData.getCurrency().toString() : null,
- (newData.getCurrency() != null) ? newData.getCurrency().toString() : null);
+ (newData.getCurrency() != null) ? newData.getCurrency().toString() : null, changeDate);
addIfValueChanged(tmpChangedFields,
"billCycleDayLocal",
- String.valueOf(oldData.getBillingCycleDayLocal()), String.valueOf(newData.getBillingCycleDayLocal()));
+ String.valueOf(oldData.getBillingCycleDayLocal()), String.valueOf(newData.getBillingCycleDayLocal()), changeDate);
addIfValueChanged(tmpChangedFields, "paymentMethodId",
(oldData.getPaymentMethodId() != null) ? oldData.getPaymentMethodId().toString() : null,
- (newData.getPaymentMethodId() != null) ? newData.getPaymentMethodId().toString() : null);
+ (newData.getPaymentMethodId() != null) ? newData.getPaymentMethodId().toString() : null, changeDate);
- addIfValueChanged(tmpChangedFields, "locale", oldData.getLocale(), newData.getLocale());
+ addIfValueChanged(tmpChangedFields, "locale", oldData.getLocale(), newData.getLocale(), changeDate);
addIfValueChanged(tmpChangedFields, "timeZone",
(oldData.getTimeZone() == null) ? null : oldData.getTimeZone().toString(),
- (newData.getTimeZone() == null) ? null : newData.getTimeZone().toString());
+ (newData.getTimeZone() == null) ? null : newData.getTimeZone().toString(), changeDate);
- addIfValueChanged(tmpChangedFields, "address1", oldData.getAddress1(), newData.getAddress1());
- addIfValueChanged(tmpChangedFields, "address2", oldData.getAddress2(), newData.getAddress2());
- addIfValueChanged(tmpChangedFields, "city", oldData.getCity(), newData.getCity());
- addIfValueChanged(tmpChangedFields, "stateOrProvince", oldData.getStateOrProvince(), newData.getStateOrProvince());
- addIfValueChanged(tmpChangedFields, "country", oldData.getCountry(), newData.getCountry());
- addIfValueChanged(tmpChangedFields, "postalCode", oldData.getPostalCode(), newData.getPostalCode());
- addIfValueChanged(tmpChangedFields, "phone", oldData.getPhone(), newData.getPhone());
+ addIfValueChanged(tmpChangedFields, "address1", oldData.getAddress1(), newData.getAddress1(), changeDate);
+ addIfValueChanged(tmpChangedFields, "address2", oldData.getAddress2(), newData.getAddress2(), changeDate);
+ addIfValueChanged(tmpChangedFields, "city", oldData.getCity(), newData.getCity(), changeDate);
+ addIfValueChanged(tmpChangedFields, "stateOrProvince", oldData.getStateOrProvince(), newData.getStateOrProvince(), changeDate);
+ addIfValueChanged(tmpChangedFields, "country", oldData.getCountry(), newData.getCountry(), changeDate);
+ addIfValueChanged(tmpChangedFields, "postalCode", oldData.getPostalCode(), newData.getPostalCode(), changeDate);
+ addIfValueChanged(tmpChangedFields, "phone", oldData.getPhone(), newData.getPhone(), changeDate);
return tmpChangedFields;
}
- private void addIfValueChanged(final List<ChangedField> inputList, final String key, final String oldData, final String newData) {
+ private void addIfValueChanged(final Collection<ChangedField> inputList, final String key, final String oldData, final String newData, final DateTime changeDate) {
// If both null => no changes
if (newData == null && oldData == null) {
// If only one is null
} else if (newData == null || oldData == null) {
- inputList.add(new DefaultChangedField(key, oldData, newData));
+ inputList.add(new DefaultChangedField(key, oldData, newData, changeDate));
// If neither are null we can safely compare values
} else if (!newData.equals(oldData)) {
- inputList.add(new DefaultChangedField(key, oldData, newData));
+ inputList.add(new DefaultChangedField(key, oldData, newData, changeDate));
}
}
}
diff --git a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java
index b137cc0..bef0089 100644
--- a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java
+++ b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java
@@ -72,7 +72,7 @@ public class DefaultAccountUserApi extends DefaultAccountApiBase implements Acco
@Override
public Account getAccountById(final UUID id, final TenantContext context) throws AccountApiException {
- final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(context);
+ final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(id, context);
return getAccountById(id, internalTenantContext);
}
diff --git a/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java b/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
index 31c33e3..19eb29a 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -57,13 +59,15 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
private final PersistentBus eventBus;
private final InternalCallContextFactory internalCallContextFactory;
+ private final Clock clock;
@Inject
public DefaultAccountDao(final IDBI dbi, final PersistentBus eventBus, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
final InternalCallContextFactory internalCallContextFactory, final NonEntityDao nonEntityDao) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), AccountSqlDao.class);
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), AccountSqlDao.class);
this.eventBus = eventBus;
this.internalCallContextFactory = internalCallContextFactory;
+ this.clock = clock;
}
@Override
@@ -157,8 +161,8 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
specifiedAccount,
context.getAccountRecordId(),
context.getTenantRecordId(),
- context.getUserToken()
- );
+ context.getUserToken(),
+ clock.getUTCNow());
try {
eventBus.postFromTransaction(changeEvent, entitySqlDaoWrapperFactory.getHandle().getConnection());
} catch (final EventBusException e) {
@@ -195,8 +199,8 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(accountId, currentAccount, account,
context.getAccountRecordId(),
context.getTenantRecordId(),
- context.getUserToken()
- );
+ context.getUserToken(),
+ clock.getUTCNow());
try {
eventBus.postFromTransaction(changeEvent, entitySqlDaoWrapperFactory.getHandle().getConnection());
diff --git a/account/src/main/java/org/killbill/billing/account/glue/DefaultAccountModule.java b/account/src/main/java/org/killbill/billing/account/glue/DefaultAccountModule.java
index 705ae60..c5931f6 100644
--- a/account/src/main/java/org/killbill/billing/account/glue/DefaultAccountModule.java
+++ b/account/src/main/java/org/killbill/billing/account/glue/DefaultAccountModule.java
@@ -22,7 +22,9 @@ import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.account.api.AccountService;
import org.killbill.billing.account.api.AccountUserApi;
import org.killbill.billing.account.api.DefaultAccountService;
+import org.killbill.billing.account.api.ImmutableAccountInternalApi;
import org.killbill.billing.account.api.svcs.DefaultAccountInternalApi;
+import org.killbill.billing.account.api.svcs.DefaultImmutableAccountInternalApi;
import org.killbill.billing.account.api.user.DefaultAccountUserApi;
import org.killbill.billing.account.dao.AccountDao;
import org.killbill.billing.account.dao.DefaultAccountDao;
@@ -51,6 +53,7 @@ public class DefaultAccountModule extends KillBillModule implements AccountModul
@Override
public void installInternalApi() {
bind(AccountInternalApi.class).to(DefaultAccountInternalApi.class).asEagerSingleton();
+ bind(ImmutableAccountInternalApi.class).to(DefaultImmutableAccountInternalApi.class).asEagerSingleton();
}
private void installAccountService() {
diff --git a/account/src/test/java/org/killbill/billing/account/AccountTestSuiteWithEmbeddedDB.java b/account/src/test/java/org/killbill/billing/account/AccountTestSuiteWithEmbeddedDB.java
index b441e7b..88bcf6b 100644
--- a/account/src/test/java/org/killbill/billing/account/AccountTestSuiteWithEmbeddedDB.java
+++ b/account/src/test/java/org/killbill/billing/account/AccountTestSuiteWithEmbeddedDB.java
@@ -16,6 +16,11 @@
package org.killbill.billing.account;
+import org.killbill.billing.ObjectType;
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.AccountApiException;
+import org.killbill.billing.account.api.AccountData;
+import org.killbill.billing.util.cache.Cachable.CacheType;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
@@ -80,4 +85,14 @@ public abstract class AccountTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
public void afterMethod() throws Exception {
bus.stop();
}
+
+ protected Account createAccount(final AccountData accountData) throws AccountApiException {
+ final Account account = accountUserApi.createAccount(accountData, callContext);
+
+ final Long accountRecordId = nonEntityDao.retrieveRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, controlCacheDispatcher.getCacheController(CacheType.RECORD_ID));
+ internalCallContext.setAccountRecordId(accountRecordId);
+ internalCallContext.setReferenceDateTimeZone(account.getTimeZone());
+
+ return account;
+ }
}
diff --git a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java
index 39bbb72..1b4f12a 100644
--- a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java
+++ b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java
@@ -50,7 +50,7 @@ public class TestDefaultAccountUserApi extends AccountTestSuiteWithEmbeddedDB {
final AccountModelDao accountModelDao = createTestAccount();
final AccountData defaultAccount = new DefaultAccount(accountModelDao);
- final Account account = accountUserApi.createAccount(defaultAccount, callContext);
+ final Account account = createAccount(defaultAccount);
await().atMost(10, SECONDS).until(new Callable<Boolean>() {
@Override
@@ -67,7 +67,7 @@ public class TestDefaultAccountUserApi extends AccountTestSuiteWithEmbeddedDB {
@Test(groups = "slow", description = "Test Account update with null values")
public void testShouldBeAbleToPassNullForSomeFieldsToAvoidUpdate() throws Exception {
- final Account account = accountUserApi.createAccount(new DefaultAccount(createTestAccount()), callContext);
+ final Account account = createAccount(new DefaultAccount(createTestAccount()));
// Update the address and leave other fields null
final MutableAccountData mutableAccountData = new DefaultMutableAccountData(null, null, null, 0, null, 0, null,
@@ -88,7 +88,7 @@ public class TestDefaultAccountUserApi extends AccountTestSuiteWithEmbeddedDB {
@Test(groups = "slow", expectedExceptions = IllegalArgumentException.class, description = "Test updating Account BCD does throws an exception")
public void testShouldntBeAbleToUpdateBillCycleDay() throws Exception {
- final Account account = accountUserApi.createAccount(new DefaultAccount(createTestAccount()), callContext);
+ final Account account = createAccount(new DefaultAccount(createTestAccount()));
final MutableAccountData otherAccount = new DefaultAccount(account.getId(), account).toMutableAccountData();
otherAccount.setBillCycleDayLocal(account.getBillCycleDayLocal() + 2);
@@ -98,7 +98,7 @@ public class TestDefaultAccountUserApi extends AccountTestSuiteWithEmbeddedDB {
@Test(groups = "slow", expectedExceptions = IllegalArgumentException.class, description = "Test updating Account currency throws an exception")
public void testShouldntBeAbleToUpdateCurrency() throws Exception {
- final Account account = accountUserApi.createAccount(new DefaultAccount(createTestAccount()), callContext);
+ final Account account = createAccount(new DefaultAccount(createTestAccount()));
final MutableAccountData otherAccount = new DefaultAccount(account.getId(), account).toMutableAccountData();
otherAccount.setCurrency(Currency.GBP);
@@ -108,7 +108,7 @@ public class TestDefaultAccountUserApi extends AccountTestSuiteWithEmbeddedDB {
@Test(groups = "slow", expectedExceptions = IllegalArgumentException.class, description = "Test updating Account externalKey throws an exception")
public void testShouldntBeAbleToUpdateExternalKey() throws Exception {
- final Account account = accountUserApi.createAccount(new DefaultAccount(createTestAccount()), callContext);
+ final Account account = createAccount(new DefaultAccount(createTestAccount()));
final MutableAccountData otherAccount = new DefaultAccount(account.getId(), account).toMutableAccountData();
otherAccount.setExternalKey(UUID.randomUUID().toString());
diff --git a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
index f3d7863..6cf12f7 100644
--- a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
+++ b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -52,7 +52,7 @@ public class TestDefaultAccountUserApiWithMocks extends AccountTestSuiteNoDB {
@BeforeMethod(groups = "fast")
public void setUp() throws Exception {
- accountDao = new MockAccountDao(Mockito.mock(PersistentBus.class));
+ accountDao = new MockAccountDao(Mockito.mock(PersistentBus.class), clock);
accountUserApi = new DefaultAccountUserApi(accountDao, nonEntityDao, controllerDispatcher, internalFactory);
}
diff --git a/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java b/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java
index 23ccdf7..23e3aa3 100644
--- a/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java
+++ b/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java
@@ -37,8 +37,8 @@ public class TestEventJson extends AccountTestSuiteNoDB {
@Test(groups = "fast", description="Test Account event deserialization")
public void testDefaultAccountChangeEvent() throws Exception {
final List<ChangedField> changes = new ArrayList<ChangedField>();
- changes.add(new DefaultChangedField("fieldXX", "valueX", "valueXXX"));
- changes.add(new DefaultChangedField("fieldYY", "valueY", "valueYYY"));
+ changes.add(new DefaultChangedField("fieldXX", "valueX", "valueXXX", clock.getUTCNow()));
+ changes.add(new DefaultChangedField("fieldYY", "valueY", "valueYYY", clock.getUTCNow()));
final AccountChangeInternalEvent e = new DefaultAccountChangeEvent(changes, UUID.randomUUID(), 1L, 2L, null);
final String json = mapper.writeValueAsString(e);
diff --git a/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java b/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java
index a06aa3f..0c33683 100644
--- a/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java
+++ b/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -16,13 +18,12 @@
package org.killbill.billing.account.dao;
+import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-import org.testng.Assert;
-
import org.killbill.billing.BillingExceptionBase;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.account.api.Account;
@@ -33,8 +34,6 @@ import org.killbill.billing.account.api.DefaultMutableAccountData;
import org.killbill.billing.account.api.user.DefaultAccountChangeEvent;
import org.killbill.billing.account.api.user.DefaultAccountCreationEvent;
import org.killbill.billing.account.api.user.DefaultAccountCreationEvent.DefaultAccountData;
-import org.killbill.bus.api.PersistentBus;
-import org.killbill.bus.api.PersistentBus.EventBusException;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.events.AccountChangeInternalEvent;
@@ -42,6 +41,10 @@ import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.entity.DefaultPagination;
import org.killbill.billing.util.entity.Pagination;
import org.killbill.billing.util.entity.dao.MockEntityDaoBase;
+import org.killbill.bus.api.PersistentBus;
+import org.killbill.bus.api.PersistentBus.EventBusException;
+import org.killbill.clock.Clock;
+import org.testng.Assert;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
@@ -52,10 +55,12 @@ public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account,
private final MockEntityDaoBase<AccountEmailModelDao, AccountEmail, AccountApiException> accountEmailSqlDao = new MockEntityDaoBase<AccountEmailModelDao, AccountEmail, AccountApiException>();
private final PersistentBus eventBus;
+ private final Clock clock;
@Inject
- public MockAccountDao(final PersistentBus eventBus) {
+ public MockAccountDao(final PersistentBus eventBus, final Clock clock) {
this.eventBus = eventBus;
+ this.clock = clock;
}
@Override
@@ -81,8 +86,8 @@ public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account,
final long tenantRecordId = context == null ? InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID
: context.getTenantRecordId();
final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), currentAccount, account,
- accountRecordId, tenantRecordId, UUID.randomUUID()
- );
+ accountRecordId, tenantRecordId, UUID.randomUUID(),
+ clock.getUTCNow());
if (changeEvent.hasChanges()) {
try {
eventBus.post(changeEvent);
@@ -106,7 +111,7 @@ public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account,
@Override
public Pagination<AccountModelDao> searchAccounts(final String searchKey, final Long offset, final Long limit, final InternalTenantContext context) {
- final List<AccountModelDao> results = new LinkedList<AccountModelDao>();
+ final Collection<AccountModelDao> results = new LinkedList<AccountModelDao>();
int maxNbRecords = 0;
for (final AccountModelDao account : getAll(context)) {
maxNbRecords++;
@@ -145,7 +150,7 @@ public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account,
public void addEmail(final AccountEmailModelDao email, final InternalCallContext context) {
try {
accountEmailSqlDao.create(email, context);
- } catch (BillingExceptionBase billingExceptionBase) {
+ } catch (final BillingExceptionBase billingExceptionBase) {
Assert.fail(billingExceptionBase.toString());
}
}
@@ -170,5 +175,4 @@ public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account,
final AccountModelDao account = getById(accountId, context);
return account != null ? account.getBillingCycleDayLocal() : 0;
}
-
}
diff --git a/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java b/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
index fc3fece..1592f85 100644
--- a/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
+++ b/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
@@ -113,28 +113,31 @@ public class TestAccountDao extends AccountTestSuiteWithEmbeddedDB {
final AccountModelDao account1 = createTestAccount();
accountDao.create(account1, internalCallContext);
final Long account1RecordId = nonEntityDao.retrieveAccountRecordIdFromObject(account1.getId(), ObjectType.ACCOUNT, null);
- final InternalCallContext internalCallContext1 = new InternalCallContext(internalCallContext, account1RecordId);
+ internalCallContext.setAccountRecordId(account1RecordId);
+ internalCallContext.setReferenceDateTimeZone(account1.getTimeZone());
// Verify audits via account record id
- final DefaultAccountAuditLogs auditLogsForAccount1ViaAccountRecordId1 = auditDao.getAuditLogsForAccountRecordId(AuditLevel.FULL, internalCallContext1);
+ final DefaultAccountAuditLogs auditLogsForAccount1ViaAccountRecordId1 = auditDao.getAuditLogsForAccountRecordId(AuditLevel.FULL, internalCallContext);
Assert.assertEquals(auditLogsForAccount1ViaAccountRecordId1.getAuditLogsForAccount().size(), 1);
Assert.assertEquals(auditLogsForAccount1ViaAccountRecordId1.getAuditLogsForAccount().get(0).getChangeType(), ChangeType.INSERT);
// Add an entry in the account_history table to make sure we pick up the right
// record id / target record id / account record id in the audit_log table
- accountDao.updatePaymentMethod(account1.getId(), UUID.randomUUID(), internalCallContext1);
+ accountDao.updatePaymentMethod(account1.getId(), UUID.randomUUID(), internalCallContext);
final AccountModelDao account2 = createTestAccount();
accountDao.create(account2, internalCallContext);
final Long account2RecordId = nonEntityDao.retrieveAccountRecordIdFromObject(account2.getId(), ObjectType.ACCOUNT, null);
- final InternalTenantContext internalTenantContext2 = new InternalCallContext(internalCallContext, account2RecordId);
+ internalCallContext.setAccountRecordId(account2RecordId);
+ internalCallContext.setReferenceDateTimeZone(account2.getTimeZone());
// Verify audits via account record id
- final DefaultAccountAuditLogs auditLogsForAccount2ViaAccountRecordId = auditDao.getAuditLogsForAccountRecordId(AuditLevel.FULL, internalTenantContext2);
+ final DefaultAccountAuditLogs auditLogsForAccount2ViaAccountRecordId = auditDao.getAuditLogsForAccountRecordId(AuditLevel.FULL, internalCallContext);
Assert.assertEquals(auditLogsForAccount2ViaAccountRecordId.getAuditLogsForAccount().size(), 1);
Assert.assertEquals(auditLogsForAccount2ViaAccountRecordId.getAuditLogsForAccount().get(0).getChangeType(), ChangeType.INSERT);
- final DefaultAccountAuditLogs auditLogsForAccount1ViaAccountRecordId2 = auditDao.getAuditLogsForAccountRecordId(AuditLevel.FULL, internalCallContext1);
+ internalCallContext.setAccountRecordId(account1RecordId);
+ final DefaultAccountAuditLogs auditLogsForAccount1ViaAccountRecordId2 = auditDao.getAuditLogsForAccountRecordId(AuditLevel.FULL, internalCallContext);
Assert.assertEquals(auditLogsForAccount1ViaAccountRecordId2.getAuditLogsForAccount().size(), 2);
Assert.assertEquals(auditLogsForAccount1ViaAccountRecordId2.getAuditLogsForAccount().get(0).getChangeType(), ChangeType.INSERT);
Assert.assertEquals(auditLogsForAccount1ViaAccountRecordId2.getAuditLogsForAccount().get(1).getChangeType(), ChangeType.UPDATE);
diff --git a/api/src/main/java/org/killbill/billing/account/api/AccountInternalApi.java b/api/src/main/java/org/killbill/billing/account/api/AccountInternalApi.java
index 4f7a92f..ad70272 100644
--- a/api/src/main/java/org/killbill/billing/account/api/AccountInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/account/api/AccountInternalApi.java
@@ -1,7 +1,9 @@
/*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -22,7 +24,7 @@ import java.util.UUID;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
-public interface AccountInternalApi {
+public interface AccountInternalApi extends ImmutableAccountInternalApi {
Account getAccountByKey(String key, InternalTenantContext context) throws AccountApiException;
@@ -41,9 +43,4 @@ public interface AccountInternalApi {
void updatePaymentMethod(UUID accountId, UUID paymentMethodId, InternalCallContext context) throws AccountApiException;
UUID getByRecordId(Long recordId, InternalTenantContext context) throws AccountApiException;
-
- ImmutableAccountData getImmutableAccountDataById(UUID accountId, InternalTenantContext context) throws AccountApiException;
-
- ImmutableAccountData getImmutableAccountDataByRecordId(Long recordId, InternalTenantContext context) throws AccountApiException;
-
}
diff --git a/api/src/main/java/org/killbill/billing/account/api/ImmutableAccountInternalApi.java b/api/src/main/java/org/killbill/billing/account/api/ImmutableAccountInternalApi.java
new file mode 100644
index 0000000..abf6c9e
--- /dev/null
+++ b/api/src/main/java/org/killbill/billing/account/api/ImmutableAccountInternalApi.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.account.api;
+
+import java.util.UUID;
+
+import org.killbill.billing.callcontext.InternalTenantContext;
+
+public interface ImmutableAccountInternalApi {
+
+ ImmutableAccountData getImmutableAccountDataById(UUID accountId, InternalTenantContext context) throws AccountApiException;
+
+ ImmutableAccountData getImmutableAccountDataByRecordId(Long recordId, InternalTenantContext context) throws AccountApiException;
+}
diff --git a/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java b/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java
index f1429a0..dee6931 100644
--- a/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java
+++ b/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java
@@ -1,7 +1,9 @@
/*
- * Copyright 2010-2012 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -21,7 +23,6 @@ import java.util.UUID;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
-
import org.joda.time.DateTimeZone;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.CallOrigin;
@@ -42,10 +43,18 @@ public class InternalCallContext extends InternalTenantContext {
private final DateTime createdDate;
private final DateTime updatedDate;
- public InternalCallContext(final Long tenantRecordId, @Nullable final Long accountRecordId, final UUID userToken, final String userName,
- final CallOrigin callOrigin, final UserType userType, final String reasonCode, final String comment,
- final DateTime createdDate, final DateTime updatedDate) {
- super(tenantRecordId, accountRecordId);
+ public InternalCallContext(final Long tenantRecordId,
+ @Nullable final Long accountRecordId,
+ @Nullable final DateTimeZone referenceDateTimeZone,
+ final UUID userToken,
+ final String userName,
+ final CallOrigin callOrigin,
+ final UserType userType,
+ final String reasonCode,
+ final String comment,
+ final DateTime createdDate,
+ final DateTime updatedDate) {
+ super(tenantRecordId, accountRecordId, referenceDateTimeZone);
this.userToken = userToken;
this.createdBy = userName;
this.updatedBy = userName;
@@ -53,24 +62,18 @@ public class InternalCallContext extends InternalTenantContext {
this.contextUserType = userType;
this.reasonCode = reasonCode;
this.comments = comment;
- this.createdDate = new DateTime(createdDate, DateTimeZone.UTC);
- this.updatedDate = updatedDate;
+ this.createdDate = toUTCDateTime(createdDate);
+ this.updatedDate = toUTCDateTime(updatedDate);
}
- public InternalCallContext(final Long tenantRecordId, @Nullable final Long accountRecordId, final CallContext callContext) {
- this(tenantRecordId, accountRecordId, callContext.getUserToken(), callContext.getUserName(), callContext.getCallOrigin(),
+ public InternalCallContext(final Long tenantRecordId, final CallContext callContext) {
+ this(tenantRecordId, null, null, callContext.getUserToken(), callContext.getUserName(), callContext.getCallOrigin(),
callContext.getUserType(), callContext.getReasonCode(), callContext.getComments(), callContext.getCreatedDate(),
callContext.getUpdatedDate());
}
- public InternalCallContext(final InternalCallContext context, final Long accountRecordId) {
- this(context.getTenantRecordId(), accountRecordId, context.getUserToken(), context.getCreatedBy(), context.getCallOrigin(),
- context.getContextUserType(), context.getReasonCode(), context.getComments(), context.getCreatedDate(),
- context.getUpdatedDate());
- }
-
- public InternalCallContext(final InternalCallContext context, final Long accountRecordId, final Long tenantRecordId) {
- this(tenantRecordId, accountRecordId, context.getUserToken(), context.getCreatedBy(), context.getCallOrigin(),
+ public InternalCallContext(final InternalCallContext context, final Long accountRecordId, final DateTimeZone referenceDateTimeZone) {
+ this(context.getTenantRecordId(), accountRecordId, referenceDateTimeZone, context.getUserToken(), context.getCreatedBy(), context.getCallOrigin(),
context.getContextUserType(), context.getReasonCode(), context.getComments(), context.getCreatedDate(),
context.getUpdatedDate());
}
diff --git a/api/src/main/java/org/killbill/billing/callcontext/InternalTenantContext.java b/api/src/main/java/org/killbill/billing/callcontext/InternalTenantContext.java
index f35241d..003fb19 100644
--- a/api/src/main/java/org/killbill/billing/callcontext/InternalTenantContext.java
+++ b/api/src/main/java/org/killbill/billing/callcontext/InternalTenantContext.java
@@ -1,7 +1,9 @@
/*
- * Copyright 2010-2012 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -20,23 +22,27 @@ import java.util.UUID;
import javax.annotation.Nullable;
+import org.joda.time.DateTimeZone;
import org.killbill.billing.util.callcontext.TenantContext;
/**
* Internal use only
*/
-public class InternalTenantContext {
+public class InternalTenantContext extends TimeAwareContext {
protected final Long tenantRecordId;
protected final Long accountRecordId;
- public InternalTenantContext(final Long tenantRecordId, @Nullable final Long accountRecordId) {
+ public InternalTenantContext(final Long tenantRecordId,
+ @Nullable final Long accountRecordId,
+ @Nullable final DateTimeZone referenceDateTimeZone) {
+ super(referenceDateTimeZone);
this.tenantRecordId = tenantRecordId;
this.accountRecordId = accountRecordId;
}
- public InternalTenantContext(final long defaultTenantRecordId) {
- this(defaultTenantRecordId, null);
+ public InternalTenantContext(final Long defaultTenantRecordId) {
+ this(defaultTenantRecordId, null, null);
}
public TenantContext toTenantContext(final UUID tenantId) {
@@ -55,8 +61,8 @@ public class InternalTenantContext {
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("InternalTenantContext");
- sb.append("{accountRecordId=").append(accountRecordId);
- sb.append(", tenantRecordId=").append(tenantRecordId);
+ sb.append("{accountRecordId=").append(getAccountRecordId());
+ sb.append(", tenantRecordId=").append(getTenantRecordId());
sb.append('}');
return sb.toString();
}
@@ -72,10 +78,10 @@ public class InternalTenantContext {
final InternalTenantContext that = (InternalTenantContext) o;
- if (accountRecordId != null ? !accountRecordId.equals(that.accountRecordId) : that.accountRecordId != null) {
+ if (getAccountRecordId() != null ? !getAccountRecordId().equals(that.getAccountRecordId()) : that.getAccountRecordId() != null) {
return false;
}
- if (tenantRecordId != null ? !tenantRecordId.equals(that.tenantRecordId) : that.tenantRecordId != null) {
+ if (getTenantRecordId() != null ? !getTenantRecordId().equals(that.getTenantRecordId()) : that.getTenantRecordId() != null) {
return false;
}
@@ -84,8 +90,8 @@ public class InternalTenantContext {
@Override
public int hashCode() {
- int result = accountRecordId != null ? accountRecordId.hashCode() : 0;
- result = 31 * result + (tenantRecordId != null ? tenantRecordId.hashCode() : 0);
+ int result = getAccountRecordId() != null ? getAccountRecordId().hashCode() : 0;
+ result = 31 * result + (getTenantRecordId() != null ? getTenantRecordId().hashCode() : 0);
return result;
}
}
diff --git a/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java b/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java
new file mode 100644
index 0000000..b265a4b
--- /dev/null
+++ b/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.callcontext;
+
+import java.util.Date;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDate;
+import org.joda.time.LocalTime;
+
+// TODO Cache the reference time and clock in the context
+public class TimeAwareContext {
+
+ private final DateTimeZone referenceDateTimeZone;
+
+ public TimeAwareContext(final DateTimeZone referenceDateTimeZone) {
+ this.referenceDateTimeZone = referenceDateTimeZone;
+ }
+
+ /// Generic functions
+ /// TODO Move to ClockUtil
+
+ // Create a DateTime object forcing the time zone to be UTC
+ protected DateTime toUTCDateTime(final DateTime dateTime) {
+ return toDateTime(dateTime, DateTimeZone.UTC);
+ }
+
+ // Create a DateTime object using the specified timezone (usually, the one on the account)
+ public DateTime toDateTime(final DateTime dateTime, final DateTimeZone accountTimeZone) {
+ return dateTime.toDateTime(accountTimeZone);
+ }
+
+ /// DateTime <-> LocalDate transformations
+
+ // Create a DateTime object using the specified reference time and timezone (usually, the one on the account)
+ public DateTime toUTCDateTime(final LocalDate localDate, final DateTime referenceDateTime) {
+ validateContext();
+
+ final DateTimeZone normalizedAccountTimezone = getNormalizedAccountTimezone(referenceDateTime);
+
+ final LocalTime referenceLocalTime = toDateTime(referenceDateTime, normalizedAccountTimezone).toLocalTime();
+
+ final DateTime targetDateTime = new DateTime(localDate.getYear(),
+ localDate.getMonthOfYear(),
+ localDate.getDayOfMonth(),
+ referenceLocalTime.getHourOfDay(),
+ referenceLocalTime.getMinuteOfHour(),
+ referenceLocalTime.getSecondOfMinute(),
+ normalizedAccountTimezone);
+
+ return toUTCDateTime(targetDateTime);
+ }
+
+ // Create a LocalDate object using the specified timezone (usually, the one on the account), respecting the offset at the time of the referenceDateTime
+ public LocalDate toLocalDate(final DateTime dateTime, final DateTime referenceDateTime) {
+ validateContext();
+
+ final DateTimeZone normalizedAccountTimezone = getNormalizedAccountTimezone(referenceDateTime);
+ return new LocalDate(dateTime, normalizedAccountTimezone);
+ }
+
+ private DateTimeZone getNormalizedAccountTimezone(final DateTime referenceDateTime) {
+ // Check if DST was in effect at the reference date time
+ final boolean shouldUseDST = !getReferenceDateTimeZone().isStandardOffset(referenceDateTime.getMillis());
+ if (shouldUseDST) {
+ return DateTimeZone.forOffsetMillis(getReferenceDateTimeZone().getOffset(referenceDateTime.getMillis()));
+ } else {
+ return DateTimeZone.forOffsetMillis(getReferenceDateTimeZone().getStandardOffset(referenceDateTime.getMillis()));
+ }
+ }
+
+ private void validateContext() {
+ if (getReferenceDateTimeZone() == null) {
+ throw new IllegalArgumentException(String.format("Context mis-configured: getReferenceDateTimeZone()=%s", getReferenceDateTimeZone()));
+ }
+ }
+
+ // For convenience, to be overridden in tests
+ protected DateTimeZone getReferenceDateTimeZone() {
+ return referenceDateTimeZone;
+ }
+}
diff --git a/api/src/main/java/org/killbill/billing/util/AccountDateAndTimeZoneContext.java b/api/src/main/java/org/killbill/billing/util/AccountDateAndTimeZoneContext.java
index d997be1..cd79eaa 100644
--- a/api/src/main/java/org/killbill/billing/util/AccountDateAndTimeZoneContext.java
+++ b/api/src/main/java/org/killbill/billing/util/AccountDateAndTimeZoneContext.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -18,7 +18,6 @@
package org.killbill.billing.util;
import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
public interface AccountDateAndTimeZoneContext {
@@ -26,7 +25,5 @@ public interface AccountDateAndTimeZoneContext {
public LocalDate computeLocalDateFromFixedAccountOffset(final DateTime targetDateTime);
public DateTime computeUTCDateTimeFromLocalDate(final LocalDate invoiceItemEndDate);
-
- public DateTimeZone getAccountTimeZone();
}
beatrix/pom.xml 6(+6 -0)
diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index b738845..3b3064f 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -267,6 +267,12 @@
</dependency>
<dependency>
<groupId>org.kill-bill.commons</groupId>
+ <artifactId>killbill-queue</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.kill-bill.commons</groupId>
<artifactId>killbill-xmlloader</artifactId>
</dependency>
<dependency>
diff --git a/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java b/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java
index 16b5b66..31389da 100644
--- a/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java
+++ b/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java
@@ -101,7 +101,13 @@ public class BeatrixListener {
externalBus.post(externalEvent);
}
} catch (final EventBusException e) {
+ //
+ // When using PersistentBus this should never be reached, because errors are caught at the 'ext' bus level and retried until either success or event row is moved to FAILED status.
+ // However when using InMemoryBus, this can happen as there is no retry logic (at the 'ext' bus level) and so we should re-throw at this level to kick-in the retry logic from the 'main' bus
+ // (The use of RuntimeException is somewhat arbitrary)
+ //
log.warn("Failed to dispatch external bus events", e);
+ throw new RuntimeException(e);
} catch (JsonProcessingException e) {
log.warn("Failed to dispatch external bus events", e);
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/extbus/TestEventJson.java b/beatrix/src/test/java/org/killbill/billing/beatrix/extbus/TestEventJson.java
index 8238496..77ab028 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/extbus/TestEventJson.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/extbus/TestEventJson.java
@@ -24,10 +24,10 @@ import org.testng.Assert;
import org.testng.annotations.Test;
import org.killbill.billing.ObjectType;
-import org.killbill.billing.beatrix.BeatrixTestSuite;
+import org.killbill.billing.beatrix.BeatrixTestSuiteNoDB;
import org.killbill.billing.util.jackson.ObjectMapper;
-public class TestEventJson extends BeatrixTestSuite {
+public class TestEventJson extends BeatrixTestSuiteNoDB {
private final ObjectMapper mapper = new ObjectMapper();
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModuleNoDB.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModuleNoDB.java
new file mode 100644
index 0000000..4c47137
--- /dev/null
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/BeatrixIntegrationModuleNoDB.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.beatrix.integration;
+
+import org.killbill.billing.GuicyKillbillTestNoDBModule;
+import org.killbill.billing.mock.glue.MockAccountModule;
+import org.killbill.billing.mock.glue.MockNonEntityDaoModule;
+import org.killbill.billing.platform.api.KillbillConfigSource;
+import org.killbill.billing.util.glue.KillBillModule;
+
+public class BeatrixIntegrationModuleNoDB extends KillBillModule {
+
+ public BeatrixIntegrationModuleNoDB(final KillbillConfigSource configSource) {
+ super(configSource);
+ }
+
+ @Override
+ protected void configure() {
+ install(new GuicyKillbillTestNoDBModule(configSource));
+ install(new MockNonEntityDaoModule(configSource));
+ install(new MockAccountModule(configSource));
+ }
+}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index b97040b..2fe3884 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -943,9 +943,9 @@ public class TestOverdueIntegration extends TestOverdueBase {
createPaymentAndCheckForCompletion(account, invoice, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
} else {
if (extraPayment) {
- createPaymentAndCheckForCompletion(account, invoice, NextEvent.BLOCK, NextEvent.TAG, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ createPaymentAndCheckForCompletion(account, invoice, NextEvent.BLOCK, NextEvent.TAG, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
} else {
- createPaymentAndCheckForCompletion(account, invoice, NextEvent.BLOCK, NextEvent.TAG, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ createPaymentAndCheckForCompletion(account, invoice, NextEvent.BLOCK, NextEvent.TAG, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
}
}
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueWithSubscriptionCancellation.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueWithSubscriptionCancellation.java
index 9575752..7011c8a 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueWithSubscriptionCancellation.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueWithSubscriptionCancellation.java
@@ -30,7 +30,6 @@ import org.killbill.billing.entitlement.api.DefaultEntitlement;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
import org.killbill.billing.entitlement.api.SubscriptionBundle;
import org.killbill.billing.invoice.api.InvoiceItemType;
-import org.killbill.billing.junction.DefaultBlockingState;
import org.killbill.billing.overdue.wrapper.OverdueWrapper;
import org.killbill.billing.subscription.api.SubscriptionBase;
import org.testng.annotations.Test;
@@ -84,10 +83,10 @@ public class TestOverdueWithSubscriptionCancellation extends TestOverdueBase {
// Cancel addOn1 one day after
clock.addDays(1);
- cancelEntitlementAndCheckForCompletion(addOn1, clock.getUTCNow(), NextEvent.BLOCK, NextEvent.CANCEL);
+ 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.INVOICE, NextEvent.PAYMENT_ERROR, NextEvent.INVOICE_PAYMENT_ERROR);
+ 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);
@@ -135,12 +134,12 @@ public class TestOverdueWithSubscriptionCancellation extends TestOverdueBase {
// Cancel bundle 2 one day after (2012-05-02)
clock.addDays(1);
- cancelEntitlementAndCheckForCompletion(baseEntitlement2, clock.getUTCNow(), NextEvent.BLOCK, NextEvent.CANCEL);
+ cancelEntitlementAndCheckForCompletion(baseEntitlement2, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.NULL_INVOICE);
final SubscriptionBase cancelledBaseSubscription2 = ((DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement2.getId(), callContext)).getSubscriptionBase();
assertTrue(cancelledBaseSubscription2.getState() == EntitlementState.CANCELLED);
// DAY 30 have to get out of trial before first payment (2012-05-31)
- addDaysAndCheckForCompletion(29, NextEvent.PHASE, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR, NextEvent.INVOICE_PAYMENT_ERROR);
+ addDaysAndCheckForCompletion(29, NextEvent.PHASE, NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR, NextEvent.INVOICE_PAYMENT_ERROR);
invoiceChecker.checkInvoice(account.getId(),
4,
callContext,
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestBundleTransfer.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestBundleTransfer.java
index 7915e6e..e32ab28 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestBundleTransfer.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestBundleTransfer.java
@@ -55,7 +55,6 @@ public class TestBundleTransfer extends TestIntegrationBase {
@Test(groups = "slow")
public void testBundleTransferWithBPAnnualOnly() throws Exception {
-
final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(3));
// Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
@@ -88,23 +87,21 @@ public class TestBundleTransfer extends TestIntegrationBase {
transferApi.transferBundle(account.getId(), newAccount.getId(), "externalKey", clock.getUTCNow(), false, false, callContext);
assertListenerStatus();
- List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(newAccount.getId(), callContext);
+ final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(newAccount.getId(), callContext);
assertEquals(invoices.size(), 1);
final List<InvoiceItem> invoiceItems = invoices.get(0).getInvoiceItems();
assertEquals(invoiceItems.size(), 1);
- InvoiceItem theItem = invoiceItems.get(0);
+ final InvoiceItem theItem = invoiceItems.get(0);
assertTrue(theItem.getStartDate().compareTo(new LocalDate(2012, 5, 11)) == 0);
assertTrue(theItem.getEndDate().compareTo(new LocalDate(2013, 5, 11)) == 0);
assertTrue(theItem.getAmount().compareTo(new BigDecimal("2399.9500")) == 0);
checkNoMoreInvoiceToGenerate(account);
-
}
@Test(groups = "slow")
public void testBundleTransferWithBPMonthlyOnly() throws Exception {
-
final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(0));
// Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
@@ -249,7 +246,7 @@ public class TestBundleTransfer extends TestIntegrationBase {
paymentChecker.checkPayment(account.getId(), 1, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 4, 1), new BigDecimal("399.95"), TransactionStatus.SUCCESS, secondInvoice.getId(), Currency.USD));
// Move past the phase for simplicity
- busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addDays(30);
assertListenerStatus();
final Invoice thirdInvoice = invoiceChecker.checkInvoice(account.getId(), 3, callContext,
@@ -270,7 +267,7 @@ public class TestBundleTransfer extends TestIntegrationBase {
final DateTime now = clock.getUTCNow();
final LocalDate transferDay = now.toLocalDate();
- busHandler.pushExpectedEvents(NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.TRANSFER, NextEvent.TRANSFER, NextEvent.INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.TRANSFER, NextEvent.TRANSFER, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
final UUID newBundleId = entitlementApi.transferEntitlements(account.getId(), newAccount.getId(), bundleExternalKey, transferDay, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
@@ -313,6 +310,5 @@ public class TestBundleTransfer extends TestIntegrationBase {
}
checkNoMoreInvoiceToGenerate(account);
-
}
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
index 3a8a532..5c0e974 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
@@ -50,7 +50,6 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
@Test(groups = "slow")
public void testRetirePlan() throws Exception {
-
// Catalog v1 starts in 2011-01-01
// Catalog v2 starts in 2015-12-01
final LocalDate today = new LocalDate(2015, 11, 5);
@@ -85,7 +84,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
try {
entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, effectiveDate, ImmutableList.<PluginProperty>of(), callContext);
fail(); // force to fail is there is not an exception
- } catch (EntitlementApiException e) {
+ } catch (final EntitlementApiException e) {
assertTrue(e.getLocalizedMessage().startsWith("Could not find a plan matching: (product: 'Pistol', billing period: 'MONTHLY'"));
}
@@ -96,15 +95,13 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
assertEquals(invoices.size(), 3);
- for (Invoice invoice : invoices) {
+ for (final Invoice invoice : invoices) {
assertEquals(invoice.getInvoiceItems().get(0).getPlanName(), "pistol-monthly");
}
-
}
@Test(groups = "slow")
public void testRetireProduct() throws Exception {
-
// Catalog v1 starts in 2011-01-01
// Catalog v3 starts in 2016-01-01
final LocalDate today = new LocalDate(2015, 11, 5);
@@ -144,7 +141,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
try {
entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, effectiveDate, ImmutableList.<PluginProperty>of(), callContext);
fail(); // force to fail is there is not an exception
- } catch (EntitlementApiException e) {
+ } catch (final EntitlementApiException e) {
assertTrue(e.getLocalizedMessage().startsWith("Could not find any product named 'Pistol'"));
}
@@ -155,15 +152,13 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
assertEquals(invoices.size(), 4);
- for (Invoice invoice : invoices) {
+ for (final Invoice invoice : invoices) {
assertEquals(invoice.getInvoiceItems().get(0).getPlanName(), "pistol-monthly");
}
-
}
@Test(groups = "slow")
public void testRetirePriceList() throws Exception {
-
// Catalog v1 starts in 2011-01-01
// Catalog v2 starts in 2015-12-01
// Catalog v3 starts in 2016-01-01
@@ -203,7 +198,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
try {
entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, effectiveDate, ImmutableList.<PluginProperty>of(), callContext);
fail(); // force to fail is there is not an exception
- } catch (EntitlementApiException e) {
+ } catch (final EntitlementApiException e) {
assertTrue(e.getLocalizedMessage().startsWith("Could not find any product named 'Pistol'"));
}
@@ -213,7 +208,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
assertListenerStatus();
// Move out a month.
- busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addMonths(1);
assertListenerStatus();
@@ -225,7 +220,5 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
assertTrue(invoices.get(2).getInvoiceItems().get(0).getPhaseName().equals("discount-pistol-monthly-discount"));
assertTrue(invoices.get(3).getInvoiceItems().get(0).getPhaseName().equals("discount-pistol-monthly-discount"));
assertTrue(invoices.get(4).getInvoiceItems().get(0).getPhaseName().equals("discount-pistol-monthly-evergreen"));
-
}
-
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
index b1ff283..366de44 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
@@ -24,15 +24,14 @@ import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
import org.joda.time.Interval;
import org.joda.time.LocalDate;
+import org.killbill.billing.ErrorCode;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountData;
import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
import org.killbill.billing.beatrix.util.PaymentChecker.ExpectedPaymentCheck;
-import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.PriceListSet;
@@ -47,7 +46,6 @@ import org.killbill.billing.invoice.api.DryRunType;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.invoice.api.InvoiceItemType;
-import org.killbill.billing.mock.MockAccountBuilder;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
@@ -65,7 +63,6 @@ public class TestIntegration extends TestIntegrationBase {
@Test(groups = "slow")
public void testCancelBPWithAOTheSameDay() throws Exception {
-
final AccountData accountData = getAccountData(1);
final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
accountChecker.checkAccount(account.getId(), accountData, callContext);
@@ -103,7 +100,7 @@ public class TestIntegration extends TestIntegrationBase {
addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
- Invoice invoice = invoiceChecker.checkInvoice(account.getId(), 2, callContext, expectedInvoices);
+ final Invoice invoice = invoiceChecker.checkInvoice(account.getId(), 2, callContext, expectedInvoices);
paymentChecker.checkPayment(account.getId(), 1, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 4, 1), new BigDecimal("399.95"), TransactionStatus.SUCCESS, invoice.getId(), Currency.USD));
expectedInvoices.clear();
@@ -121,23 +118,20 @@ public class TestIntegration extends TestIntegrationBase {
invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
- cancelEntitlementAndCheckForCompletion(bpSubscription, clock.getUTCNow(), NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.INVOICE);
+ cancelEntitlementAndCheckForCompletion(bpSubscription, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.INVOICE);
invoiceChecker.checkInvoice(account.getId(), 3,
callContext,
expectedInvoices);
checkNoMoreInvoiceToGenerate(account);
-
}
@Test(groups = "slow")
public void testBasePlanCompleteWithBillingDayInPast() throws Exception {
-
final int billingDay = 31;
final DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
- log.info("Beginning test with BCD of " + billingDay);
final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
// set clock to the initial start date
@@ -213,7 +207,7 @@ public class TestIntegration extends TestIntegrationBase {
invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
- addDaysAndCheckForCompletion(31, NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ addDaysAndCheckForCompletion(31, NextEvent.CHANGE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, callContext, expectedInvoices);
invoiceChecker.checkChargedThroughDate(subscription.getId(), secondRecurringPistolDate, callContext);
expectedInvoices.clear();
@@ -236,24 +230,20 @@ public class TestIntegration extends TestIntegrationBase {
//
// FINALLY CANCEL SUBSCRIPTION EOT
//
- baseEntitlement = cancelEntitlementAndCheckForCompletion(baseEntitlement, clock.getUTCNow(), NextEvent.BLOCK);
+ baseEntitlement = cancelEntitlementAndCheckForCompletion(baseEntitlement, NextEvent.BLOCK);
// MOVE AFTER CANCEL DATE AND EXPECT EVENT : NextEvent.CANCEL
- addDaysAndCheckForCompletion(31, NextEvent.CANCEL);
+ addDaysAndCheckForCompletion(31, NextEvent.CANCEL, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE);
invoiceChecker.checkChargedThroughDate(subscription.getId(), new LocalDate(2012, 7, 31), callContext);
checkNoMoreInvoiceToGenerate(account);
-
- log.info("TEST PASSED !");
}
@Test(groups = "slow")
public void testBasePlanCompleteWithBillingDayAlignedWithTrial() throws Exception {
-
final int billingDay = 2;
final DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
- log.info("Beginning test with BCD of " + billingDay);
final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
// set clock to the initial start date
@@ -292,17 +282,15 @@ public class TestIntegration extends TestIntegrationBase {
//
- TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null, SubscriptionEventType.CHANGE,
- subscription.getId(), subscription.getBundleId(), null, null);
+ final TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null, SubscriptionEventType.CHANGE,
+ subscription.getId(), subscription.getBundleId(), null, null);
try {
invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
Assert.fail("Call should return no invoices");
- } catch (InvoiceApiException e) {
- System.out.print("foo");
-
+ } catch (final InvoiceApiException e) {
+ assertEquals(e.getCode(), ErrorCode.INVOICE_NOTHING_TO_DO.getCode());
}
-
baseEntitlement = changeEntitlementAndCheckForCompletion(baseEntitlement, "Pistol", BillingPeriod.MONTHLY, null);
subscription = subscriptionDataFromSubscription(baseEntitlement.getSubscriptionBase());
@@ -311,7 +299,7 @@ public class TestIntegration extends TestIntegrationBase {
//
final LocalDate firstRecurringPistolDate = subscription.getChargedThroughDate().toLocalDate();
final LocalDate secondRecurringPistolDate = firstRecurringPistolDate.plusMonths(1);
- addDaysAndCheckForCompletion(31, NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ addDaysAndCheckForCompletion(31, NextEvent.CHANGE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 2), new LocalDate(2012, 5, 2), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
invoiceChecker.checkChargedThroughDate(subscription.getId(), secondRecurringPistolDate, callContext);
@@ -333,23 +321,20 @@ public class TestIntegration extends TestIntegrationBase {
//
// FINALLY CANCEL SUBSCRIPTION EOT
//
- cancelEntitlementAndCheckForCompletion(baseEntitlement, clock.getUTCNow(), NextEvent.BLOCK);
+ cancelEntitlementAndCheckForCompletion(baseEntitlement, NextEvent.BLOCK);
- // MOVE AFTER CANCEL DATE AND EXPECT EVENT : NextEvent.CANCEL
- addDaysAndCheckForCompletion(31, NextEvent.CANCEL);
+ // MOVE AFTER CANCEL DATE
+ addDaysAndCheckForCompletion(31, NextEvent.CANCEL, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE);
invoiceChecker.checkChargedThroughDate(subscription.getId(), new LocalDate(2012, 8, 2), callContext);
checkNoMoreInvoiceToGenerate(account);
-
}
@Test(groups = "slow")
public void testBasePlanCompleteWithBillingDayInFuture() throws Exception {
-
final int billingDay = 3;
final DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
- log.info("Beginning test with BCD of " + billingDay);
final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
// set clock to the initial start date
@@ -401,7 +386,7 @@ public class TestIntegration extends TestIntegrationBase {
//
final LocalDate firstRecurringPistolDate = subscription.getChargedThroughDate().toLocalDate();
final LocalDate secondRecurringPistolDate = firstRecurringPistolDate.plusMonths(1);
- addDaysAndCheckForCompletion(31, NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ addDaysAndCheckForCompletion(31, NextEvent.CHANGE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 3), new LocalDate(2012, 5, 3), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
invoiceChecker.checkChargedThroughDate(subscription.getId(), secondRecurringPistolDate, callContext);
@@ -423,16 +408,13 @@ public class TestIntegration extends TestIntegrationBase {
//
// FINALLY CANCEL SUBSCRIPTION EOT
//
- baseEntitlement = cancelEntitlementAndCheckForCompletion(baseEntitlement, clock.getUTCNow(), NextEvent.BLOCK);
+ baseEntitlement = cancelEntitlementAndCheckForCompletion(baseEntitlement, NextEvent.BLOCK);
// MOVE AFTER CANCEL DATE AND EXPECT EVENT : NextEvent.CANCEL
- addDaysAndCheckForCompletion(31, NextEvent.CANCEL);
+ addDaysAndCheckForCompletion(31, NextEvent.CANCEL, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE);
invoiceChecker.checkChargedThroughDate(subscription.getId(), new LocalDate(2012, 8, 3), callContext);
checkNoMoreInvoiceToGenerate(account);
-
- log.info("TEST PASSED !");
-
}
@Test(groups = {"stress"}, enabled = false)
@@ -494,7 +476,6 @@ public class TestIntegration extends TestIntegrationBase {
// MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
final Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
- log.info("Moving clock from" + clock.getUTCNow() + " to " + clock.getUTCNow().plusDays(3));
clock.addDays(3);
final DefaultEntitlement aoEntitlement1 = addAOEntitlementAndCheckForCompletion(baseEntitlement.getBundleId(), "Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY,
@@ -504,36 +485,29 @@ public class TestIntegration extends TestIntegrationBase {
NextEvent.CREATE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
// MOVE CLOCK A LITTLE BIT MORE -- EITHER STAY IN TRIAL OR GET OUT
- busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
- log.info("Moving clock from" + clock.getUTCNow() + " to " + clock.getUTCNow().plusDays(28));
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addDays(28);// 26 / 5
assertListenerStatus();
- busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
- log.info("Moving clock from" + clock.getUTCNow() + " to " + clock.getUTCNow().plusDays(3));
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addDays(3);// 29 / 5
assertListenerStatus();
- log.info("Moving clock from" + clock.getUTCNow() + " to " + clock.getUTCNow().plusDays(10));
clock.addDays(10);// 8 / 6
assertListenerStatus();
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
- log.info("Moving clock from" + clock.getUTCNow() + " to " + clock.getUTCNow().plusDays(18));
clock.addDays(18);// 26 / 6
assertListenerStatus();
- log.info("Moving clock from" + clock.getUTCNow() + " to " + clock.getUTCNow().plusDays(3));
clock.addDays(3);
assertListenerStatus();
checkNoMoreInvoiceToGenerate(account);
-
}
@Test(groups = "slow")
public void testCreateMultipleBPWithSameExternalKey() throws Exception {
-
final DateTime initialDate = new DateTime(2012, 4, 25, 0, 13, 42, 0, testTimeZone);
clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
@@ -546,7 +520,7 @@ public class TestIntegration extends TestIntegrationBase {
final DefaultEntitlement baseEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
final SubscriptionBundle initialBundle = subscriptionApi.getActiveSubscriptionBundleForExternalKey("bundleKey", callContext);
- busHandler.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CANCEL);
+ busHandler.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.NULL_INVOICE);
baseEntitlement.cancelEntitlementWithPolicy(EntitlementActionPolicy.IMMEDIATE, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
@@ -565,7 +539,6 @@ public class TestIntegration extends TestIntegrationBase {
assertEquals(newBaseEntitlement.getState(), EntitlementState.ACTIVE);
checkNoMoreInvoiceToGenerate(account);
-
}
@Test(groups = "slow")
@@ -573,7 +546,6 @@ public class TestIntegration extends TestIntegrationBase {
final DateTime initialDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
final int billingDay = 2;
- log.info("Beginning test with BCD of " + billingDay);
final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
final UUID accountId = account.getId();
assertNotNull(account);
@@ -581,9 +553,9 @@ public class TestIntegration extends TestIntegrationBase {
// set clock to the initial start date
clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
- String productName = "Shotgun";
- BillingPeriod term = BillingPeriod.MONTHLY;
- String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+ final String productName = "Shotgun";
+ final BillingPeriod term = BillingPeriod.MONTHLY;
+ final String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
//
// CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE NextEvent.INVOICE
@@ -594,7 +566,7 @@ public class TestIntegration extends TestIntegrationBase {
//
// VERIFY CTD HAS BEEN SET
//
- DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) baseEntitlement.getSubscriptionBase();
+ final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) baseEntitlement.getSubscriptionBase();
final DateTime startDate = subscription.getCurrentPhaseStart();
final BigDecimal rate = subscription.getCurrentPhase().getFixed().getPrice().getPrice(Currency.USD);
verifyTestResult(accountId, subscription.getId(), startDate, null, rate, clock.getUTCNow(), 1);
@@ -610,8 +582,7 @@ public class TestIntegration extends TestIntegrationBase {
// PAUSE THE ENTITLEMENT
DefaultEntitlement entitlement = (DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext);
- busHandler.pushExpectedEvents(NextEvent.PAUSE, NextEvent.BLOCK);
- busHandler.pushExpectedEvent(NextEvent.INVOICE);
+ busHandler.pushExpectedEvents(NextEvent.PAUSE, NextEvent.BLOCK, NextEvent.NULL_INVOICE, NextEvent.INVOICE);
entitlementApi.pause(entitlement.getBundleId(), clock.getUTCNow().toLocalDate(), ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
@@ -628,8 +599,7 @@ public class TestIntegration extends TestIntegrationBase {
// MOVE CLOCK FORWARD ADN CHECK THERE IS NO NEW INVOICE
clock.addDeltaFromReality(AT_LEAST_ONE_MONTH_MS);
- busHandler.pushExpectedEvents(NextEvent.RESUME, NextEvent.BLOCK);
- busHandler.pushExpectedEvent(NextEvent.INVOICE);
+ busHandler.pushExpectedEvents(NextEvent.RESUME, NextEvent.BLOCK, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE, NextEvent.INVOICE);
entitlementApi.resume(entitlement.getBundleId(), clock.getUTCNow().toLocalDate(), ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
@@ -638,14 +608,10 @@ public class TestIntegration extends TestIntegrationBase {
new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 5), new LocalDate(2012, 4, 5), InvoiceItemType.CBA_ADJ, new BigDecimal("-224.96")));
checkNoMoreInvoiceToGenerate(account);
-
}
@Test(groups = "slow")
public void testForMultipleRecurringPhases() throws Exception {
-
- log.info("Starting testForMultipleRecurringPhases");
-
final DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
clock.setDeltaFromReality(initialCreationDate.getMillis() - clock.getUTCNow().getMillis());
@@ -675,7 +641,7 @@ public class TestIntegration extends TestIntegrationBase {
assertListenerStatus();
}
- busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addDeltaFromReality(AT_LEAST_ONE_MONTH_MS);
assertListenerStatus();
@@ -698,4 +664,73 @@ public class TestIntegration extends TestIntegrationBase {
checkNoMoreInvoiceToGenerate(account);
}
+
+ @Test(groups = "slow")
+ public void testFixedTermPlan() throws Exception {
+ // We take april as it has 30 days (easier to play with BCD)
+ // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
+ clock.setDay(new LocalDate(2015, 4, 1));
+
+ final AccountData accountData = getAccountData(1);
+ final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+ accountChecker.checkAccount(account.getId(), accountData, callContext);
+
+
+ // First invoice
+ final DefaultEntitlement bpSubscription = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, /* NextEvent.BLOCK, */ NextEvent.INVOICE);
+
+
+ // Second invoice -> first recurring for Refurbish-Maintenance
+ addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Refurbish-Maintenance", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, NextEvent.CREATE, /* NextEvent.BLOCK, */ NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+
+ final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
+
+ expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 4, 1), null, InvoiceItemType.FIXED, new BigDecimal("599.95")));
+ expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 4, 1), new LocalDate(2015, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("199.95")));
+ invoiceChecker.checkInvoice(account.getId(), 2, callContext, expectedInvoices);
+ expectedInvoices.clear();
+
+
+ expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 5, 1), new LocalDate(2015, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("199.95")));
+ expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 5, 1), new LocalDate(2015, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
+
+ // 2015-5-1
+ // Third invoice -> second recurring for Refurbish-Maintenance
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ clock.addDays(30); // Also = 1 month because or initial date 2015, 4, 1
+ assertListenerStatus();
+
+ invoiceChecker.checkInvoice(account.getId(), 3, callContext, expectedInvoices);
+ expectedInvoices.clear();
+
+
+ // Next 10 invoices -> third to twelve **and last** recurring for Refurbish-Maintenance
+ LocalDate startDate = new LocalDate(2015, 6, 1);
+ for (int i = 0; i < 10; i++) {
+
+ final LocalDate endDate = startDate.plusMonths(1);
+ expectedInvoices.add(new ExpectedInvoiceItemCheck(startDate, endDate, InvoiceItemType.RECURRING, new BigDecimal("199.95")));
+ expectedInvoices.add(new ExpectedInvoiceItemCheck(startDate, endDate, InvoiceItemType.RECURRING, new BigDecimal("29.95")));
+
+ busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ clock.addMonths(1);
+ assertListenerStatus();
+
+ invoiceChecker.checkInvoice(account.getId(), 4 + i, callContext, expectedInvoices);
+ expectedInvoices.clear();
+
+ startDate = endDate;
+ }
+
+ // We check there is no more recurring for Refurbish-Maintenance
+ expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2016, 4, 1), new LocalDate(2016, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
+
+ busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ clock.addMonths(1);
+ assertListenerStatus();
+
+
+ invoiceChecker.checkInvoice(account.getId(), 14, callContext, expectedInvoices);
+ expectedInvoices.clear();
+ }
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index fef7033..14f32de 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -99,8 +99,11 @@ import org.killbill.billing.util.api.RecordIdApi;
import org.killbill.billing.util.api.TagApiException;
import org.killbill.billing.util.api.TagDefinitionApiException;
import org.killbill.billing.util.api.TagUserApi;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.TestCallContext;
+import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.nodes.KillbillNodesApi;
import org.killbill.billing.util.tag.ControlTagType;
import org.killbill.billing.util.tag.Tag;
@@ -247,6 +250,8 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
@Inject
protected IDBI idbi;
+ @Inject
+ protected NonEntityDao nonEntityDao;
@Inject
protected TestApiListener busHandler;
@@ -260,6 +265,9 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
@Inject
protected KillbillNodesApi nodesApi;
+ @Inject
+ protected CacheControllerDispatcher controllerDispatcher;
+
protected void assertListenerStatus() {
busHandler.assertListenerStatus();
}
@@ -278,6 +286,9 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
//Thread.currentThread().setContextClassLoader(null);
log.debug("RESET TEST FRAMEWORK");
+
+ controllerDispatcher.clearAll();
+
overdueConfigCache.loadDefaultOverdueConfig((OverdueConfig) null);
clock.resetDeltaFromReality();
@@ -309,10 +320,12 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
}
protected void checkNoMoreInvoiceToGenerate(final Account account) {
+ busHandler.pushExpectedEvent(NextEvent.NULL_INVOICE);
try {
invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), null, callContext);
fail("Should not have generated an extra invoice");
} catch (final InvoiceApiException e) {
+ assertListenerStatus();
assertEquals(e.getCode(), ErrorCode.INVOICE_NOTHING_TO_DO.getCode());
}
}
@@ -349,6 +362,10 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
final Account account = accountUserApi.createAccount(accountData, callContext);
assertNotNull(account);
+ final Long accountRecordId = nonEntityDao.retrieveRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, controlCacheDispatcher.getCacheController(CacheType.RECORD_ID));
+ internalCallContext.setAccountRecordId(accountRecordId);
+ internalCallContext.setReferenceDateTimeZone(account.getTimeZone());
+
final PaymentMethodPlugin info = createPaymentMethodPlugin();
paymentApi.addPaymentMethod(account, UUID.randomUUID().toString(), paymentPluginName, true, info, PLUGIN_PROPERTIES, callContext);
@@ -565,8 +582,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
public Entitlement apply(@Nullable final Void dontcare) {
try {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, productCategory, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final LocalDate effectiveDate = new LocalDate(clock.getUTCNow());
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(accountId, spec, bundleExternalKey, overrides, effectiveDate, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(accountId, spec, bundleExternalKey, overrides, null, ImmutableList.<PluginProperty>of(), callContext);
assertNotNull(entitlement);
return entitlement;
} catch (final EntitlementApiException e) {
@@ -600,8 +616,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
public Entitlement apply(@Nullable final Void dontcare) {
try {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, productCategory, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final LocalDate effectiveDate = new LocalDate(clock.getUTCNow());
- final Entitlement entitlement = entitlementApi.addEntitlement(bundleId, spec, null, effectiveDate, ImmutableList.<PluginProperty>of(), callContext);
+ final Entitlement entitlement = entitlementApi.addEntitlement(bundleId, spec, null, null, ImmutableList.<PluginProperty>of(), callContext);
assertNotNull(entitlement);
return entitlement;
} catch (final EntitlementApiException e) {
@@ -627,7 +642,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
if (billingPolicy == null) {
refreshedEntitlement = refreshedEntitlement.changePlan(productName, billingPeriod, priceList, null, ImmutableList.<PluginProperty>of(), callContext);
} else {
- refreshedEntitlement = refreshedEntitlement.changePlanOverrideBillingPolicy(productName, billingPeriod, priceList, null, clock.getUTCNow().toLocalDate(), billingPolicy, ImmutableList.<PluginProperty>of(), callContext);
+ refreshedEntitlement = refreshedEntitlement.changePlanOverrideBillingPolicy(productName, billingPeriod, priceList, null, null, billingPolicy, ImmutableList.<PluginProperty>of(), callContext);
}
return refreshedEntitlement;
} catch (final EntitlementApiException e) {
@@ -647,7 +662,12 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
}
protected DefaultEntitlement cancelEntitlementAndCheckForCompletion(final Entitlement entitlement,
- final DateTime requestedDate,
+ final NextEvent... events) {
+ return cancelEntitlementAndCheckForCompletion(entitlement, null, events);
+ }
+
+ protected DefaultEntitlement cancelEntitlementAndCheckForCompletion(final Entitlement entitlement,
+ final LocalDate requestedDate,
final NextEvent... events) {
return (DefaultEntitlement) doCallAndCheckForCompletion(new Function<Void, Entitlement>() {
@Override
@@ -655,7 +675,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
try {
// Need to fetch again to get latest CTD updated from the system
Entitlement refreshedEntitlement = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
- refreshedEntitlement = refreshedEntitlement.cancelEntitlementWithDate(requestedDate.toLocalDate(), false, ImmutableList.<PluginProperty>of(), callContext);
+ refreshedEntitlement = refreshedEntitlement.cancelEntitlementWithDate(requestedDate, false, ImmutableList.<PluginProperty>of(), callContext);
return refreshedEntitlement;
} catch (final EntitlementApiException e) {
fail(e.getMessage());
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
index 403343f..7c34a8e 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
@@ -137,7 +137,7 @@ public class TestIntegrationWithAutoInvoiceOffTag extends TestIntegrationBase {
add_AUTO_INVOICING_OFF_Tag(bpEntitlement.getSubscriptionBase().getBundleId(), ObjectType.BUNDLE);
- busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addDays(40); // DAY 40 out of trial
assertListenerStatus();
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithDifferentBillingPeriods.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithDifferentBillingPeriods.java
index 55c5715..270f9a1 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithDifferentBillingPeriods.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithDifferentBillingPeriods.java
@@ -153,7 +153,7 @@ public class TestIntegrationWithDifferentBillingPeriods extends TestIntegrationB
invoiceChecker.checkInvoice(invoices.get(2).getId(), callContext, toBeChecked);
// Move to 1020-08-01
- busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addDays(20);
clock.addMonths(2);
assertListenerStatus();
@@ -199,7 +199,7 @@ public class TestIntegrationWithDifferentBillingPeriods extends TestIntegrationB
// 2012-5-12
clock.addDays(10);
- busHandler.pushExpectedEvents(NextEvent.PAUSE, NextEvent.BLOCK, NextEvent.INVOICE);
+ busHandler.pushExpectedEvents(NextEvent.PAUSE, NextEvent.BLOCK, NextEvent.NULL_INVOICE, NextEvent.INVOICE);
entitlementApi.pause(bpEntitlement.getBundleId(), clock.getUTCNow().toLocalDate(), ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
@@ -218,7 +218,7 @@ public class TestIntegrationWithDifferentBillingPeriods extends TestIntegrationB
// 2012-6-4
clock.addDays(23);
- busHandler.pushExpectedEvents(NextEvent.RESUME, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.RESUME, NextEvent.BLOCK, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
entitlementApi.resume(bpEntitlement.getBundleId(), clock.getUTCNow().toLocalDate(), ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
@@ -230,7 +230,7 @@ public class TestIntegrationWithDifferentBillingPeriods extends TestIntegrationB
new ExpectedInvoiceItemCheck(new LocalDate(2012, 6, 4), new LocalDate(2012, 6, 4), InvoiceItemType.CBA_ADJ, new BigDecimal("-2327.62")));
invoiceChecker.checkInvoice(invoices.get(3).getId(), callContext, toBeChecked);
- busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addYears(1);
assertListenerStatus();
@@ -307,7 +307,7 @@ public class TestIntegrationWithDifferentBillingPeriods extends TestIntegrationB
new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 12), new LocalDate(2013, 5, 1), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-2327.62")));
invoiceChecker.checkInvoice(invoices.get(2).getId(), callContext, toBeChecked);
- busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addYears(1);
assertListenerStatus();
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
index fbe0b9e..f38238b 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPublicBus.java
@@ -100,6 +100,8 @@ public class TestPublicBus extends TestIntegrationBase {
log.debug("RESET TEST FRAMEWORK");
+ controllerDispatcher.clearAll();
+
overdueConfigCache.loadDefaultOverdueConfig((OverdueConfig) null);
clock.resetDeltaFromReality();
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
index a08b05e..7970eab 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
@@ -211,7 +211,7 @@ public class TestSubscription extends TestIntegrationBase {
specifierList.add(addOnEntitlementSpecifier1);
specifierList.add(addOnEntitlementSpecifier2);
- busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE, NextEvent.CREATE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE, NextEvent.CREATE, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
final Entitlement entitlement = entitlementApi.createBaseEntitlementWithAddOns(account.getId(), externalKey, specifierList, initialDate, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
checkNoMoreInvoiceToGenerate(account);
@@ -251,7 +251,6 @@ public class TestSubscription extends TestIntegrationBase {
@Test(groups = "slow")
public void testCancelFutureSubscriptionWithPolicy() throws Exception {
-
final LocalDate initialDate = new LocalDate(2015, 9, 1);
clock.setDay(initialDate);
@@ -273,8 +272,7 @@ public class TestSubscription extends TestIntegrationBase {
assertListenerStatus();
// Move off trial and reach start/cancellation date
- // NextEvent.INVOICE is required because of #467
- busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.CANCEL);
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE);
clock.addDays(30);
assertListenerStatus();
@@ -285,7 +283,6 @@ public class TestSubscription extends TestIntegrationBase {
@Test(groups = "slow")
public void testCancelFutureSubscriptionWithRequestedDate() throws Exception {
-
final LocalDate initialDate = new LocalDate(2015, 9, 1);
clock.setDay(initialDate);
@@ -315,13 +312,12 @@ public class TestSubscription extends TestIntegrationBase {
assertListenerStatus();
// Move off trial and reach start/cancellation date
- busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.CANCEL);
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE);
clock.addDays(30);
assertListenerStatus();
// Just to make sure we really don't invoice for anything move to next month
clock.addMonths(1);
assertListenerStatus();
-
}
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
index 24fa051..07d2ecd 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
@@ -52,10 +52,8 @@ public class TestWithTimeZones extends TestIntegrationBase {
// Verify that recurring invoice items are correctly computed although we went through and out of daylight saving transitions
@Test(groups = "slow")
public void testWithDayLightSaving() throws Exception {
-
// Start with a date in daylight saving period and make sure we use a time of 8 hour so that we we reach standard time
// the next month where the difference is 9 hours, a transformation from DateTime to LocalDate with the account time zone would bring us a day earlier
- //
clock.setTime(new DateTime("2015-09-01T08:01:01.000Z"));
final DateTimeZone tz = DateTimeZone.forID("America/Juneau");
@@ -76,9 +74,9 @@ public class TestWithTimeZones extends TestIntegrationBase {
final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
- TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
- SubscriptionEventType.START_BILLING, null, null, clock.getUTCNow(), null);
- Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
+ final TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
+ SubscriptionEventType.START_BILLING, null, null, clock.getUTCNow(), null);
+ final Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 9, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
@@ -97,7 +95,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
LocalDate startDate = new LocalDate(2015, 11, 1);
// We loop 18 times to go over a year and transitions several times between winter and summer (daylight saving)
for (int i = 0; i < 18; i++) {
- LocalDate endDate = startDate.plusMonths(1);
+ final LocalDate endDate = startDate.plusMonths(1);
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addMonths(1);
@@ -109,10 +107,9 @@ public class TestWithTimeZones extends TestIntegrationBase {
}
}
- // Verify cancellation logic when we exit daylight savind period
+ // Verify cancellation logic when we exit daylight saving period
@Test(groups = "slow")
public void testCancellationFrom_PDT_to_PST() throws Exception {
-
// Start with a date in daylight saving period (PDT) and make sure we use a time of 7 hour so that we we reach standard time (PST)
// the next month where the difference is 8 hours, a transformation from DateTime to LocalDate with the account time zone would bring us a day earlier
// (e.g new LocalDate("2015-12-01T07:01:01.000Z", tz) -> "2015-11-30.
@@ -143,27 +140,18 @@ public class TestWithTimeZones extends TestIntegrationBase {
// Cancel the next month specifying just a LocalDate
final LocalDate cancellationDate = new LocalDate("2015-12-01", tz);
entitlement = entitlement.cancelEntitlementWithDate(cancellationDate, true, ImmutableList.<PluginProperty>of(), callContext);
+ assertListenerStatus();
// Verify first entitlement is correctly cancelled on the right date
Assert.assertEquals(entitlement.getEffectiveEndDate(), cancellationDate);
- // We move the clock to the date of the next invoice notification 2015-12-01 07:01:01 (invoice is using a fixed offset of 7 hours and all billing events are converted using that offset)
- clock.setTime(new DateTime("2015-12-01T07:01:02"));
- // Unfortunately we did not plug NullInvoice events so we cannot synchronize on that (See https://github.com/killbill/killbill/issues/448)
- assertListenerStatus();
-
- // We now move the clock to the date of the cancellation (one hour later), which match the cancellation day from the client point of view
- //
- // For curious reader, the reason why the time end up being '8:01:0' comes from (https://github.com/killbill/killbill-commons/blob/master/clock/src/main/java/org/killbill/clock/ClockUtil.java#L51):
- // We compute a DateTime in the account timezone by specifying explicitly the year-month-day we want to end up in, and shoving *a time*. The reason why we end up on an 8:01:02 is not necessarily so important,
- // What's important is that by construction that DateTime is guaranteed to match a LocalDate of 2015-12-01
- //
- busHandler.pushExpectedEvents(NextEvent.CANCEL, NextEvent.BLOCK);
- clock.setTime(new DateTime("2015-12-01T08:01:02"));
+ // We now move the clock to the date of the cancellation, which match the cancellation day from the client point of view
+ busHandler.pushExpectedEvents(NextEvent.NULL_INVOICE, NextEvent.CANCEL, NextEvent.BLOCK, NextEvent.NULL_INVOICE);
+ clock.setTime(new DateTime("2015-12-01T07:01:02Z"));
assertListenerStatus();
- // Verify second that there was no repair (so the cancellation did correctly happen on the "2015-12-01"
- List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
+ // Verify second that there was no repair (so the cancellation did correctly happen on the "2015-12-01")
+ final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
Assert.assertEquals(invoices.size(), 1);
}
@@ -171,7 +159,6 @@ public class TestWithTimeZones extends TestIntegrationBase {
// an offset of 8 hours and then go through 7 hours so anyway we would stay in the same day.
@Test(groups = "slow")
public void testCancellationFrom_PST_to_PDT() throws Exception {
-
clock.setTime(new DateTime("2015-02-01T08:01:01.000Z"));
final DateTimeZone tz = DateTimeZone.forID("America/Los_Angeles");
@@ -203,16 +190,13 @@ public class TestWithTimeZones extends TestIntegrationBase {
// Verify first entitlement is correctly cancelled on the right date
Assert.assertEquals(entitlement.getEffectiveEndDate(), cancellationDate);
-
// We now move the clock to the date of the cancellation which match the cancellation day from the client point of view
- busHandler.pushExpectedEvents(NextEvent.CANCEL, NextEvent.BLOCK);
+ busHandler.pushExpectedEvents(NextEvent.CANCEL, NextEvent.BLOCK, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE);
clock.setTime(new DateTime("2015-03-01T08:01:02"));
assertListenerStatus();
// Verify second that there was no repair (so the cancellation did correctly happen on the "2015-12-01"
- List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
+ final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
Assert.assertEquals(invoices.size(), 1);
-
}
-
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java
index 54107d1..80ccbac 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java
@@ -60,7 +60,6 @@ public class TestConsumableInArrear extends TestIntegrationBase {
@Test(groups = "slow")
public void testWithNoUsageInPeriodAndOldUsage() throws Exception {
-
final AccountData accountData = getAccountData(1);
final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
accountChecker.checkAccount(account.getId(), accountData, callContext);
@@ -80,12 +79,12 @@ public class TestConsumableInArrear extends TestIntegrationBase {
//
// ADD ADD_ON ON THE SAME DAY
//
- final DefaultEntitlement aoSubscription = addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Bullets", ProductCategory.ADD_ON, BillingPeriod.NO_BILLING_PERIOD, NextEvent.CREATE);
+ final DefaultEntitlement aoSubscription = addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Bullets", ProductCategory.ADD_ON, BillingPeriod.NO_BILLING_PERIOD, NextEvent.CREATE, NextEvent.NULL_INVOICE);
setUsage(aoSubscription.getId(), "bullets", new LocalDate(2012, 4, 1), 99L, callContext);
setUsage(aoSubscription.getId(), "bullets", new LocalDate(2012, 4, 15), 100L, callContext);
- busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addDays(30);
assertListenerStatus();
@@ -93,9 +92,10 @@ public class TestConsumableInArrear extends TestIntegrationBase {
new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2013, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("2399.95")),
new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 5, 1), InvoiceItemType.USAGE, new BigDecimal("5.90")));
- // We don't expect any invoice, but we want to give the system the time to verify there is nothing to do so we can fail
+ // We don't expect any invoice
+ busHandler.pushExpectedEvents(NextEvent.NULL_INVOICE);
clock.addMonths(1);
- Thread.sleep(1000);
+ assertListenerStatus();
setUsage(aoSubscription.getId(), "bullets", new LocalDate(2012, 6, 1), 50L, callContext);
setUsage(aoSubscription.getId(), "bullets", new LocalDate(2012, 6, 16), 300L, callContext);
@@ -128,7 +128,6 @@ public class TestConsumableInArrear extends TestIntegrationBase {
@Test(groups = "slow")
public void testWithCancellation() throws Exception {
-
final AccountData accountData = getAccountData(1);
final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
accountChecker.checkAccount(account.getId(), accountData, callContext);
@@ -148,12 +147,12 @@ public class TestConsumableInArrear extends TestIntegrationBase {
//
// ADD ADD_ON ON THE SAME DAY
//
- final DefaultEntitlement aoSubscription = addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Bullets", ProductCategory.ADD_ON, BillingPeriod.NO_BILLING_PERIOD, NextEvent.CREATE);
+ final DefaultEntitlement aoSubscription = addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Bullets", ProductCategory.ADD_ON, BillingPeriod.NO_BILLING_PERIOD, NextEvent.CREATE, NextEvent.NULL_INVOICE);
setUsage(aoSubscription.getId(), "bullets", new LocalDate(2012, 4, 1), 99L, callContext);
setUsage(aoSubscription.getId(), "bullets", new LocalDate(2012, 4, 15), 100L, callContext);
- busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addDays(30);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 2, callContext,
@@ -174,14 +173,13 @@ public class TestConsumableInArrear extends TestIntegrationBase {
invoiceChecker.checkInvoice(account.getId(), 3, callContext,
new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 5, 28), InvoiceItemType.USAGE, new BigDecimal("5.90")));
+ busHandler.pushExpectedEvent(NextEvent.NULL_INVOICE);
clock.addDays(4);
- Thread.sleep(1000);
-
+ assertListenerStatus();
}
@Test(groups = "slow")
public void testWithDayLightSaving() throws Exception {
-
clock.setTime(new DateTime("2015-09-01T08:01:01.000Z"));
final DateTimeZone tz = DateTimeZone.forID("America/Juneau");
@@ -212,20 +210,22 @@ public class TestConsumableInArrear extends TestIntegrationBase {
//
// ADD ADD_ON ON THE SAME DAY
//
- final DefaultEntitlement aoSubscription = addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Bullets", ProductCategory.ADD_ON, BillingPeriod.NO_BILLING_PERIOD, NextEvent.CREATE);
+ final DefaultEntitlement aoSubscription = addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Bullets", ProductCategory.ADD_ON, BillingPeriod.NO_BILLING_PERIOD, NextEvent.CREATE, NextEvent.NULL_INVOICE);
assertListenerStatus();
- busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addDays(30);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 2, callContext,
new ExpectedInvoiceItemCheck(new LocalDate(2015, 10, 1), new LocalDate(2016, 10, 1), InvoiceItemType.RECURRING, new BigDecimal("2399.95")));
// 2015-11-1
+ busHandler.pushExpectedEvent(NextEvent.NULL_INVOICE);
clock.addMonths(1);
assertListenerStatus();
// 2015-12-1
+ busHandler.pushExpectedEvent(NextEvent.NULL_INVOICE);
clock.addMonths(1);
assertListenerStatus();
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/CatalogDateHelper.java b/catalog/src/main/java/org/killbill/billing/catalog/CatalogDateHelper.java
new file mode 100644
index 0000000..0eb59ff
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/CatalogDateHelper.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.catalog;
+
+import java.util.Date;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+public abstract class CatalogDateHelper {
+
+ // From JDK to Joda (see http://www.joda.org/joda-time/userguide.html#JDK_Interoperability)
+ public static DateTime toUTCDateTime(final Date date) {
+ return new DateTime(date).toDateTime(DateTimeZone.UTC);
+ }
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
index 52e02e7..d0945db 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -19,6 +21,8 @@ package org.killbill.billing.catalog;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
@@ -73,7 +77,6 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements
@XmlElement(required = false)
private Integer plansAllowedInBundle = 1;
-
public DefaultPlan() {
initialPhases = new DefaultPlanPhase[0];
}
@@ -83,49 +86,64 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements
this.effectiveDateForExistingSubscriptons = in.getEffectiveDateForExistingSubscriptons();
this.product = (DefaultProduct) in.getProduct();
this.initialPhases = new DefaultPlanPhase[in.getInitialPhases().length];
- for (int i = 0; i< overrides.length - 1; i++) {
+ for (int i = 0; i < overrides.length - 1; i++) {
final DefaultPlanPhase newPhase = new DefaultPlanPhase(this, in.getInitialPhases()[i], overrides[i]);
initialPhases[i] = newPhase;
}
this.finalPhase = new DefaultPlanPhase(this, in.getFinalPhase(), overrides[overrides.length - 1]);
}
- /* (non-Javadoc)
- * @see org.killbill.billing.catalog.IPlan#getEffectiveDateForExistingSubscriptons()
- */
+
@Override
public Date getEffectiveDateForExistingSubscriptons() {
return effectiveDateForExistingSubscriptons;
- } /* (non-Javadoc)
- * @see org.killbill.billing.catalog.IPlan#getPhases()
- */
+ }
+
+ public void setEffectiveDateForExistingSubscriptons(
+ final Date effectiveDateForExistingSubscriptons) {
+ this.effectiveDateForExistingSubscriptons = effectiveDateForExistingSubscriptons;
+ }
@Override
public DefaultPlanPhase[] getInitialPhases() {
return initialPhases;
}
- /* (non-Javadoc)
- * @see org.killbill.billing.catalog.IPlan#getProduct()
- */
+ public DefaultPlan setInitialPhases(final DefaultPlanPhase[] phases) {
+ this.initialPhases = phases;
+ return this;
+ }
+
@Override
public Product getProduct() {
return product;
}
- /* (non-Javadoc)
- * @see org.killbill.billing.catalog.IPlan#getName()
- */
+ public DefaultPlan setProduct(final DefaultProduct product) {
+ this.product = product;
+ return this;
+ }
+
@Override
public String getName() {
return name;
}
+ public DefaultPlan setName(final String name) {
+ this.name = name;
+ return this;
+ }
+
@Override
public DefaultPlanPhase getFinalPhase() {
return finalPhase;
}
+ public DefaultPlan setFinalPhase(final DefaultPlanPhase finalPhase) {
+ this.finalPhase = finalPhase;
+ return this;
+ }
+
@Override
public PlanPhase[] getAllPhases() {
final int length = (initialPhases == null || initialPhases.length == 0) ? 1 : (initialPhases.length + 1);
@@ -156,23 +174,23 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements
return finalPhase.getRecurring() != null ? finalPhase.getRecurring().getBillingPeriod() : BillingPeriod.NO_BILLING_PERIOD;
}
- /* (non-Javadoc)
- * @see org.killbill.billing.catalog.IPlan#getPlansAllowedInBundle()
- */
@Override
public int getPlansAllowedInBundle() {
return plansAllowedInBundle;
}
+ public DefaultPlan setPlansAllowedInBundle(final Integer plansAllowedInBundle) {
+ this.plansAllowedInBundle = plansAllowedInBundle;
+ return this;
+ }
+
/* (non-Javadoc)
* @see org.killbill.billing.catalog.IPlan#getPhaseIterator()
*/
@Override
public Iterator<PlanPhase> getInitialPhaseIterator() {
- final ArrayList<PlanPhase> list = new ArrayList<PlanPhase>();
- for (final DefaultPlanPhase p : initialPhases) {
- list.add(p);
- }
+ final Collection<PlanPhase> list = new ArrayList<PlanPhase>();
+ Collections.addAll(list, initialPhases);
return list.iterator();
}
@@ -194,7 +212,7 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements
@Override
public ValidationErrors validate(final StandaloneCatalog catalog, final ValidationErrors errors) {
if (effectiveDateForExistingSubscriptons != null &&
- catalog.getEffectiveDate().getTime() > effectiveDateForExistingSubscriptons.getTime()) {
+ catalog.getEffectiveDate().getTime() > effectiveDateForExistingSubscriptons.getTime()) {
errors.add(new ValidationError(String.format("Price effective date %s is before catalog effective date '%s'",
effectiveDateForExistingSubscriptons,
catalog.getEffectiveDate().getTime()),
@@ -206,40 +224,10 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements
return errors;
}
- public void setEffectiveDateForExistingSubscriptons(
- final Date effectiveDateForExistingSubscriptons) {
- this.effectiveDateForExistingSubscriptons = effectiveDateForExistingSubscriptons;
- }
-
- public DefaultPlan setName(final String name) {
- this.name = name;
- return this;
- }
-
- public DefaultPlan setFinalPhase(final DefaultPlanPhase finalPhase) {
- this.finalPhase = finalPhase;
- return this;
- }
-
- public DefaultPlan setProduct(final DefaultProduct product) {
- this.product = product;
- return this;
- }
-
- public DefaultPlan setInitialPhases(final DefaultPlanPhase[] phases) {
- this.initialPhases = phases;
- return this;
- }
-
- public DefaultPlan setPlansAllowedInBundle(final Integer plansAllowedInBundle) {
- this.plansAllowedInBundle = plansAllowedInBundle;
- return this;
- }
-
@Override
public DateTime dateOfFirstRecurringNonZeroCharge(final DateTime subscriptionStartDate, final PhaseType initialPhaseType) {
- DateTime result = subscriptionStartDate.toDateTime();
- boolean skipPhase = initialPhaseType == null ? false : true;
+ DateTime result = subscriptionStartDate;
+ boolean skipPhase = initialPhaseType != null;
for (final PlanPhase phase : getAllPhases()) {
if (skipPhase) {
if (phase.getPhaseType() != initialPhaseType) {
@@ -303,8 +291,8 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements
@Override
public String toString() {
return "DefaultPlan [name=" + name + ", effectiveDateForExistingSubscriptons="
- + effectiveDateForExistingSubscriptons + ", product=" + product + ", initialPhases="
- + Arrays.toString(initialPhases) + ", finalPhase=" + finalPhase + ", plansAllowedInBundle="
- + plansAllowedInBundle + "]";
+ + effectiveDateForExistingSubscriptons + ", product=" + product + ", initialPhases="
+ + Arrays.toString(initialPhases) + ", finalPhase=" + finalPhase + ", plansAllowedInBundle="
+ + plansAllowedInBundle + "]";
}
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java b/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
index 3b5f7de..0d85afc 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
@@ -55,13 +55,10 @@ public class VersionedCatalogLoader implements CatalogLoader {
this.internalCallContextFactory = internalCallContextFactory;
}
- /* (non-Javadoc)
- * @see org.killbill.billing.catalog.io.ICatalogLoader#loadDefaultCatalog(java.lang.String)
- */
@Override
public VersionedCatalog loadDefaultCatalog(final String uriString) throws CatalogApiException {
try {
- List<URI> xmlURIs;
+ final List<URI> xmlURIs;
if (uriString.endsWith(XML_EXTENSION)) { // Assume its an xml file
xmlURIs = new ArrayList<URI>();
xmlURIs.add(new URI(uriString));
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
index ac2326a..d80bbd4 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -24,7 +24,6 @@ import java.util.regex.Matcher;
import javax.annotation.Nullable;
-import org.joda.time.DateTime;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -141,15 +140,14 @@ public class StandaloneCatalogWithPriceOverride extends ValidatingConfig<Standal
}
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(overrides.getCallContext());
- return priceOverride.getOrCreateOverriddenPlan(defaultPlan, new DateTime(getEffectiveDate()), overrides.getOverrides(), internalCallContext);
+ return priceOverride.getOrCreateOverriddenPlan(defaultPlan, CatalogDateHelper.toUTCDateTime(getEffectiveDate()), overrides.getOverrides(), internalCallContext);
}
@Override
public Plan findCurrentPlan(final String planName) throws CatalogApiException {
-
final Matcher m = DefaultPriceOverride.CUSTOM_PLAN_NAME_PATTERN.matcher(planName);
if (m.matches()) {
- final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(tenantRecordId, null);
+ final InternalTenantContext internalTenantContext = createInternalTenantContext();
return priceOverride.getOverriddenPlan(planName, standaloneCatalog, internalTenantContext);
}
return standaloneCatalog.findCurrentPlan(planName);
@@ -165,8 +163,8 @@ public class StandaloneCatalogWithPriceOverride extends ValidatingConfig<Standal
final String planName = DefaultPlanPhase.planName(phaseName);
final Matcher m = DefaultPriceOverride.CUSTOM_PLAN_NAME_PATTERN.matcher(planName);
if (m.matches()) {
- final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(tenantRecordId, null);
- Plan plan = priceOverride.getOverriddenPlan(planName, standaloneCatalog, internalTenantContext);
+ final InternalTenantContext internalTenantContext = createInternalTenantContext();
+ final Plan plan = priceOverride.getOverriddenPlan(planName, standaloneCatalog, internalTenantContext);
return plan.findPhase(phaseName);
}
return standaloneCatalog.findCurrentPhase(phaseName);
@@ -241,4 +239,7 @@ public class StandaloneCatalogWithPriceOverride extends ValidatingConfig<Standal
return standaloneCatalog.findCurrentPriceList(priceListName);
}
+ private InternalTenantContext createInternalTenantContext() {
+ return internalCallContextFactory.createInternalTenantContext(tenantRecordId, null);
+ }
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
index b0aa352..b4a222a 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -65,21 +65,20 @@ import org.killbill.xmlloader.ValidationErrors;
public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPriceOverride> implements Catalog, StaticCatalog {
private final Clock clock;
+ @XmlElement(name = "catalogVersion", required = true)
+ private final List<StandaloneCatalogWithPriceOverride> versions;
private String catalogName;
private BillingMode recurringBillingMode;
- @XmlElement(name = "catalogVersion", required = true)
- private List<StandaloneCatalogWithPriceOverride> versions;
-
// Required for JAXB deserialization
public VersionedCatalog() {
this.clock = null;
- versions = new ArrayList<StandaloneCatalogWithPriceOverride>();
+ this.versions = new ArrayList<StandaloneCatalogWithPriceOverride>();
}
public VersionedCatalog(final Clock clock) {
this.clock = clock;
- versions = new ArrayList<StandaloneCatalogWithPriceOverride>();
+ this.versions = new ArrayList<StandaloneCatalogWithPriceOverride>();
}
public VersionedCatalog(final Clock clock, final String catalogName, final BillingMode recurringBillingMode, final List<StandaloneCatalogWithPriceOverride> versions, final InternalTenantContext tenantContext) {
@@ -93,7 +92,6 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
}
}
-
//
// Private methods
//
@@ -154,16 +152,16 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
final DateTime subscriptionStartDate)
throws CatalogApiException {
final List<StandaloneCatalogWithPriceOverride> catalogs = versionsBeforeDate(requestedDate.toDate());
- if (catalogs.size() == 0) {
+ if (catalogs.isEmpty()) {
throw new CatalogApiException(ErrorCode.CAT_NO_CATALOG_FOR_GIVEN_DATE, requestedDate.toDate().toString());
}
for (int i = catalogs.size() - 1; i >= 0; i--) { // Working backwards to find the latest applicable plan
final StandaloneCatalogWithPriceOverride c = catalogs.get(i);
- Plan plan;
+ final Plan plan;
try {
plan = wrapper.findPlan(c);
- } catch (CatalogApiException e) {
+ } catch (final CatalogApiException e) {
if (e.getCode() != ErrorCode.CAT_NO_SUCH_PLAN.getCode()) {
throw e;
} else {
@@ -172,12 +170,12 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
}
}
- DateTime catalogEffectiveDate = new DateTime(c.getEffectiveDate());
+ final DateTime catalogEffectiveDate = CatalogDateHelper.toUTCDateTime(c.getEffectiveDate());
if (!subscriptionStartDate.isBefore(catalogEffectiveDate)) { // Its a new subscription this plan always applies
return plan;
} else { //Its an existing subscription
if (plan.getEffectiveDateForExistingSubscriptons() != null) { //if it is null any change to this does not apply to existing subscriptions
- final DateTime existingSubscriptionDate = new DateTime(plan.getEffectiveDateForExistingSubscriptons());
+ final DateTime existingSubscriptionDate = CatalogDateHelper.toUTCDateTime(plan.getEffectiveDateForExistingSubscriptons());
if (requestedDate.isAfter(existingSubscriptionDate)) { // this plan is now applicable to existing subs
return plan;
}
@@ -271,10 +269,10 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
@Override
public Plan createOrFindPlan(final String productName,
- final BillingPeriod term,
- final String priceListName,
- final PlanPhasePriceOverridesWithCallContext overrides,
- final DateTime requestedDate)
+ final BillingPeriod term,
+ final String priceListName,
+ final PlanPhasePriceOverridesWithCallContext overrides,
+ final DateTime requestedDate)
throws CatalogApiException {
return versionForDate(requestedDate).createOrFindCurrentPlan(productName, term, priceListName, overrides);
}
@@ -289,11 +287,11 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
@Override
public Plan createOrFindPlan(final String productName,
- final BillingPeriod term,
- final String priceListName,
- final PlanPhasePriceOverridesWithCallContext overrides,
- final DateTime requestedDate,
- final DateTime subscriptionStartDate)
+ final BillingPeriod term,
+ final String priceListName,
+ final PlanPhasePriceOverridesWithCallContext overrides,
+ final DateTime requestedDate,
+ final DateTime subscriptionStartDate)
throws CatalogApiException {
return findPlan(new PlanRequestWrapper(productName, term, priceListName, overrides), requestedDate, subscriptionStartDate);
}
@@ -434,7 +432,7 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
@Override
public Plan createOrFindCurrentPlan(final String productName, final BillingPeriod term,
- final String priceList, PlanPhasePriceOverridesWithCallContext overrides) throws CatalogApiException {
+ final String priceList, final PlanPhasePriceOverridesWithCallContext overrides) throws CatalogApiException {
return versionForDate(clock.getUTCNow()).createOrFindCurrentPlan(productName, term, priceList, overrides);
}
@@ -512,7 +510,7 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
}
@Override
- public boolean compliesWithLimits(String phaseName, String unit, double value) throws CatalogApiException {
+ public boolean compliesWithLimits(final String phaseName, final String unit, final double value) throws CatalogApiException {
return versionForDate(clock.getUTCNow()).compliesWithLimits(phaseName, unit, value);
}
}
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/glue/TestCatalogModule.java b/catalog/src/test/java/org/killbill/billing/catalog/glue/TestCatalogModule.java
index b6f5354..e3bef69 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/glue/TestCatalogModule.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/glue/TestCatalogModule.java
@@ -19,6 +19,7 @@
package org.killbill.billing.catalog.glue;
import org.killbill.billing.GuicyKillbillTestNoDBModule;
+import org.killbill.billing.mock.glue.MockAccountModule;
import org.killbill.billing.mock.glue.MockNonEntityDaoModule;
import org.killbill.billing.mock.glue.MockTenantModule;
import org.killbill.billing.platform.api.KillbillConfigSource;
@@ -36,5 +37,6 @@ public class TestCatalogModule extends CatalogModule {
install(new MockNonEntityDaoModule(configSource));
install(new CacheModule(configSource));
install(new MockTenantModule(configSource));
+ install(new MockAccountModule(configSource));
}
}
diff --git a/catalog/src/test/resources/catalogTest.xml b/catalog/src/test/resources/catalogTest.xml
index 56576c4..4b1ee25 100644
--- a/catalog/src/test/resources/catalogTest.xml
+++ b/catalog/src/test/resources/catalogTest.xml
@@ -50,6 +50,7 @@
<available>
<addonProduct>Cleaning</addonProduct>
<addonProduct>Bullets</addonProduct>
+ <addonProduct>Refurbish-Maintenance</addonProduct>
</available>
</product>
<product name="Shotgun">
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java
index 065076f..ec04528 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -30,7 +30,7 @@ import java.util.UUID;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
@@ -41,10 +41,8 @@ import org.killbill.billing.entitlement.block.BlockingChecker.BlockingAggregator
import org.killbill.billing.entitlement.block.DefaultBlockingChecker.DefaultBlockingAggregator;
import org.killbill.billing.junction.DefaultBlockingState;
-import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
// Given an event stream (across one or multiple entitlements), insert the blocking events at the right place
public class BlockingStateOrdering extends EntitlementOrderingBase {
@@ -53,29 +51,31 @@ public class BlockingStateOrdering extends EntitlementOrderingBase {
private BlockingStateOrdering() {}
- public static void insertSorted(final Iterable<Entitlement> entitlements, final DateTimeZone accountTimeZone, final LinkedList<SubscriptionEvent> result) {
- INSTANCE.computeEvents(entitlements, accountTimeZone, result);
+ public static void insertSorted(final Iterable<Entitlement> entitlements, final InternalTenantContext internalTenantContext, final LinkedList<SubscriptionEvent> result) {
+ INSTANCE.computeEvents(entitlements, internalTenantContext, result);
}
- private void computeEvents(final Iterable<Entitlement> entitlements, final DateTimeZone accountTimeZone, final LinkedList<SubscriptionEvent> result) {
+ private void computeEvents(final Iterable<Entitlement> entitlements, final InternalTenantContext internalTenantContext, final LinkedList<SubscriptionEvent> result) {
final Collection<UUID> allEntitlementUUIDs = new HashSet<UUID>();
final Collection<BlockingState> blockingStates = new LinkedList<BlockingState>();
+ final Map<UUID, DateTime> referenceTimes = new HashMap<UUID, DateTime>();
for (final Entitlement entitlement : entitlements) {
allEntitlementUUIDs.add(entitlement.getId());
Preconditions.checkState(entitlement instanceof DefaultEntitlement, "Entitlement %s is not a DefaultEntitlement", entitlement);
blockingStates.addAll(((DefaultEntitlement) entitlement).getEventsStream().getBlockingStates());
+ referenceTimes.put(entitlement.getId(), ((DefaultEntitlement) entitlement).getSubscriptionBase().getStartDate());
}
// Trust the incoming ordering here: blocking states were sorted using ProxyBlockingStateDao#sortedCopy
for (final BlockingState bs : blockingStates) {
final List<SubscriptionEvent> newEvents = new ArrayList<SubscriptionEvent>();
- final int index = insertFromBlockingEvent(accountTimeZone, allEntitlementUUIDs, result, bs, bs.getEffectiveDate(), newEvents);
+ final int index = insertFromBlockingEvent(referenceTimes, internalTenantContext, allEntitlementUUIDs, result, bs, bs.getEffectiveDate(), newEvents);
insertAfterIndex(result, newEvents, index);
}
}
// Returns the index and the newEvents generated from the incoming blocking state event. Those new events will all be created for the same effectiveDate and should be ordered.
- private int insertFromBlockingEvent(final DateTimeZone accountTimeZone, final Collection<UUID> allEntitlementUUIDs, final List<SubscriptionEvent> result, final BlockingState bs, final DateTime bsEffectiveDate, final List<SubscriptionEvent> newEvents) {
+ private int insertFromBlockingEvent(final Map<UUID, DateTime> referenceTimes, final InternalTenantContext internalTenantContext, final Collection<UUID> allEntitlementUUIDs, final List<SubscriptionEvent> result, final BlockingState bs, final DateTime bsEffectiveDate, final Collection<SubscriptionEvent> newEvents) {
// Keep the current state per entitlement
final Map<UUID, TargetState> targetStates = new HashMap<UUID, TargetState>();
for (final UUID cur : allEntitlementUUIDs) {
@@ -134,7 +134,7 @@ public class BlockingStateOrdering extends EntitlementOrderingBase {
final List<SubscriptionEventType> eventTypes = curTargetState.addStateAndReturnEventTypes(bs);
for (final SubscriptionEventType t : eventTypes) {
- newEvents.add(toSubscriptionEvent(prevNext[0], prevNext[1], targetEntitlementId, bs, t, accountTimeZone));
+ newEvents.add(toSubscriptionEvent(prevNext[0], prevNext[1], targetEntitlementId, bs, t, referenceTimes.get(targetEntitlementId), internalTenantContext));
}
}
return index;
@@ -176,7 +176,8 @@ public class BlockingStateOrdering extends EntitlementOrderingBase {
}
private SubscriptionEvent toSubscriptionEvent(@Nullable final SubscriptionEvent prev, @Nullable final SubscriptionEvent next,
- final UUID entitlementId, final BlockingState in, final SubscriptionEventType eventType, final DateTimeZone accountTimeZone) {
+ final UUID entitlementId, final BlockingState in, final SubscriptionEventType eventType,
+ final DateTime referenceTime, final InternalTenantContext internalTenantContext) {
final Product prevProduct;
final Plan prevPlan;
final PlanPhase prevPlanPhase;
@@ -257,7 +258,8 @@ public class BlockingStateOrdering extends EntitlementOrderingBase {
nextPriceList,
nextBillingPeriod,
in.getCreatedDate(),
- accountTimeZone);
+ referenceTime,
+ internalTenantContext);
}
private void insertAfterIndex(final LinkedList<SubscriptionEvent> original, final Collection<SubscriptionEvent> newEvents, final int index) {
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
index 93462b9..a93cdbb 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
@@ -25,11 +25,14 @@ import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
+import javax.annotation.Nullable;
+
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Plan;
@@ -76,6 +79,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
private final SecurityApi securityApi;
protected final EventsStreamBuilder eventsStreamBuilder;
protected final EntitlementDateHelper dateHelper;
+ protected final InternalTenantContext internalTenantContext;
protected final InternalCallContextFactory internalCallContextFactory;
protected final Clock clock;
protected final BlockingChecker checker;
@@ -90,7 +94,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
protected EventsStream eventsStream;
- public DefaultEntitlement(final UUID entitlementId, final EventsStreamBuilder eventsStreamBuilder,
+ public DefaultEntitlement(final UUID accountId, final UUID entitlementId, final EventsStreamBuilder eventsStreamBuilder,
final EntitlementApi entitlementApi, final EntitlementPluginExecution pluginExecution, final BlockingStateDao blockingStateDao,
final SubscriptionBaseInternalApi subscriptionInternalApi, final BlockingChecker checker,
final NotificationQueueService notificationQueueService, final EntitlementUtils entitlementUtils,
@@ -98,14 +102,14 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
final InternalCallContextFactory internalCallContextFactory, final TenantContext tenantContext) throws EntitlementApiException {
this(eventsStreamBuilder.buildForEntitlement(entitlementId, tenantContext), eventsStreamBuilder,
entitlementApi, pluginExecution, blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
- entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
+ entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory.createInternalTenantContext(accountId, tenantContext), internalCallContextFactory);
}
public DefaultEntitlement(final EventsStream eventsStream, final EventsStreamBuilder eventsStreamBuilder,
final EntitlementApi entitlementApi, final EntitlementPluginExecution pluginExecution, final BlockingStateDao blockingStateDao,
final SubscriptionBaseInternalApi subscriptionInternalApi, final BlockingChecker checker,
final NotificationQueueService notificationQueueService, final EntitlementUtils entitlementUtils,
- final EntitlementDateHelper dateHelper, final Clock clock, final SecurityApi securityApi, final InternalCallContextFactory internalCallContextFactory) {
+ final EntitlementDateHelper dateHelper, final Clock clock, final SecurityApi securityApi, final InternalTenantContext internalTenantContext, final InternalCallContextFactory internalCallContextFactory) {
super(eventsStream.getEntitlementId(), eventsStream.getSubscriptionBase().getCreatedDate(), eventsStream.getSubscriptionBase().getUpdatedDate());
this.eventsStreamBuilder = eventsStreamBuilder;
this.eventsStream = eventsStream;
@@ -113,6 +117,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
this.entitlementApi = entitlementApi;
this.pluginExecution = pluginExecution;
this.subscriptionInternalApi = subscriptionInternalApi;
+ this.internalTenantContext = internalTenantContext;
this.internalCallContextFactory = internalCallContextFactory;
this.clock = clock;
this.securityApi = securityApi;
@@ -135,6 +140,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
in.getDateHelper(),
in.getClock(),
in.getSecurityApi(),
+ in.getInternalTenantContext(),
in.getInternalCallContextFactory());
}
@@ -164,6 +170,10 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
return dateHelper;
}
+ public InternalTenantContext getInternalTenantContext() {
+ return internalTenantContext;
+ }
+
public InternalCallContextFactory getInternalCallContextFactory() {
return internalCallContextFactory;
}
@@ -236,7 +246,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
@Override
public LocalDate getEffectiveStartDate() {
- return new LocalDate(getSubscriptionBase().getStartDate(), eventsStream.getAccountTimeZone());
+ return internalTenantContext.toLocalDate(getSubscriptionBase().getStartDate(), getSubscriptionBase().getStartDate());
}
@Override
@@ -281,7 +291,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
}
@Override
- public Entitlement cancelEntitlementWithDate(final LocalDate localCancelDate, final boolean overrideBillingEffectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+ public Entitlement cancelEntitlementWithDate(@Nullable final LocalDate localCancelDate, final boolean overrideBillingEffectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
checkForPermissions(Permission.ENTITLEMENT_CAN_CANCEL, callContext);
@@ -391,7 +401,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
// See also EntitlementInternalApi#cancel for the bulk API
@Override
- public Entitlement cancelEntitlementWithDateOverrideBillingPolicy(final LocalDate localCancelDate, final BillingActionPolicy billingPolicy, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+ public Entitlement cancelEntitlementWithDateOverrideBillingPolicy(@Nullable final LocalDate localCancelDate, final BillingActionPolicy billingPolicy, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
checkForPermissions(Permission.ENTITLEMENT_CAN_CANCEL, callContext);
@@ -419,8 +429,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
// (we don't want an entitlement cancel date one second or so after the subscription cancel date or add-ons cancellations
// computations won't work).
final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(getAccountId(), callContext);
- final LocalDate effectiveLocalDate = new LocalDate(updatedPluginContext.getEffectiveDate(), eventsStream.getAccountTimeZone());
- final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(effectiveLocalDate, getSubscriptionBase().getStartDate(), contextWithValidAccountRecordId);
+ final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), getSubscriptionBase().getStartDate(), contextWithValidAccountRecordId);
try {
// Cancel subscription base first, to correctly compute the add-ons entitlements we need to cancel (see below)
@@ -449,10 +458,14 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
final LocalDate cancellationDate;
switch (entitlementPolicy) {
case IMMEDIATE:
- cancellationDate = new LocalDate(clock.getUTCNow(), eventsStream.getAccountTimeZone());
+ cancellationDate = clock.getToday(eventsStream.getAccountTimeZone());
break;
case END_OF_TERM:
- cancellationDate = getSubscriptionBase().getChargedThroughDate() != null ? new LocalDate(getSubscriptionBase().getChargedThroughDate(), eventsStream.getAccountTimeZone()) : new LocalDate(clock.getUTCNow(), eventsStream.getAccountTimeZone());
+ if (getSubscriptionBase().getChargedThroughDate() != null) {
+ cancellationDate = internalTenantContext.toLocalDate(getSubscriptionBase().getChargedThroughDate(), getSubscriptionBase().getStartDate());
+ } else {
+ cancellationDate = clock.getToday(eventsStream.getAccountTimeZone());
+ }
break;
default:
throw new RuntimeException("Unsupported policy " + entitlementPolicy);
@@ -522,7 +535,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
}
@Override
- public Entitlement changePlanWithDate(final String productName, final BillingPeriod billingPeriod, final String priceList, final List<PlanPhasePriceOverride> overrides, final LocalDate localDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+ public Entitlement changePlanWithDate(final String productName, final BillingPeriod billingPeriod, final String priceList, final List<PlanPhasePriceOverride> overrides, @Nullable final LocalDate localDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
checkForPermissions(Permission.ENTITLEMENT_CAN_CHANGE_PLAN, callContext);
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
index 0560b0e..67342e1 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
+import javax.annotation.Nullable;
import javax.inject.Inject;
import org.joda.time.DateTime;
@@ -111,11 +112,11 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
this.entitlementUtils = entitlementUtils;
this.pluginExecution = pluginExecution;
this.securityApi = securityApi;
- this.dateHelper = new EntitlementDateHelper(accountApi, clock);
+ this.dateHelper = new EntitlementDateHelper(clock);
}
@Override
- public Entitlement createBaseEntitlement(final UUID accountId, final PlanPhaseSpecifier planPhaseSpecifier, final String externalKey, final List<PlanPhasePriceOverride> overrides, final LocalDate effectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+ public Entitlement createBaseEntitlement(final UUID accountId, final PlanPhaseSpecifier planPhaseSpecifier, final String externalKey, final List<PlanPhasePriceOverride> overrides, @Nullable final LocalDate effectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
final EntitlementSpecifier entitlementSpecifier = new DefaultEntitlementSpecifier(planPhaseSpecifier, overrides);
final List<EntitlementSpecifier> entitlementSpecifierList = new ArrayList<EntitlementSpecifier>();
@@ -135,7 +136,6 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
public Entitlement doCall(final EntitlementApi entitlementApi, final EntitlementContext updatedPluginContext) throws EntitlementApiException {
final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(accountId, callContext);
try {
-
if (entitlementUtils.getFirstActiveSubscriptionIdForKeyOrNull(externalKey, contextWithValidAccountRecordId) != null) {
throw new EntitlementApiException(new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS, externalKey));
}
@@ -147,7 +147,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
final EntitlementSpecifier specifier = getFirstEntitlementSpecifier(updatedPluginContext.getEntitlementSpecifiers());
final SubscriptionBase subscription = subscriptionBaseInternalApi.createSubscription(bundle.getId(), specifier.getPlanPhaseSpecifier(), specifier.getOverrides(), requestedDate, contextWithValidAccountRecordId);
- return new DefaultEntitlement(subscription.getId(), eventsStreamBuilder, entitlementApi, pluginExecution,
+ return new DefaultEntitlement(accountId, subscription.getId(), eventsStreamBuilder, entitlementApi, pluginExecution,
blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory, callContext);
} catch (final SubscriptionBaseApiException e) {
@@ -167,7 +167,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
@Override
public Entitlement createBaseEntitlementWithAddOns(final UUID accountId, final String externalKey, final Iterable<EntitlementSpecifier> entitlementSpecifiers,
- final LocalDate effectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext)
+ @Nullable final LocalDate effectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext)
throws EntitlementApiException {
final EntitlementSpecifier baseSpecifier = Iterables.tryFind(entitlementSpecifiers, new Predicate<EntitlementSpecifier>() {
@@ -210,7 +210,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
final DateTime requestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), referenceTime, contextWithValidAccountRecordId);
final SubscriptionBase subscription = subscriptionBaseInternalApi.createBaseSubscriptionWithAddOns(bundle.getId(), entitlementSpecifiers, requestedDate, contextWithValidAccountRecordId);
- return new DefaultEntitlement(subscription.getId(), eventsStreamBuilder, entitlementApi, pluginExecution,
+ return new DefaultEntitlement(accountId, subscription.getId(), eventsStreamBuilder, entitlementApi, pluginExecution,
blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory, callContext);
@@ -224,7 +224,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
}
@Override
- public Entitlement addEntitlement(final UUID bundleId, final PlanPhaseSpecifier planPhaseSpecifier, final List<PlanPhasePriceOverride> overrides, final LocalDate effectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+ public Entitlement addEntitlement(final UUID bundleId, final PlanPhaseSpecifier planPhaseSpecifier, final List<PlanPhasePriceOverride> overrides, @Nullable final LocalDate effectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
final EntitlementSpecifier entitlementSpecifier = new DefaultEntitlementSpecifier(planPhaseSpecifier, overrides);
final List<EntitlementSpecifier> entitlementSpecifierList = new ArrayList<EntitlementSpecifier>();
@@ -261,7 +261,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
final EntitlementSpecifier specifier = getFirstEntitlementSpecifier(updatedPluginContext.getEntitlementSpecifiers());
final SubscriptionBase subscription = subscriptionBaseInternalApi.createSubscription(bundleId, specifier.getPlanPhaseSpecifier(), specifier.getOverrides(), requestedDate, context);
- return new DefaultEntitlement(subscription.getId(), eventsStreamBuilder, entitlementApi, pluginExecution,
+ return new DefaultEntitlement(eventsStreamForBaseSubscription.getAccountId(), subscription.getId(), eventsStreamBuilder, entitlementApi, pluginExecution,
blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory, callContext);
} catch (final SubscriptionBaseApiException e) {
@@ -273,8 +273,8 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
}
@Override
- public List<EntitlementAOStatusDryRun> getDryRunStatusForChange(final UUID bundleId, final String targetProductName, final LocalDate effectiveDate, final TenantContext context) throws EntitlementApiException {
- final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(context);
+ public List<EntitlementAOStatusDryRun> getDryRunStatusForChange(final UUID bundleId, final String targetProductName, @Nullable final LocalDate effectiveDate, final TenantContext context) throws EntitlementApiException {
+ final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(bundleId, ObjectType.BUNDLE, context);
try {
final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.getBundleFromId(bundleId, internalContext);
final SubscriptionBase baseSubscription = subscriptionBaseInternalApi.getBaseSubscription(bundleId, internalContext);
@@ -295,7 +295,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
@Override
public List<Entitlement> getAllEntitlementsForBundle(final UUID bundleId, final TenantContext tenantContext) throws EntitlementApiException {
- final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(tenantContext);
+ final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(bundleId, ObjectType.BUNDLE, tenantContext);
final UUID accountId;
try {
accountId = subscriptionBaseInternalApi.getBundleFromId(bundleId, internalContext).getAccountId();
@@ -337,7 +337,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
public Entitlement apply(final EventsStream eventsStream) {
return new DefaultEntitlement(eventsStream, eventsStreamBuilder, entitlementApi, pluginExecution,
blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
- entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
+ entitlementUtils, dateHelper, clock, securityApi, context, internalCallContextFactory);
}
});
}
@@ -376,7 +376,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
}
@Override
- public UUID transferEntitlementsOverrideBillingPolicy(final UUID sourceAccountId, final UUID destAccountId, final String externalKey, final LocalDate effectiveDate, final BillingActionPolicy billingPolicy, final Iterable<PluginProperty> properties, final CallContext context) throws EntitlementApiException {
+ public UUID transferEntitlementsOverrideBillingPolicy(final UUID sourceAccountId, final UUID destAccountId, final String externalKey, @Nullable final LocalDate effectiveDate, final BillingActionPolicy billingPolicy, final Iterable<PluginProperty> properties, final CallContext context) throws EntitlementApiException {
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.TRANSFER_BUNDLE,
sourceAccountId,
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementContext.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementContext.java
index 79da30c..000c1a0 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementContext.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementContext.java
@@ -73,7 +73,7 @@ public class DefaultEntitlementContext implements EntitlementContext {
final UUID bundleId,
final String externalKey,
final List<EntitlementSpecifier> entitlementSpecifiers,
- final LocalDate effectiveDate,
+ @Nullable final LocalDate effectiveDate,
final Iterable<PluginProperty> pluginProperties,
final CallContext callContext) {
this(operationType, accountId, destinationAccountId, bundleId, externalKey, entitlementSpecifiers, effectiveDate, pluginProperties,
@@ -88,7 +88,7 @@ public class DefaultEntitlementContext implements EntitlementContext {
final UUID bundleId,
final String externalKey,
final List<EntitlementSpecifier> entitlementSpecifiers,
- final LocalDate effectiveDate,
+ @Nullable final LocalDate effectiveDate,
final Iterable<PluginProperty> pluginProperties,
final UUID userToken,
final String userName,
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscription.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscription.java
index 3667835..9da4080 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscription.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscription.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -31,7 +31,7 @@ public class DefaultSubscription extends DefaultEntitlement implements Subscript
@Override
public LocalDate getBillingStartDate() {
- return new LocalDate(getSubscriptionBase().getStartDate(), getAccountTimeZone());
+ return internalTenantContext.toLocalDate(getSubscriptionBase().getStartDate(), getSubscriptionBase().getStartDate());
}
@Override
@@ -51,16 +51,16 @@ public class DefaultSubscription extends DefaultEntitlement implements Subscript
futureOrCurrentEndDate = futureOrCurrentEndDateForSubscription;
}
- return futureOrCurrentEndDate != null ? new LocalDate(futureOrCurrentEndDate, getAccountTimeZone()) : null;
+ return futureOrCurrentEndDate != null ? internalTenantContext.toLocalDate(futureOrCurrentEndDate, getSubscriptionBase().getStartDate()) : null;
}
@Override
public LocalDate getChargedThroughDate() {
- return getSubscriptionBase().getChargedThroughDate() != null ? new LocalDate(getSubscriptionBase().getChargedThroughDate(), getAccountTimeZone()) : null;
+ return getSubscriptionBase().getChargedThroughDate() != null ? internalTenantContext.toLocalDate(getSubscriptionBase().getChargedThroughDate(), getSubscriptionBase().getStartDate()) : null;
}
@Override
public List<SubscriptionEvent> getSubscriptionEvents() {
- return SubscriptionEventOrdering.sortedCopy(this, getAccountTimeZone());
+ return SubscriptionEventOrdering.sortedCopy(this, internalTenantContext);
}
}
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
index 5aeffe1..e74f7ef 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -121,10 +121,6 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
@Override
public SubscriptionBundle getSubscriptionBundle(final UUID bundleId, final TenantContext tenantContext) throws SubscriptionApiException {
-
- final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(tenantContext);
-
-
final UUID accountId = internalCallContextFactory.getAccountId(bundleId, ObjectType.BUNDLE, tenantContext);
final Optional<SubscriptionBundle> bundleOptional = Iterables.<SubscriptionBundle>tryFind(getSubscriptionBundlesForAccount(accountId, tenantContext),
@@ -241,10 +237,11 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
}
private List<SubscriptionBundle> getSubscriptionBundlesForAccount(final UUID accountId, final TenantContext tenantContext) throws SubscriptionApiException {
+ final InternalTenantContext internalTenantContextWithValidAccountRecordId = internalCallContextFactory.createInternalTenantContext(accountId, tenantContext);
+
// Retrieve entitlements
final AccountEntitlements accountEntitlements;
try {
- final InternalTenantContext internalTenantContextWithValidAccountRecordId = internalCallContextFactory.createInternalTenantContext(accountId, tenantContext);
accountEntitlements = entitlementInternalApi.getAllEntitlementsForAccountId(accountId, internalTenantContextWithValidAccountRecordId);
} catch (final EntitlementApiException e) {
throw new SubscriptionApiException(e);
@@ -261,11 +258,11 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
final List<Subscription> subscriptionsForBundle = subscriptionsPerBundle.get(bundleId);
final String externalKey = subscriptionsForBundle.get(0).getExternalKey();
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone,
- accountId,
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId,
bundleId,
externalKey,
- accountEntitlements.getEntitlements().get(bundleId));
+ accountEntitlements.getEntitlements().get(bundleId),
+ internalTenantContextWithValidAccountRecordId);
final SubscriptionBaseBundle baseBundle = accountEntitlements.getBundles().get(bundleId);
final SubscriptionBundle subscriptionBundle = new DefaultSubscriptionBundle(bundleId,
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
index 91e5758..3d9f2ef 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -21,7 +21,7 @@ package org.killbill.billing.entitlement.api;
import java.util.List;
import java.util.UUID;
-import org.joda.time.DateTimeZone;
+import org.killbill.billing.callcontext.InternalTenantContext;
public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTimeline {
@@ -30,11 +30,15 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
private final String externalKey;
private final List<SubscriptionEvent> events;
- public DefaultSubscriptionBundleTimeline(final DateTimeZone accountTimeZone, final UUID accountId, final UUID bundleId, final String externalKey, final Iterable<Entitlement> entitlements) {
+ public DefaultSubscriptionBundleTimeline(final UUID accountId,
+ final UUID bundleId,
+ final String externalKey,
+ final Iterable<Entitlement> entitlements,
+ final InternalTenantContext internalTenantContext) {
this.accountId = accountId;
this.bundleId = bundleId;
this.externalKey = externalKey;
- this.events = SubscriptionEventOrdering.sortedCopy(entitlements, accountTimeZone);
+ this.events = SubscriptionEventOrdering.sortedCopy(entitlements, internalTenantContext);
}
@Override
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionEvent.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionEvent.java
index 9035efc..0bd996d 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionEvent.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionEvent.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -21,7 +23,7 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
-
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
@@ -50,7 +52,8 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
private final PriceList nextPriceList;
private final BillingPeriod nextBillingPeriod;
private final DateTime createdDate;
- private final DateTimeZone accountTimeZone;
+ private final DateTime referenceTime;
+ private final InternalTenantContext internalTenantContext;
public DefaultSubscriptionEvent(final UUID id,
final UUID entitlementId,
@@ -71,7 +74,8 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
final PriceList nextPriceList,
final BillingPeriod nextBillingPeriod,
final DateTime createDate,
- final DateTimeZone accountTimeZone) {
+ final DateTime referenceTime,
+ final InternalTenantContext internalTenantContext) {
this.id = id;
this.entitlementId = entitlementId;
this.effectiveDate = effectiveDate;
@@ -92,11 +96,8 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
this.nextPriceList = nextPriceList;
this.nextBillingPeriod = nextBillingPeriod;
this.createdDate = createDate;
- this.accountTimeZone = accountTimeZone;
- }
-
- public DateTimeZone getAccountTimeZone() {
- return accountTimeZone;
+ this.referenceTime = referenceTime;
+ this.internalTenantContext = internalTenantContext;
}
public DateTime getEffectiveDateTime() {
@@ -119,12 +120,12 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
@Override
public LocalDate getEffectiveDate() {
- return effectiveDate != null ? new LocalDate(effectiveDate, accountTimeZone) : null;
+ return effectiveDate != null ? internalTenantContext.toLocalDate(effectiveDate, referenceTime) : null;
}
@Override
public LocalDate getRequestedDate() {
- return requestedDate != null ? new LocalDate(requestedDate, accountTimeZone) : null;
+ return requestedDate != null ? internalTenantContext.toLocalDate(requestedDate, referenceTime) : null;
}
@Override
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java
index d802daa..9ab7b85 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -16,47 +18,39 @@
package org.killbill.billing.entitlement.api;
+import javax.annotation.Nullable;
+
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
-import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountInternalApi;
-import org.killbill.billing.account.api.ImmutableAccountData;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.clock.Clock;
-import org.killbill.clock.ClockUtil;
public class EntitlementDateHelper {
- private final AccountInternalApi accountApi;
private final Clock clock;
- public EntitlementDateHelper(final AccountInternalApi accountApi, final Clock clock) {
- this.accountApi = accountApi;
+ public EntitlementDateHelper(final Clock clock) {
this.clock = clock;
}
- public DateTime fromLocalDateAndReferenceTime(final LocalDate requestedDate, final DateTime referenceDateTime, final InternalTenantContext callContext) throws EntitlementApiException {
- try {
- final ImmutableAccountData account = accountApi.getImmutableAccountDataByRecordId(callContext.getAccountRecordId(), callContext);
- return ClockUtil.computeDateTimeWithUTCReferenceTime(requestedDate, referenceDateTime.toDateTime(DateTimeZone.UTC).toLocalTime(), account.getTimeZone(), clock);
- } catch (AccountApiException e) {
- throw new EntitlementApiException(e);
- }
+ public DateTime fromLocalDateAndReferenceTime(@Nullable final LocalDate requestedDate, final DateTime referenceDateTime, final InternalTenantContext callContext) throws EntitlementApiException {
+ return requestedDate == null ? clock.getUTCNow() : callContext.toUTCDateTime(requestedDate, referenceDateTime);
}
/**
* Check if the date portion of a date/time is before or equals at now (as returned by the clock).
*
- * @param inputDate the fully qualified DateTime
- * @param accountTimeZone the account timezone
+ * @param inputDate the fully qualified DateTime
+ * @param accountTimeZone the account timezone
+ * @param internalTenantContext the context
* @return true if the inputDate, once converted into a LocalDate using account timezone is less or equals than today
*/
// TODO Move to ClockUtils
- public boolean isBeforeOrEqualsToday(final DateTime inputDate, final DateTimeZone accountTimeZone) {
- final LocalDate localDateNowInAccountTimezone = new LocalDate(clock.getUTCNow(), accountTimeZone);
- final LocalDate targetDateInAccountTimezone = new LocalDate(inputDate, accountTimeZone);
+ public boolean isBeforeOrEqualsToday(final DateTime inputDate, final DateTime referenceDatetime, final DateTimeZone accountTimeZone, final InternalTenantContext internalTenantContext) {
+ final LocalDate localDateNowInAccountTimezone = clock.getToday(accountTimeZone);
+ final LocalDate targetDateInAccountTimezone = internalTenantContext.toLocalDate(inputDate, referenceDatetime);
return targetDateInAccountTimezone.compareTo(localDateNowInAccountTimezone) <= 0;
}
-
}
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java
index 26ae84e..b6614b5 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -24,7 +24,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import org.joda.time.DateTimeZone;
+import org.joda.time.DateTime;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.entitlement.DefaultEntitlementService;
import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
@@ -47,20 +48,20 @@ public class SubscriptionEventOrdering extends EntitlementOrderingBase {
private SubscriptionEventOrdering() {}
- public static List<SubscriptionEvent> sortedCopy(final Entitlement entitlement, final DateTimeZone accountTimeZone) {
- return sortedCopy(ImmutableList.<Entitlement>of(entitlement), accountTimeZone);
+ public static List<SubscriptionEvent> sortedCopy(final Entitlement entitlement, final InternalTenantContext internalTenantContext) {
+ return sortedCopy(ImmutableList.<Entitlement>of(entitlement), internalTenantContext);
}
- public static List<SubscriptionEvent> sortedCopy(final Iterable<Entitlement> entitlements, final DateTimeZone accountTimeZone) {
- return INSTANCE.computeEvents(entitlements, accountTimeZone);
+ public static List<SubscriptionEvent> sortedCopy(final Iterable<Entitlement> entitlements, final InternalTenantContext internalTenantContext) {
+ return INSTANCE.computeEvents(entitlements, internalTenantContext);
}
- private List<SubscriptionEvent> computeEvents(final Iterable<Entitlement> entitlements, final DateTimeZone accountTimeZone) {
+ private List<SubscriptionEvent> computeEvents(final Iterable<Entitlement> entitlements, final InternalTenantContext internalTenantContext) {
// Compute base events across all entitlements (already ordered per entitlement)
- final LinkedList<SubscriptionEvent> result = computeSubscriptionBaseEvents(entitlements, accountTimeZone);
+ final LinkedList<SubscriptionEvent> result = computeSubscriptionBaseEvents(entitlements, internalTenantContext);
// Add blocking states at the right place
- BlockingStateOrdering.insertSorted(entitlements, accountTimeZone, result);
+ BlockingStateOrdering.insertSorted(entitlements, internalTenantContext, result);
// Final cleanups
reOrderSubscriptionEventsOnSameDateByType(result);
@@ -70,7 +71,7 @@ public class SubscriptionEventOrdering extends EntitlementOrderingBase {
}
// Compute the initial stream of events based on the subscription base events
- private LinkedList<SubscriptionEvent> computeSubscriptionBaseEvents(final Iterable<Entitlement> entitlements, final DateTimeZone accountTimeZone) {
+ private LinkedList<SubscriptionEvent> computeSubscriptionBaseEvents(final Iterable<Entitlement> entitlements, final InternalTenantContext internalTenantContext) {
final LinkedList<SubscriptionEvent> result = new LinkedList<SubscriptionEvent>();
for (final Entitlement cur : entitlements) {
Preconditions.checkState(cur instanceof DefaultEntitlement, "Entitlement %s is not a DefaultEntitlement", cur);
@@ -79,7 +80,7 @@ public class SubscriptionEventOrdering extends EntitlementOrderingBase {
for (final SubscriptionBaseTransition tr : baseTransitions) {
final List<SubscriptionEventType> eventTypes = toEventTypes(tr.getTransitionType());
for (final SubscriptionEventType eventType : eventTypes) {
- final SubscriptionEvent event = toSubscriptionEvent(tr, eventType, accountTimeZone);
+ final SubscriptionEvent event = toSubscriptionEvent(tr, eventType, base.getStartDate(), internalTenantContext);
insertSubscriptionEvent(event, result);
}
}
@@ -150,7 +151,7 @@ public class SubscriptionEventOrdering extends EntitlementOrderingBase {
result.add(index, event);
}
- private SubscriptionEvent toSubscriptionEvent(final SubscriptionBaseTransition in, final SubscriptionEventType eventType, final DateTimeZone accountTimeZone) {
+ private SubscriptionEvent toSubscriptionEvent(final SubscriptionBaseTransition in, final SubscriptionEventType eventType, final DateTime referenceTime, final InternalTenantContext internalTenantContext) {
return new DefaultSubscriptionEvent(in.getId(),
in.getSubscriptionId(),
in.getEffectiveTransitionTime(),
@@ -170,7 +171,8 @@ public class SubscriptionEventOrdering extends EntitlementOrderingBase {
in.getNextPriceList(),
(in.getNextPlan() != null ? in.getNextPlan().getRecurringBillingPeriod() : null),
in.getCreatedDate(),
- accountTimeZone);
+ referenceTime,
+ internalTenantContext);
}
//
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java
index 59f2c89..1198f44 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -120,11 +120,10 @@ public class DefaultEntitlementApiBase {
this.eventsStreamBuilder = eventsStreamBuilder;
this.entitlementUtils = entitlementUtils;
this.securityApi = securityApi;
- this.dateHelper = new EntitlementDateHelper(accountApi, clock);
+ this.dateHelper = new EntitlementDateHelper(clock);
}
public AccountEntitlements getAllEntitlementsForAccountId(final UUID accountId, final InternalTenantContext tenantContext) throws EntitlementApiException {
-
final AccountEventsStreams accountEventsStreams = eventsStreamBuilder.buildForAccount(tenantContext);
final Map<UUID, Collection<Entitlement>> entitlementsPerBundle = new HashMap<UUID, Collection<Entitlement>>();
@@ -136,7 +135,7 @@ public class DefaultEntitlementApiBase {
for (final EventsStream eventsStream : accountEventsStreams.getEventsStreams().get(bundleId)) {
final Entitlement entitlement = new DefaultEntitlement(eventsStream, eventsStreamBuilder, entitlementApi, pluginExecution,
blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
- entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
+ entitlementUtils, dateHelper, clock, securityApi, tenantContext, internalCallContextFactory);
entitlementsPerBundle.get(bundleId).add(entitlement);
}
}
@@ -148,10 +147,10 @@ public class DefaultEntitlementApiBase {
final EventsStream eventsStream = eventsStreamBuilder.buildForEntitlement(entitlementId, tenantContext);
return new DefaultEntitlement(eventsStream, eventsStreamBuilder, entitlementApi, pluginExecution,
blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
- entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
+ entitlementUtils, dateHelper, clock, securityApi, tenantContext, internalCallContextFactory);
}
- public void pause(final UUID bundleId, final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
+ public void pause(final UUID bundleId, @Nullable final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.PAUSE_SUBSCRIPTION,
null,
@@ -173,7 +172,7 @@ public class DefaultEntitlementApiBase {
final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, internalCallContext);
final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), baseSubscription.getStartDate(), internalCallContext);
- if (!dateHelper.isBeforeOrEqualsToday(effectiveDate, account.getTimeZone())) {
+ if (!dateHelper.isBeforeOrEqualsToday(effectiveDate, baseSubscription.getStartDate(), account.getTimeZone(), internalCallContext)) {
recordPauseResumeNotificationEntry(baseSubscription.getId(), bundleId, effectiveDate, true, internalCallContext);
return null;
}
@@ -204,7 +203,7 @@ public class DefaultEntitlementApiBase {
pluginExecution.executeWithPlugin(pauseWithPlugin, pluginContext);
}
- public void resume(final UUID bundleId, final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
+ public void resume(final UUID bundleId, @Nullable final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.RESUME_SUBSCRIPTION,
null,
@@ -225,7 +224,7 @@ public class DefaultEntitlementApiBase {
final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), baseSubscription.getStartDate(), internalCallContext);
- if (!dateHelper.isBeforeOrEqualsToday(effectiveDate, account.getTimeZone())) {
+ if (!dateHelper.isBeforeOrEqualsToday(effectiveDate, baseSubscription.getStartDate(), account.getTimeZone(), internalCallContext)) {
recordPauseResumeNotificationEntry(baseSubscription.getId(), bundleId, effectiveDate, false, internalCallContext);
return null;
}
@@ -261,7 +260,7 @@ public class DefaultEntitlementApiBase {
blockUnblockBundle(bundleId, stateName, serviceName, localEffectiveDate, blockBilling, blockEntitlement, blockChange, null, internalCallContext);
}
- private UUID blockUnblockBundle(final UUID bundleId, final String stateName, final String serviceName, final LocalDate localEffectiveDate, boolean blockBilling, boolean blockEntitlement, boolean blockChange, @Nullable final SubscriptionBase inputBaseSubscription, final InternalCallContext internalCallContext)
+ private UUID blockUnblockBundle(final UUID bundleId, final String stateName, final String serviceName, @Nullable final LocalDate localEffectiveDate, boolean blockBilling, boolean blockEntitlement, boolean blockChange, @Nullable final SubscriptionBase inputBaseSubscription, final InternalCallContext internalCallContext)
throws EntitlementApiException {
try {
final SubscriptionBase baseSubscription = inputBaseSubscription == null ? subscriptionInternalApi.getBaseSubscription(bundleId, internalCallContext) : inputBaseSubscription;
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
index d77e4ab..8398dc9 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
@@ -28,6 +28,7 @@ import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
+import javax.annotation.Nullable;
import javax.inject.Inject;
import org.joda.time.DateTime;
@@ -91,7 +92,7 @@ public class DefaultEntitlementInternalApi extends DefaultEntitlementApiBase imp
}
@Override
- public void cancel(final Iterable<Entitlement> entitlements, final LocalDate effectiveDate, final BillingActionPolicy billingPolicy, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
+ public void cancel(final Iterable<Entitlement> entitlements, @Nullable final LocalDate effectiveDate, final BillingActionPolicy billingPolicy, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
final CallContext callContext = internalCallContextFactory.createCallContext(internalCallContext);
final ImmutableMap.Builder<BlockingState, Optional<UUID>> blockingStates = new ImmutableMap.Builder<BlockingState, Optional<UUID>>();
@@ -216,8 +217,7 @@ public class DefaultEntitlementInternalApi extends DefaultEntitlementApiBase imp
@Override
public Entitlement doCall(final EntitlementApi entitlementApi, final EntitlementContext updatedPluginContext) throws EntitlementApiException {
- final LocalDate effectiveLocalDate = new LocalDate(updatedPluginContext.getEffectiveDate(), entitlement.getAccountTimeZone());
- DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(effectiveLocalDate, entitlement.getSubscriptionBase().getStartDate(), internalCallContext);
+ DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEffectiveDate(), entitlement.getSubscriptionBase().getStartDate(), internalCallContext);
// Avoid timing issues for IMM cancellations (we don't want an entitlement cancel date one second or so after the subscription cancel date or
// add-ons cancellations computations won't work).
if (effectiveDate.compareTo(entitlement.getSubscriptionBase().getEndDate()) > 0) {
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/DefaultBlockingStateDao.java b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/DefaultBlockingStateDao.java
index 9d67470..cb1551e 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/DefaultBlockingStateDao.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/DefaultBlockingStateDao.java
@@ -47,6 +47,7 @@ import org.killbill.billing.entitlement.block.StatelessBlockingChecker;
import org.killbill.billing.entitlement.engine.core.BlockingTransitionNotificationKey;
import org.killbill.billing.util.cache.Cachable.CacheType;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.dao.EntityDaoBase;
import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
@@ -112,8 +113,8 @@ public class DefaultBlockingStateDao extends EntityDaoBase<BlockingStateModelDao
private final StatelessBlockingChecker statelessBlockingChecker = new StatelessBlockingChecker();
public DefaultBlockingStateDao(final IDBI dbi, final Clock clock, final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
- final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), BlockingStateSqlDao.class);
+ final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), BlockingStateSqlDao.class);
this.clock = clock;
this.notificationQueueService = notificationQueueService;
this.eventBus = eventBus;
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java
index 3c228f2..35c718a 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/OptimizedProxyBlockingStateDao.java
@@ -35,6 +35,7 @@ import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.bus.api.PersistentBus;
import org.killbill.clock.Clock;
@@ -47,8 +48,8 @@ public class OptimizedProxyBlockingStateDao extends ProxyBlockingStateDao {
public OptimizedProxyBlockingStateDao(final EventsStreamBuilder eventsStreamBuilder, final SubscriptionBaseInternalApi subscriptionBaseInternalApi,
final IDBI dbi, final Clock clock, final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
- final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
- super(eventsStreamBuilder, subscriptionBaseInternalApi, dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao);
+ final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
+ super(eventsStreamBuilder, subscriptionBaseInternalApi, dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
}
/**
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java
index 1defc97..ea237a3 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/ProxyBlockingStateDao.java
@@ -44,6 +44,7 @@ import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.customfield.ShouldntHappenException;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.Pagination;
@@ -171,11 +172,11 @@ public class ProxyBlockingStateDao implements BlockingStateDao {
@Inject
public ProxyBlockingStateDao(final EventsStreamBuilder eventsStreamBuilder, final SubscriptionBaseInternalApi subscriptionBaseInternalApi,
final IDBI dbi, final Clock clock, final NotificationQueueService notificationQueueService, final PersistentBus eventBus,
- final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+ final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
this.eventsStreamBuilder = eventsStreamBuilder;
this.subscriptionInternalApi = subscriptionBaseInternalApi;
this.clock = clock;
- this.delegate = new DefaultBlockingStateDao(dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao);
+ this.delegate = new DefaultBlockingStateDao(dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
}
@Override
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java b/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java
index 7e189c0..8369a8a 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/DefaultEntitlementService.java
@@ -142,9 +142,9 @@ public class DefaultEntitlementService implements EntitlementService {
EntitlementNotificationKeyAction.CANCEL.equals(entitlementNotificationKeyAction)) {
blockAddOnsIfRequired(key, (DefaultEntitlement) entitlement, callContext, internalCallContext);
} else if (EntitlementNotificationKeyAction.PAUSE.equals(entitlementNotificationKeyAction)) {
- entitlementInternalApi.pause(key.getBundleId(), key.getEffectiveDate().toLocalDate(), ImmutableList.<PluginProperty>of(), internalCallContext);
+ entitlementInternalApi.pause(key.getBundleId(), internalCallContext.toLocalDate(key.getEffectiveDate(), ((DefaultEntitlement) entitlement).getSubscriptionBase().getStartDate()), ImmutableList.<PluginProperty>of(), internalCallContext);
} else if (EntitlementNotificationKeyAction.RESUME.equals(entitlementNotificationKeyAction)) {
- entitlementInternalApi.resume(key.getBundleId(), key.getEffectiveDate().toLocalDate(), ImmutableList.<PluginProperty>of(), internalCallContext);
+ entitlementInternalApi.resume(key.getBundleId(), internalCallContext.toLocalDate(key.getEffectiveDate(), ((DefaultEntitlement) entitlement).getSubscriptionBase().getStartDate()), ImmutableList.<PluginProperty>of(), internalCallContext);
}
} catch (final EntitlementApiException e) {
log.error("Error processing event for entitlement {}" + entitlement.getId(), e);
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
index e6d701e..b3cccf9 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -399,12 +401,12 @@ public class DefaultEventsStream implements EventsStream {
return DefaultEntitlementApi.ENT_STATE_CANCELLED.equals(input.getStateName());
}
}).orNull();
- entitlementEffectiveEndDate = entitlementCancelEvent != null ? new LocalDate(entitlementCancelEvent.getEffectiveDate(), account.getTimeZone()) : null;
+ entitlementEffectiveEndDate = entitlementCancelEvent != null ? internalTenantContext.toLocalDate(entitlementCancelEvent.getEffectiveDate(),getSubscriptionBase().getStartDate()) : null;
}
private void computeStateForEntitlement() {
// Current state for the ENTITLEMENT_SERVICE_NAME is set to cancelled
- if (entitlementEffectiveEndDate != null && entitlementEffectiveEndDate.compareTo(new LocalDate(utcNow, account.getTimeZone())) <= 0) {
+ if (entitlementEffectiveEndDate != null && entitlementEffectiveEndDate.compareTo(internalTenantContext.toLocalDate(utcNow, getSubscriptionBase().getStartDate())) <= 0) {
entitlementState = EntitlementState.CANCELLED;
} else {
// Gather states across all services and check if one of them is set to 'blockEntitlement'
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
index b090a03..dc6a097 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
@@ -89,8 +89,8 @@ public class EventsStreamBuilder {
this.clock = clock;
this.internalCallContextFactory = internalCallContextFactory;
- this.defaultBlockingStateDao = new DefaultBlockingStateDao(dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao);
- this.blockingStateDao = new OptimizedProxyBlockingStateDao(this, subscriptionInternalApi, dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao);
+ this.defaultBlockingStateDao = new DefaultBlockingStateDao(dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+ this.blockingStateDao = new OptimizedProxyBlockingStateDao(this, subscriptionInternalApi, dbi, clock, notificationQueueService, eventBus, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
}
public EventsStream refresh(final EventsStream eventsStream, final TenantContext tenantContext) throws EntitlementApiException {
@@ -100,7 +100,7 @@ public class EventsStreamBuilder {
public EventsStream buildForBaseSubscription(final UUID bundleId, final TenantContext tenantContext) throws EntitlementApiException {
final SubscriptionBase baseSubscription;
try {
- final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(tenantContext);
+ final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(bundleId, ObjectType.BUNDLE, tenantContext);
baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, internalTenantContext);
} catch (SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
index e2a2bf1..b085b5c 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
@@ -48,7 +48,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -75,7 +75,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -109,7 +109,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -142,7 +142,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -167,7 +167,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -210,7 +210,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -250,7 +250,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -284,7 +284,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
index 74fda0c..e060144 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -54,7 +56,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -117,7 +119,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -150,7 +152,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -242,7 +244,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -281,7 +283,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -357,7 +359,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
// Create entitlement
testListener.pushExpectedEvent(NextEvent.CREATE);
@@ -402,8 +404,9 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account accountSrc = accountApi.createAccount(getAccountData(7), callContext);
- final Account accountDesc = accountApi.createAccount(getAccountData(15), callContext);
+ final Account accountDesc = createAccount(getAccountData(15));
+ // internal context will be configured for accountSrc
+ final Account accountSrc = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -443,7 +446,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -508,15 +511,13 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
assertEquals(bundleEntitlements.get(0).getState(), EntitlementState.ACTIVE);
}
-
-
- @Test(groups = "slow")
+ @Test(groups = "slow")
public void testCreateEntitlementInThePast() throws AccountApiException, EntitlementApiException, SubscriptionBaseApiException {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
final LocalDate clockDate = new LocalDate(2013, 10, 7);
clock.setDay(clockDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -561,7 +562,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Cleaning", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -599,7 +600,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Invalid", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -629,7 +630,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Cleaning", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Bullets", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
index 474eb3e..fd9162d 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
@@ -54,7 +54,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE, NextEvent.BLOCK);
final Entitlement entitlement1 = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, initialDate, ImmutableList.<PluginProperty>of(), callContext);
@@ -97,7 +97,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -165,7 +165,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
clock.addDays(3);
- final Account account2 = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account2 = createAccount(getAccountData(7));
testListener.pushExpectedEvents(NextEvent.TRANSFER, NextEvent.CANCEL, NextEvent.BLOCK);
entitlementApi.transferEntitlements(account.getId(), account2.getId(), externalKey, new LocalDate(clock.getUTCNow(), account.getTimeZone()), ImmutableList.<PluginProperty>of(), callContext);
@@ -203,7 +203,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
// Create entitlement
testListener.pushExpectedEvent(NextEvent.CREATE);
@@ -259,7 +259,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -297,7 +297,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
+ final Account account = createAccount(getAccountData(7));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
index 7c67a0e..5208a5b 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -60,8 +62,8 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
public class TestSubscriptionBundleTimeline extends DefaultSubscriptionBundleTimeline {
- public TestSubscriptionBundleTimeline(final DateTimeZone accountTimeZone, final UUID accountId, final UUID bundleId, final String externalKey, final Iterable<Entitlement> entitlements) {
- super(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ public TestSubscriptionBundleTimeline(final UUID accountId, final UUID bundleId, final String externalKey, final Iterable<Entitlement> entitlements) {
+ super(accountId, bundleId, externalKey, entitlements, internalCallContext);
}
public SubscriptionEvent createEvent(final UUID subscriptionId, final SubscriptionEventType type, final DateTime effectiveDate) {
@@ -84,14 +86,15 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
null,
null,
null,
- null);
+ effectiveDate,
+ internalCallContext);
}
}
@Test(groups = "fast")
public void testReOrderSubscriptionEventsOnInvalidOrder1() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, null, new ArrayList<Entitlement>());
+ final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
final UUID subscriptionId = UUID.randomUUID();
@@ -111,7 +114,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
@Test(groups = "fast")
public void testReOrderSubscriptionEventsOnInvalidOrder2() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, null, new ArrayList<Entitlement>());
+ final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
final UUID subscriptionId = UUID.randomUUID();
@@ -131,7 +134,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
@Test(groups = "fast")
public void testReOrderSubscriptionEventsOnInvalidOrder3() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, null, new ArrayList<Entitlement>());
+ final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
final UUID subscriptionId = UUID.randomUUID();
@@ -151,7 +154,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
@Test(groups = "fast")
public void testReOrderSubscriptionEventsOnInvalidOrderAndDifferentSubscriptionsSameDates1() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, null, new ArrayList<Entitlement>());
+ final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
final UUID subscriptionId = UUID.fromString("60b64e0c-cefd-48c3-8de9-c731a9558165");
@@ -178,7 +181,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
@Test(groups = "fast")
public void testReOrderSubscriptionEventsOnInvalidOrderAndDifferentSubscriptionsSameDates2() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, null, new ArrayList<Entitlement>());
+ final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
final UUID subscriptionId = UUID.fromString("35b3b340-31b2-46ea-b062-e9fc9fab3bc9");
@@ -205,7 +208,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
@Test(groups = "fast")
public void testReOrderSubscriptionEventsOnInvalidOrderAndDifferentSubscriptionsDates() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, null, new ArrayList<Entitlement>());
+ final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
final UUID subscriptionId = UUID.randomUUID();
@@ -243,7 +246,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
@Test(groups = "fast")
public void testReOrderSubscriptionEventsOnCorrectOrder() {
- final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, null, new ArrayList<Entitlement>());
+ final TestSubscriptionBundleTimeline timeline = new TestSubscriptionBundleTimeline(null, null, null, new ArrayList<Entitlement>());
final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
final UUID subscriptionId = UUID.randomUUID();
@@ -293,7 +296,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions);
entitlements.add(entitlement);
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
@@ -364,7 +367,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
@@ -459,7 +462,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
@@ -598,7 +601,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
@@ -722,7 +725,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
@@ -806,7 +809,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 6);
@@ -904,7 +907,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
final Entitlement entitlement2 = createEntitlement(entitlementId2, allTransitions2, blockingStates);
entitlements.add(entitlement2);
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 9);
@@ -1006,7 +1009,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
// Verify the timeline without the blocking state events
final ImmutableList<Entitlement> entitlementsWithoutBlockingStates = ImmutableList.<Entitlement>of(createEntitlement(entitlementId, allTransitions, blockingStates));
- final List<SubscriptionEvent> eventsWithoutBlockingStates = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlementsWithoutBlockingStates).getSubscriptionEvents();
+ final List<SubscriptionEvent> eventsWithoutBlockingStates = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlementsWithoutBlockingStates, internalCallContext).getSubscriptionEvents();
assertEquals(eventsWithoutBlockingStates.size(), 4);
assertEquals(eventsWithoutBlockingStates.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(eventsWithoutBlockingStates.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
@@ -1022,7 +1025,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
// Verify the timeline with the overdue event blocking the entitlement
final ImmutableList<Entitlement> entitlementsWithOverdueEvent = ImmutableList.<Entitlement>of(createEntitlement(entitlementId, allTransitions, blockingStates));
- final List<SubscriptionEvent> eventsWithOverdueEvent = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlementsWithOverdueEvent).getSubscriptionEvents();
+ final List<SubscriptionEvent> eventsWithOverdueEvent = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlementsWithOverdueEvent, internalCallContext).getSubscriptionEvents();
assertEquals(eventsWithOverdueEvent.size(), 5);
assertEquals(eventsWithOverdueEvent.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
assertEquals(eventsWithOverdueEvent.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
@@ -1041,7 +1044,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
entitlements.add(entitlement);
// Verify the timeline with both the overdue event and the entitlement cancel event
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
assertEquals(timeline.getAccountId(), accountId);
assertEquals(timeline.getBundleId(), bundleId);
@@ -1141,7 +1144,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 4);
@@ -1234,7 +1237,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
final Entitlement entitlement = createEntitlement(entitlementId, allTransitions, blockingStates);
entitlements.add(entitlement);
- final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements);
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountId, bundleId, externalKey, entitlements, internalCallContext);
final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
assertEquals(events.size(), 11);
@@ -1325,6 +1328,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
final SubscriptionBase base = Mockito.mock(SubscriptionBase.class);
Mockito.when(base.getAllTransitions()).thenReturn(allTransitions);
Mockito.when(result.getSubscriptionBase()).thenReturn(base);
+ Mockito.when(result.getSubscriptionBase().getStartDate()).thenReturn(new DateTime(DateTimeZone.UTC));
return result;
}
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
index ae889c9..9a22d1d 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -19,15 +21,14 @@ package org.killbill.billing.entitlement.api;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.entitlement.EntitlementTestSuiteNoDB;
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-import org.killbill.billing.account.api.Account;
-import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.entitlement.EntitlementTestSuiteNoDB;
-
import static org.testng.Assert.assertTrue;
public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
@@ -39,12 +40,11 @@ public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
public void beforeMethod() throws Exception {
super.beforeClass();
-
account = Mockito.mock(Account.class);
Mockito.when(accountInternalApi.getAccountByRecordId(Mockito.anyLong(), Mockito.<InternalTenantContext>any())).thenReturn(account);
Mockito.when(accountInternalApi.getImmutableAccountDataByRecordId(Mockito.anyLong(), Mockito.<InternalTenantContext>any())).thenReturn(account);
- dateHelper = new EntitlementDateHelper(accountInternalApi, clock);
- clock.resetDeltaFromReality();;
+ dateHelper = new EntitlementDateHelper(clock);
+ clock.resetDeltaFromReality();
}
@Test(groups = "fast")
@@ -61,7 +61,6 @@ public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
Assert.assertEquals(targetDate, expectedDate);
}
-
@Test(groups = "fast")
public void testWithAccountInUtcMinus8() throws EntitlementApiException {
@@ -71,12 +70,12 @@ public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
final DateTimeZone timeZoneUtcMinus8 = DateTimeZone.forOffsetHours(-8);
Mockito.when(account.getTimeZone()).thenReturn(timeZoneUtcMinus8);
+ internalCallContext.setReferenceDateTimeZone(account.getTimeZone());
// We also use a reference time of 1, 28, 10, 0 -> DateTime in accountTimeZone will be (2013, 8, 7, 1, 28, 10)
final DateTime refererenceDateTime = new DateTime(2013, 1, 1, 1, 28, 10, 0, DateTimeZone.UTC);
final DateTime targetDate = dateHelper.fromLocalDateAndReferenceTime(inputDate, refererenceDateTime, internalCallContext);
-
// Things to verify:
// 1. Verify the resulting DateTime brings us back into the correct LocalDate (in the account timezone)
Assert.assertEquals(new LocalDate(targetDate, timeZoneUtcMinus8), inputDate);
@@ -90,8 +89,6 @@ public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
Assert.assertEquals(targetDate, new DateTime(2013, 8, 8, 1, 28, 10, 0, DateTimeZone.UTC));
}
-
-
@Test(groups = "fast")
public void testWithAccountInUtcPlus5() throws EntitlementApiException {
@@ -100,6 +97,7 @@ public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
final DateTimeZone timeZoneUtcPlus5 = DateTimeZone.forOffsetHours(+5);
Mockito.when(account.getTimeZone()).thenReturn(timeZoneUtcPlus5);
+ internalCallContext.setReferenceDateTimeZone(account.getTimeZone());
// We also use a reference time of 20, 28, 10, 0 -> DateTime in accountTimeZone will be (2013, 8, 7, 20, 28, 10)
final DateTime refererenceDateTime = new DateTime(2013, 1, 1, 20, 28, 10, 0, DateTimeZone.UTC);
@@ -119,36 +117,18 @@ public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
}
@Test(groups = "fast")
- public void testWhereLocalDateInAccountTimeZoneContainsNow() throws EntitlementApiException {
-
- final DateTime initialNow = new DateTime(2013, 8, 22,22, 07, 01, 0, DateTimeZone.UTC);
- clock.setTime(initialNow);
-
- final LocalDate inputDate = new LocalDate(2013, 8, 22);
-
- final DateTimeZone timeZoneUtcMinus8 = DateTimeZone.forOffsetHours(-8);
- Mockito.when(account.getTimeZone()).thenReturn(timeZoneUtcMinus8);
-
- final DateTime referenceDateTimeThatDoesNotMatter = new DateTime();
- final DateTime targetDate = dateHelper.fromLocalDateAndReferenceTime(inputDate, referenceDateTimeThatDoesNotMatter, internalCallContext);
-
- final DateTime now = clock.getUTCNow();
- Assert.assertTrue(initialNow.compareTo(targetDate) <= 0);
- Assert.assertTrue(targetDate.compareTo(now) <= 0);
- }
-
-
- @Test(groups = "fast")
public void testIsBeforeOrEqualsToday() {
clock.setTime(new DateTime(2013, 8, 7, 3, 28, 10, 0, DateTimeZone.UTC));
final DateTimeZone timeZoneUtcMinus8 = DateTimeZone.forOffsetHours(-8);
-
+ Mockito.when(account.getTimeZone()).thenReturn(timeZoneUtcMinus8);
+ internalCallContext.setReferenceDateTimeZone(account.getTimeZone());
final DateTime inputDateEquals = new DateTime(2013, 8, 6, 23, 28, 10, 0, timeZoneUtcMinus8);
// Check that our input date is greater than now
assertTrue(inputDateEquals.compareTo(clock.getUTCNow()) > 0);
// And yet since the LocalDate match the function returns true
- assertTrue(dateHelper.isBeforeOrEqualsToday(inputDateEquals, timeZoneUtcMinus8));
+ final DateTime referenceDateTimeThatDoesNotMatter = new DateTime();
+ assertTrue(dateHelper.isBeforeOrEqualsToday(inputDateEquals, referenceDateTimeThatDoesNotMatter, timeZoneUtcMinus8, internalCallContext));
}
}
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
index 984955c..e8b76b0 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -88,8 +88,7 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
final boolean blockEntitlement = false;
final boolean blockBilling = false;
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ final Account account = createAccount(getAccountData(7));
testListener.pushExpectedEvent(NextEvent.BLOCK);
final BlockingState state1 = new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, overdueStateName, service, blockChange, blockEntitlement, blockBilling, clock.getUTCNow());
@@ -118,7 +117,6 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
Assert.assertEquals(history.get(1).getStateName(), overdueStateName2);
}
-
@Test(groups = "slow")
public void testBlockingAcrossTypes() throws Exception {
@@ -130,8 +128,7 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
final boolean blockEntitlement = true;
final boolean blockBilling = false;
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ final Account account = createAccount(getAccountData(7));
testListener.pushExpectedEvent(NextEvent.BLOCK);
final BlockingState state1 = new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, stateNameBlock, service, blockChange, blockEntitlement, blockBilling, clock.getUTCNow());
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestBlockingDao.java b/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestBlockingDao.java
index f078f2f..a9478c7 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestBlockingDao.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestBlockingDao.java
@@ -40,10 +40,7 @@ public class TestBlockingDao extends EntitlementTestSuiteWithEmbeddedDB {
@BeforeMethod(groups = "slow")
public void setUp() throws Exception {
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
-
- // Override the context with the right account record id
- internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ final Account account = createAccount(getAccountData(7));
}
@Test(groups = "slow", description = "Check BlockingStateDao with a single service")
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java b/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
index 62a2919..19f605f 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
@@ -50,10 +50,7 @@ public class TestDefaultBlockingStateDao extends EntitlementTestSuiteWithEmbedde
@BeforeMethod(groups = "slow")
public void setUp() throws Exception {
- account = accountApi.createAccount(getAccountData(7), callContext);
-
- // Override the context with the right account record id
- internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ account = createAccount(getAccountData(7));
}
@Test(groups = "slow", description = "Verify we don't insert extra add-on events")
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
index b69e58b..c58a695 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -24,7 +26,10 @@ import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
+import org.killbill.billing.ObjectType;
+import org.killbill.billing.entitlement.AccountEventsStreams;
import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.util.cache.Cachable.CacheType;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -71,10 +76,7 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
sqlDao = dbi.onDemand(BlockingStateSqlDao.class);
clock.setDay(initialDate);
- account = accountApi.createAccount(getAccountData(7), callContext);
-
- // Override the context with the right account record id
- internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ account = createAccount(getAccountData(7));
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE);
@@ -450,8 +452,10 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
}
private Collection<BlockingState> computeFutureBlockingStatesForAssociatedAddonsViaAccount(final DefaultEntitlement baseEntitlement) throws EntitlementApiException {
- final InternalTenantContext context = internalCallContextFactory.createInternalTenantContext(baseEntitlement.getAccountId(), callContext);
- final EventsStream eventsStream = Iterables.<EventsStream>find(Iterables.<EventsStream>concat(eventsStreamBuilder.buildForAccount(context).getEventsStreams().values()),
+ setContextAccountRecordId();
+ final AccountEventsStreams accountEventsStreams = eventsStreamBuilder.buildForAccount(internalCallContext);
+
+ final EventsStream eventsStream = Iterables.<EventsStream>find(Iterables.<EventsStream>concat(accountEventsStreams.getEventsStreams().values()),
new Predicate<EventsStream>() {
@Override
public boolean apply(final EventsStream input) {
@@ -467,8 +471,10 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
}
private Collection<BlockingState> computeBlockingStatesForAssociatedAddonsViaAccount(final DefaultEntitlement baseEntitlement, final DateTime effectiveDate) throws EntitlementApiException {
- final InternalTenantContext context = internalCallContextFactory.createInternalTenantContext(baseEntitlement.getAccountId(), callContext);
- final EventsStream eventsStream = Iterables.<EventsStream>find(Iterables.<EventsStream>concat(eventsStreamBuilder.buildForAccount(context).getEventsStreams().values()),
+ setContextAccountRecordId();
+ final AccountEventsStreams accountEventsStreams = eventsStreamBuilder.buildForAccount(internalCallContext);
+
+ final EventsStream eventsStream = Iterables.<EventsStream>find(Iterables.<EventsStream>concat(accountEventsStreams.getEventsStreams().values()),
new Predicate<EventsStream>() {
@Override
public boolean apply(final EventsStream input) {
@@ -487,4 +493,8 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
}
}));
}
+
+ private void setContextAccountRecordId() {
+ internalCallContext.setAccountRecordId(nonEntityDao.retrieveRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, controlCacheDispatcher.getCacheController(CacheType.RECORD_ID)));
+ }
}
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java b/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
index 1fe5700..82785c0 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
@@ -32,6 +32,9 @@ import org.apache.shiro.util.ThreadContext;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.killbill.billing.GuicyKillbillTestSuiteWithEmbeddedDB;
+import org.killbill.billing.ObjectType;
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountData;
import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.account.api.AccountUserApi;
@@ -57,7 +60,9 @@ import org.killbill.billing.subscription.api.SubscriptionBaseService;
import org.killbill.billing.subscription.engine.core.DefaultSubscriptionBaseService;
import org.killbill.billing.tag.TagInternalApi;
import org.killbill.billing.util.api.AuditUserApi;
+import org.killbill.billing.util.cache.Cachable.CacheType;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.tag.dao.TagDao;
import org.killbill.bus.api.PersistentBus;
import org.killbill.clock.ClockMock;
@@ -118,6 +123,8 @@ public class EntitlementTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWi
protected InternalCallContextFactory internalCallContextFactory;
@Inject
protected SecurityApi securityApi;
+ @Inject
+ protected NonEntityDao nonEntityDao;
protected Catalog catalog;
@@ -279,6 +286,16 @@ public class EntitlementTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWi
.build();
}
+ protected Account createAccount(final AccountData accountData) throws AccountApiException {
+ final Account account = accountApi.createAccount(accountData, callContext);
+
+ final Long accountRecordId = nonEntityDao.retrieveRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, controlCacheDispatcher.getCacheController(CacheType.RECORD_ID));
+ internalCallContext.setAccountRecordId(accountRecordId);
+ internalCallContext.setReferenceDateTimeZone(account.getTimeZone());
+
+ return account;
+ }
+
protected void assertListenerStatus() {
testListener.assertListenerStatus();
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/migration/DefaultInvoiceMigrationApi.java b/invoice/src/main/java/org/killbill/billing/invoice/api/migration/DefaultInvoiceMigrationApi.java
index b537bff..765bebf 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/migration/DefaultInvoiceMigrationApi.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/migration/DefaultInvoiceMigrationApi.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -22,17 +24,11 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
-import org.killbill.billing.account.api.ImmutableAccountData;
-import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications;
-import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications.SubscriptionNotification;
-import org.killbill.billing.util.timezone.DefaultAccountDateAndTimeZoneContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.killbill.billing.account.api.AccountApiException;
+import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.MigrationPlan;
-import org.killbill.clock.Clock;
+import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications;
+import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications.SubscriptionNotification;
import org.killbill.billing.invoice.api.InvoiceItemType;
import org.killbill.billing.invoice.api.InvoiceMigrationApi;
import org.killbill.billing.invoice.dao.DefaultInvoiceDao;
@@ -40,7 +36,10 @@ import org.killbill.billing.invoice.dao.InvoiceItemModelDao;
import org.killbill.billing.invoice.dao.InvoiceModelDao;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.util.timezone.DefaultAccountDateAndTimeZoneContext;
+import org.killbill.clock.Clock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -50,17 +49,14 @@ public class DefaultInvoiceMigrationApi implements InvoiceMigrationApi {
private static final Logger log = LoggerFactory.getLogger(DefaultInvoiceMigrationApi.class);
- private final AccountInternalApi accountUserApi;
private final DefaultInvoiceDao dao;
private final Clock clock;
private final InternalCallContextFactory internalCallContextFactory;
@Inject
- public DefaultInvoiceMigrationApi(final AccountInternalApi accountUserApi,
- final DefaultInvoiceDao dao,
+ public DefaultInvoiceMigrationApi(final DefaultInvoiceDao dao,
final Clock clock,
final InternalCallContextFactory internalCallContextFactory) {
- this.accountUserApi = accountUserApi;
this.dao = dao;
this.clock = clock;
this.internalCallContextFactory = internalCallContextFactory;
@@ -68,13 +64,7 @@ public class DefaultInvoiceMigrationApi implements InvoiceMigrationApi {
@Override
public UUID createMigrationInvoice(final UUID accountId, final LocalDate targetDate, final BigDecimal balance, final Currency currency, final CallContext context) {
- ImmutableAccountData account;
- try {
- account = accountUserApi.getImmutableAccountDataById(accountId, internalCallContextFactory.createInternalTenantContext(accountId, context));
- } catch (AccountApiException e) {
- log.warn("Unable to find account for id {}", accountId);
- return null;
- }
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(accountId, context);
final InvoiceModelDao migrationInvoice = new InvoiceModelDao(accountId, clock.getUTCToday(), targetDate, currency, true);
final InvoiceItemModelDao migrationInvoiceItem = new InvoiceItemModelDao(context.getCreatedDate(), InvoiceItemType.FIXED, migrationInvoice.getId(), accountId, null, null,
@@ -82,9 +72,9 @@ public class DefaultInvoiceMigrationApi implements InvoiceMigrationApi {
targetDate, null, balance, null, currency, null);
final DateTime wrongEffectiveDateButDoesNotMatter = null;
- final DefaultAccountDateAndTimeZoneContext dateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(wrongEffectiveDateButDoesNotMatter, account.getTimeZone());
+ final DefaultAccountDateAndTimeZoneContext dateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(wrongEffectiveDateButDoesNotMatter, internalCallContext);
dao.createInvoice(migrationInvoice, ImmutableList.<InvoiceItemModelDao>of(migrationInvoiceItem),
- true, new FutureAccountNotifications(dateAndTimeZoneContext, ImmutableMap.<UUID, List<SubscriptionNotification>>of()), internalCallContextFactory.createInternalCallContext(accountId, context));
+ true, new FutureAccountNotifications(dateAndTimeZoneContext, ImmutableMap.<UUID, List<SubscriptionNotification>>of()), internalCallContext);
return migrationInvoice.getId();
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
index 9e1cd9d..7e7406c 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -127,7 +127,7 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
@Override
public Invoice getInvoiceByPayment(final UUID paymentId, final TenantContext context) throws InvoiceApiException {
- final InternalTenantContext tenantContext = internalCallContextFactory.createInternalTenantContext(context);
+ final InternalTenantContext tenantContext = internalCallContextFactory.createInternalTenantContext(paymentId, ObjectType.PAYMENT, context);
final UUID invoiceId = dao.getInvoiceIdByPaymentId(paymentId, tenantContext);
if (invoiceId == null) {
throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND, paymentId);
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
index 5166e98..1aa7fd8 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -114,7 +114,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
final InvoiceDaoHelper invoiceDaoHelper,
final CBADao cbaDao,
final InternalCallContextFactory internalCallContextFactory) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), InvoiceSqlDao.class);
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), InvoiceSqlDao.class);
this.nextBillingDatePoster = nextBillingDatePoster;
this.eventBus = eventBus;
this.invoiceConfig = invoiceConfig;
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
index f6726f6..27e6a43 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
@@ -33,6 +33,8 @@ import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.api.BillingMode;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.Duration;
+import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.invoice.api.InvoiceItem;
@@ -84,7 +86,7 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
// Generate list of proposed invoice items based on billing events from junction-- proposed items are ALL items since beginning of time
final List<InvoiceItem> proposedItems = new ArrayList<InvoiceItem>();
- processRecurringBillingEvents(invoiceId, account.getId(), eventSet, targetDate, targetCurrency, proposedItems, perSubscriptionFutureNotificationDate);
+ processRecurringBillingEvents(invoiceId, account.getId(), eventSet, targetDate, targetCurrency, proposedItems, perSubscriptionFutureNotificationDate, existingInvoices);
processFixedBillingEvents(invoiceId, account.getId(), eventSet, targetDate, targetCurrency, proposedItems);
accountItemTree.mergeWithProposedItems(proposedItems);
@@ -92,8 +94,9 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
}
private void processRecurringBillingEvents(final UUID invoiceId, final UUID accountId, final BillingEventSet events,
- final LocalDate targetDate, final Currency currency, final List<InvoiceItem> proposedItems,
- final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate) throws InvoiceApiException {
+ final LocalDate targetDate, final Currency currency, final List<InvoiceItem> proposedItems,
+ final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
+ @Nullable final List<Invoice> existingInvoices) throws InvoiceApiException {
if (events.size() == 0) {
return;
@@ -160,7 +163,6 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
}
}
-
// Turn a set of events into a list of invoice items. Note that the dates on the invoice items will be rounded (granularity of a day)
private List<InvoiceItem> processRecurringEvent(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent, @Nullable final BillingEvent nextEvent,
final LocalDate targetDate, final Currency currency,
@@ -169,6 +171,11 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
final AccountDateAndTimeZoneContext dateAndTimeZoneContext) throws InvoiceApiException {
final List<InvoiceItem> items = new ArrayList<InvoiceItem>();
+ // For FIXEDTERM phases we need to stop when the specified duration has been reached
+ final LocalDate maxEndDate = thisEvent.getPlanPhase().getPhaseType() == PhaseType.FIXEDTERM ?
+ computeMaxEndDateForFixedTermPlanPhase(thisEvent, dateAndTimeZoneContext) :
+ null;
+
// Handle recurring items
final BillingPeriod billingPeriod = thisEvent.getBillingPeriod();
if (billingPeriod != BillingPeriod.NO_BILLING_PERIOD) {
@@ -187,8 +194,12 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
}
for (final RecurringInvoiceItemData itemDatum : itemDataWithNextBillingCycleDate.getItemData()) {
- final BigDecimal rate = thisEvent.getRecurringPrice();
+ // Stop if there a maxEndDate and we have reached it
+ if (maxEndDate != null && maxEndDate.compareTo(itemDatum.getEndDate()) < 0) {
+ break;
+ }
+ final BigDecimal rate = thisEvent.getRecurringPrice();
if (rate != null) {
final BigDecimal amount = KillBillMoney.of(itemDatum.getNumberOfCycles().multiply(rate), currency);
final RecurringInvoiceItem recurringItem = new RecurringInvoiceItem(invoiceId,
@@ -197,7 +208,8 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
thisEvent.getSubscription().getId(),
thisEvent.getPlan().getName(),
thisEvent.getPlanPhase().getName(),
- itemDatum.getStartDate(), itemDatum.getEndDate(),
+ itemDatum.getStartDate(),
+ itemDatum.getEndDate(),
amount, rate, currency);
items.add(recurringItem);
}
@@ -216,6 +228,15 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
return items;
}
+ //
+ // Go through invoices in reverse order and for each invoice extract a possible item for that subscription and the phaseName associated with this billing event
+ // Computes the startDate for that first one seen in that uninterrupted sequence and then add the FIXEDTERM duration to compute the max endDate
+ //
+ private LocalDate computeMaxEndDateForFixedTermPlanPhase(final BillingEvent thisEvent, final AccountDateAndTimeZoneContext dateAndTimeZoneContext) {
+ final LocalDate eventEffectiveDate = dateAndTimeZoneContext.computeLocalDateFromFixedAccountOffset(thisEvent.getEffectiveDate());
+ return addDurationToLocalDate(eventEffectiveDate, thisEvent.getPlanPhase().getDuration());
+ }
+
private void updatePerSubscriptionNextNotificationDate(final UUID subscriptionId, final LocalDate nextBillingCycleDate, final List<InvoiceItem> newProposedItems, final BillingMode billingMode, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates) {
LocalDate nextNotificationDate = null;
@@ -359,4 +380,26 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator
}
}
}
+
+ // That code should belong to Duration/DefaultDuration but requires a change api (not possible for 0.16.3, but will be moreved in 0.17.0)
+ private LocalDate addDurationToLocalDate(@Nullable final LocalDate inputDate, final Duration duration) {
+
+ if (inputDate == null) {
+ return inputDate;
+ }
+
+ switch (duration.getUnit()) {
+ case DAYS:
+ return inputDate.plusDays(duration.getNumber());
+ case MONTHS:
+ return inputDate.plusMonths(duration.getNumber());
+ case YEARS:
+ return inputDate.plusYears(duration.getNumber());
+ case UNLIMITED:
+ return inputDate.plusYears(100);
+ default:
+ throw new IllegalStateException("Unknwon duration " + duration.getUnit());
+ }
+ }
+
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceDateUtils.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceDateUtils.java
index f4f4a38..879ef43 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceDateUtils.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceDateUtils.java
@@ -147,24 +147,6 @@ public class InvoiceDateUtils {
return calculateProrationBetweenDates(previousBillThroughDate, endDate, previousBillThroughDate, nextBillThroughDate);
}
- /*
- public static LocalDate calculateBillingCycleDateOnOrAfter(final LocalDate date, final DateTimeZone accountTimeZone,
- final int billingCycleDayLocal) {
- final DateTime tmp = date.toDateTimeAtStartOfDay(accountTimeZone);
- final DateTime proposedDateTime = calculateBillingCycleDateOnOrAfter(tmp, billingCycleDayLocal);
-
- return new LocalDate(proposedDateTime, accountTimeZone);
- }
-
- public static LocalDate calculateBillingCycleDateAfter(final LocalDate date, final DateTimeZone accountTimeZone,
- final int billingCycleDayLocal) {
- final DateTime tmp = date.toDateTimeAtStartOfDay(accountTimeZone);
- final DateTime proposedDateTime = calculateBillingCycleDateAfter(tmp, billingCycleDayLocal);
-
- return new LocalDate(proposedDateTime, accountTimeZone);
- }
- */
-
public static LocalDate calculateBillingCycleDateOnOrAfter(final LocalDate date, final int billingCycleDayLocal) {
final int lastDayOfMonth = date.dayOfMonth().getMaximumValue();
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index 5784606..fd4b071 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -23,20 +25,18 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
import org.killbill.billing.account.api.Account;
-import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.invoice.InvoiceTestSuiteWithEmbeddedDB;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.invoice.dao.InvoiceModelDao;
import org.killbill.billing.invoice.dao.InvoiceModelDaoHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbeddedDB {
@@ -71,8 +71,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbedded
Assert.assertNotNull(migrationInvoiceId);
//Double check it was created and values are correct
- final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(accountId, callContext);
- final InvoiceModelDao invoice = invoiceDao.getById(migrationInvoiceId, internalTenantContext);
+ final InvoiceModelDao invoice = invoiceDao.getById(migrationInvoiceId, internalCallContext);
Assert.assertNotNull(invoice);
Assert.assertEquals(invoice.getAccountId(), accountId);
@@ -101,26 +100,15 @@ public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbedded
Assert.assertEquals(unpaid.size(), 2);
}
-
// ACCOUNT balance should reflect total of migration and non-migration invoices
@Test(groups = "slow")
public void testBalance() throws InvoiceApiException {
- final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(accountId, callContext);
- final InvoiceModelDao migrationInvoice = invoiceDao.getById(migrationInvoiceId, internalTenantContext);
- final InvoiceModelDao regularInvoice = invoiceDao.getById(regularInvoiceId, internalTenantContext);
+ final InvoiceModelDao migrationInvoice = invoiceDao.getById(migrationInvoiceId, internalCallContext);
+ final InvoiceModelDao regularInvoice = invoiceDao.getById(regularInvoiceId, internalCallContext);
final BigDecimal balanceOfAllInvoices = InvoiceModelDaoHelper.getBalance(migrationInvoice).add(InvoiceModelDaoHelper.getBalance(regularInvoice));
final BigDecimal accountBalance = invoiceUserApi.getAccountBalance(accountId, callContext);
log.info("ACCOUNT balance: " + accountBalance + " should equal the Balance Of All Invoices: " + balanceOfAllInvoices);
Assert.assertEquals(accountBalance.compareTo(balanceOfAllInvoices), 0);
}
-
- private boolean checkContains(final List<Invoice> invoices, final UUID invoiceId) {
- for (final Invoice invoice : invoices) {
- if (invoice.getId().equals(invoiceId)) {
- return true;
- }
- }
- return false;
- }
}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
index 6a16b88..dc87e42 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
@@ -1109,7 +1109,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 1, BillingMode.IN_ADVANCE,
"testEvent1", 1L, SubscriptionBaseTransitionType.CREATE);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
events.add(event1);
final InvoiceWithMetadata invoiceWithMetadata1 = generator.generateInvoice(account, events, invoiceList, targetDate, Currency.USD, context);
@@ -1161,7 +1161,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
final BillingEvent event = invoiceUtil.createMockBillingEvent(null, subscription, effectiveDate, plan, phase,
fixedPrice.getPrice(currency), null, currency, BillingPeriod.MONTHLY, 15, BillingMode.IN_ADVANCE,
"testEvent", 1L, SubscriptionBaseTransitionType.CREATE);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
events.add(event);
final LocalDate targetDate = invoiceUtil.buildDate(2011, 1, 15);
@@ -1203,7 +1203,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
final BillingEvent event1 = invoiceUtil.createMockBillingEvent(null, subscription, effectiveDate1, plan, phase1, fixedPrice.getPrice(currency),
null, currency, BillingPeriod.MONTHLY, 1, BillingMode.IN_ADVANCE,
"testEvent1", 1L, SubscriptionBaseTransitionType.CREATE);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
events.add(event1);
final UUID accountId = account.getId();
@@ -1246,7 +1246,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
@Test(groups = "slow")
public void testInvoiceForEmptyEventSet() throws InvoiceApiException {
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final InvoiceWithMetadata invoiceWithMetadata = generator.generateInvoice(account, events, null, new LocalDate(), Currency.USD, context);
final Invoice invoice = invoiceWithMetadata.getInvoice();
assertNull(invoice);
@@ -1273,7 +1273,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
fixedPrice.getPrice(currency), null, currency,
BillingPeriod.MONTHLY, 1, BillingMode.IN_ADVANCE,
"testEvent1", 1L, SubscriptionBaseTransitionType.CREATE);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
events.add(event1);
final DateTime effectiveDate2 = effectiveDate1.plusDays(30);
@@ -1340,7 +1340,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
invoices.add(new DefaultInvoice(savedInvoice));
// NOW COMPUTE A DIFFERENT ITEM TO TRIGGER REPAIR
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final SubscriptionBase subscription = getZombieSubscription(subscriptionId);
final Plan plan = Mockito.mock(Plan.class);
@@ -1381,7 +1381,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
final PlanPhase phase2 = Mockito.mock(PlanPhase.class);
Mockito.when(phase2.getName()).thenReturn("plan-phase2");
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final List<Invoice> invoices = new ArrayList<Invoice>();
final BillingEvent event1 = invoiceUtil.createMockBillingEvent(null, subscription, targetDate1, plan, phase1, null,
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
index 4b8be24..3d20246 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
@@ -157,14 +157,14 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast")
public void testWithEmptyEventSet() throws InvoiceApiException {
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final InvoiceWithMetadata invoiceWithMetadata = generator.generateInvoice(account, events, null, clock.getUTCToday(), Currency.USD, internalCallContext);
assertNull(invoiceWithMetadata.getInvoice());
}
@Test(groups = "fast")
public void testWithSingleMonthlyEvent() throws InvoiceApiException, CatalogApiException {
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final SubscriptionBase sub = createSubscription();
final LocalDate startDate = invoiceUtil.buildDate(2011, 9, 1);
@@ -208,7 +208,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final int bcdLocal = 16;
final LocalDate startDate = invoiceUtil.buildDate(2012, 7, bcdLocal);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final BillingEvent event = createBillingEvent(sub.getId(), sub.getBundleId(), startDate, plan, phase, bcdLocal);
events.add(event);
@@ -233,7 +233,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final int bcdLocal = 16;
final LocalDate startDate = invoiceUtil.buildDate(2012, 7, 16);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
events.add(createBillingEvent(sub.getId(), sub.getBundleId(), startDate, plan, phaseEvergreen, bcdLocal));
// Set a target date of today (start date)
@@ -248,7 +248,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast")
public void testWithSingleMonthlyEventWithLeadingProRation() throws InvoiceApiException, CatalogApiException {
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final SubscriptionBase sub = createSubscription();
final LocalDate startDate = invoiceUtil.buildDate(2011, 9, 1);
@@ -273,7 +273,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast")
public void testTwoMonthlySubscriptionsWithAlignedBillingDates() throws InvoiceApiException, CatalogApiException {
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final Plan plan1 = new MockPlan();
final BigDecimal rate1 = FIVE;
@@ -301,7 +301,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast")
public void testOnePlan_TwoMonthlyPhases_ChangeImmediate() throws InvoiceApiException, CatalogApiException {
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final Plan plan1 = new MockPlan();
final BigDecimal rate1 = FIVE;
@@ -338,7 +338,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast")
public void testOnePlan_ThreeMonthlyPhases_ChangeEOT() throws InvoiceApiException, CatalogApiException {
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final Plan plan1 = new MockPlan();
final BigDecimal rate1 = FIVE;
@@ -368,7 +368,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast")
public void testSingleEventWithExistingInvoice() throws InvoiceApiException, CatalogApiException {
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final SubscriptionBase sub = createSubscription();
final LocalDate startDate = invoiceUtil.buildDate(2011, 9, 1);
@@ -446,7 +446,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
BigDecimal expectedAmount;
final List<Invoice> invoices = new ArrayList<Invoice>();
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
// on 1/5/2011, create SubscriptionBase 1 (trial)
events.add(createBillingEvent(subscriptionId1, bundleId, plan1StartDate, plan1, plan1Phase1, 5));
@@ -556,7 +556,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
public void testZeroDollarEvents() throws InvoiceApiException, CatalogApiException {
final Plan plan = new MockPlan();
final PlanPhase planPhase = createMockMonthlyPlanPhase(ZERO);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final LocalDate targetDate = invoiceUtil.buildDate(2011, 1, 1);
events.add(createBillingEvent(UUID.randomUUID(), UUID.randomUUID(), targetDate, plan, planPhase, 1));
@@ -569,7 +569,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
public void testEndDateIsCorrect() throws InvoiceApiException, CatalogApiException {
final Plan plan = new MockPlan();
final PlanPhase planPhase = createMockMonthlyPlanPhase(ONE);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final LocalDate startDate = clock.getUTCToday().minusDays(1);
final LocalDate targetDate = startDate.plusDays(1);
@@ -597,7 +597,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final DateTime changeDate = new DateTime("2012-04-1");
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final BillingEvent event1 = invoiceUtil.createMockBillingEvent(null, subscription, new DateTime("2012-01-1"),
plan, phase1,
@@ -636,7 +636,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final BigDecimal fixedCost = TEN;
final PlanPhase phase1 = createMockMonthlyPlanPhase(monthlyRate, fixedCost, PhaseType.TRIAL);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final UUID subscriptionId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
@@ -674,7 +674,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final PlanPhase phase1 = createMockMonthlyPlanPhase(null, fixedCost1, PhaseType.TRIAL);
final PlanPhase phase2 = createMockMonthlyPlanPhase(null, fixedCost2, PhaseType.EVERGREEN);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final UUID subscriptionId = UUID.randomUUID();
final UUID accountId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
@@ -706,7 +706,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast")
public void testInvoiceGenerationFailureScenario() throws InvoiceApiException, CatalogApiException {
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final UUID subscriptionId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
final int BILL_CYCLE_DAY = 15;
@@ -766,7 +766,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast", expectedExceptions = {InvoiceApiException.class})
public void testTargetDateRestrictionFailure() throws InvoiceApiException, CatalogApiException {
final LocalDate targetDate = clock.getUTCToday().plusMonths(60);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final Plan plan1 = new MockPlan();
final PlanPhase phase1 = createMockMonthlyPlanPhase(null, ZERO, PhaseType.TRIAL);
events.add(createBillingEvent(UUID.randomUUID(), UUID.randomUUID(), clock.getUTCToday(), plan1, phase1, 1));
@@ -840,7 +840,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final MockInternationalPrice price20 = new MockInternationalPrice(new DefaultPrice(TWENTY, Currency.USD));
final PlanPhase basePlanEvergreen = new MockPlanPhase(price10, null, BillingPeriod.MONTHLY, PhaseType.EVERGREEN);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
events.add(createBillingEvent(baseSubscription.getId(), baseSubscription.getBundleId(), april25, basePlan, basePlanEvergreen, 25));
// generate invoice
@@ -876,7 +876,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
// perform a repair (change base plan; remove one add-on)
// event stream should include just two plans
- final MockBillingEventSet newEvents = new MockBillingEventSet();
+ final MockBillingEventSet newEvents = new MockBillingEventSet(internalCallContext);
final Plan basePlan2 = new MockPlan("base plan 2");
final MockInternationalPrice price13 = new MockInternationalPrice(new DefaultPrice(THIRTEEN, Currency.USD));
final PlanPhase basePlan2Phase = new MockPlanPhase(price13, null, BillingPeriod.MONTHLY, PhaseType.EVERGREEN);
@@ -905,7 +905,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final MockInternationalPrice price10 = new MockInternationalPrice(new DefaultPrice(TEN, Currency.USD));
final PlanPhase originalPlanEvergreen = new MockPlanPhase(price10, null, BillingPeriod.MONTHLY, PhaseType.EVERGREEN);
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
events.add(createBillingEvent(originalSubscription.getId(), originalSubscription.getBundleId(), april25, originalPlan, originalPlanEvergreen, 25));
final InvoiceWithMetadata invoiceWithMetadata1 = generator.generateInvoice(account, events, null, april25, Currency.USD, internalCallContext);
@@ -983,7 +983,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
//
// Note : this is the interesting part of the test; it does not provide the blocking billing events, which force invoice
// to un repair what was previously repaired.
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final BillingEvent event = invoiceUtil.createMockBillingEvent(null, subscription, new DateTime("2013-06-15", DateTimeZone.UTC),
plan, phase,
null, recurringPrice.getPrice(currency), currency,
@@ -1064,7 +1064,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast")
public void testAutoInvoiceOffAccount() throws Exception {
- final MockBillingEventSet events = new MockBillingEventSet();
+ final MockBillingEventSet events = new MockBillingEventSet(internalCallContext);
events.setAccountInvoiceOff(true);
final SubscriptionBase sub = createSubscription();
@@ -1087,7 +1087,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
public void testAutoInvoiceOffWithCredits() throws CatalogApiException, InvoiceApiException {
final Currency currency = Currency.USD;
final List<Invoice> invoices = new ArrayList<Invoice>();
- final MockBillingEventSet eventSet = new MockBillingEventSet();
+ final MockBillingEventSet eventSet = new MockBillingEventSet(internalCallContext);
final UUID accountId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestFixedAndRecurringInvoiceItemGenerator.java b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestFixedAndRecurringInvoiceItemGenerator.java
index fc2d83a..706d61b 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestFixedAndRecurringInvoiceItemGenerator.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestFixedAndRecurringInvoiceItemGenerator.java
@@ -23,7 +23,6 @@ import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.catalog.DefaultPrice;
@@ -69,7 +68,7 @@ public class TestFixedAndRecurringInvoiceItemGenerator extends InvoiceTestSuiteN
try {
account = invoiceUtil.createAccount(callContext);
subscription = invoiceUtil.createSubscription();
- dateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(new DateTime("2016-01-08T03:01:01.000Z"), DateTimeZone.UTC);
+ dateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(new DateTime("2016-01-08T03:01:01.000Z"), internalCallContext);
} catch (final Exception e) {
Assert.fail(e.getMessage());
}
@@ -170,7 +169,7 @@ public class TestFixedAndRecurringInvoiceItemGenerator extends InvoiceTestSuiteN
final LocalDate targetDate = new LocalDate("2016-01-08");
final UUID invoiceId = UUID.randomUUID();
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final BigDecimal fixedPriceAmount = BigDecimal.TEN;
final MockInternationalPrice fixedPrice = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount, Currency.USD));
@@ -203,7 +202,7 @@ public class TestFixedAndRecurringInvoiceItemGenerator extends InvoiceTestSuiteN
final LocalDate targetDate = new LocalDate("2016-01-08");
final UUID invoiceId = UUID.randomUUID();
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final BigDecimal fixedPriceAmount = BigDecimal.TEN;
final MockInternationalPrice fixedPrice = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount, Currency.USD));
@@ -239,7 +238,7 @@ public class TestFixedAndRecurringInvoiceItemGenerator extends InvoiceTestSuiteN
final LocalDate targetDate = new LocalDate("2016-01-08");
final UUID invoiceId = UUID.randomUUID();
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final BigDecimal fixedPriceAmount1 = BigDecimal.TEN;
final MockInternationalPrice fixedPrice1 = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount1, Currency.USD));
@@ -287,4 +286,4 @@ public class TestFixedAndRecurringInvoiceItemGenerator extends InvoiceTestSuiteN
assertEquals(proposedItems.get(0).getAmount(), fixedPriceAmount3);
}
-}
\ No newline at end of file
+}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModuleNoDB.java b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModuleNoDB.java
index a2f5751..cf36e03 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModuleNoDB.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModuleNoDB.java
@@ -35,6 +35,7 @@ import org.killbill.billing.currency.api.Rate;
import org.killbill.billing.invoice.dao.InvoiceDao;
import org.killbill.billing.invoice.dao.MockInvoiceDao;
import org.killbill.billing.mock.api.MockAccountUserApi;
+import org.killbill.billing.mock.glue.MockAccountModule;
import org.killbill.billing.mock.glue.MockNonEntityDaoModule;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.mockito.Mockito;
@@ -55,8 +56,7 @@ public class TestInvoiceModuleNoDB extends TestInvoiceModule {
install(new GuicyKillbillTestNoDBModule(configSource));
install(new MockNonEntityDaoModule(configSource));
- bind(AccountInternalApi.class).toInstance(Mockito.mock(AccountInternalApi.class));
- bind(AccountUserApi.class).to(MockAccountUserApi.class);
+ install(new MockAccountModule(configSource));
installCurrencyConversionApi();
}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/MockBillingEventSet.java b/invoice/src/test/java/org/killbill/billing/invoice/MockBillingEventSet.java
index 356cb3d..566e80b 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/MockBillingEventSet.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/MockBillingEventSet.java
@@ -24,9 +24,7 @@ import java.util.Map;
import java.util.TreeSet;
import java.util.UUID;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.joda.time.LocalDate;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingMode;
import org.killbill.billing.catalog.api.Usage;
import org.killbill.billing.junction.BillingEvent;
@@ -38,12 +36,15 @@ public class MockBillingEventSet extends TreeSet<BillingEvent> implements Billin
private static final long serialVersionUID = 1L;
+ private final InternalTenantContext internalTenantContext;
+
private boolean isAccountInvoiceOff;
private List<UUID> subscriptionIdsWithAutoInvoiceOff;
private AccountDateAndTimeZoneContext accountDateAndTimeZoneContext;
- public MockBillingEventSet() {
+ public MockBillingEventSet(final InternalTenantContext internalTenantContext) {
super();
+ this.internalTenantContext = internalTenantContext;
this.isAccountInvoiceOff = false;
this.subscriptionIdsWithAutoInvoiceOff = new ArrayList<UUID>();
}
@@ -51,7 +52,7 @@ public class MockBillingEventSet extends TreeSet<BillingEvent> implements Billin
@Override
public boolean add(final BillingEvent e) {
if (accountDateAndTimeZoneContext == null) {
- this.accountDateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(e.getEffectiveDate(), DateTimeZone.UTC);
+ this.accountDateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(e.getEffectiveDate(), internalTenantContext);
}
return super.add(e);
}
@@ -59,7 +60,7 @@ public class MockBillingEventSet extends TreeSet<BillingEvent> implements Billin
@Override
public boolean addAll(final Collection<? extends BillingEvent> all) {
if (accountDateAndTimeZoneContext == null) {
- this.accountDateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(all.iterator().next().getEffectiveDate(), DateTimeZone.UTC);
+ this.accountDateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(all.iterator().next().getEffectiveDate(), internalTenantContext);
}
return super.addAll(all);
}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/proRations/InvoiceTestUtils.java b/invoice/src/test/java/org/killbill/billing/invoice/proRations/InvoiceTestUtils.java
index 0f90be1..9f9a536 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/proRations/InvoiceTestUtils.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/proRations/InvoiceTestUtils.java
@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
-import org.joda.time.DateTimeZone;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.callcontext.InternalCallContext;
@@ -106,7 +105,7 @@ public class InvoiceTestUtils {
}
Mockito.when(invoice.getInvoiceItems()).thenReturn(invoiceItems);
- final DefaultAccountDateAndTimeZoneContext dateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(clock.getUTCNow(), DateTimeZone.UTC);
+ final DefaultAccountDateAndTimeZoneContext dateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(clock.getUTCNow(), internalCallContext);
invoiceDao.createInvoice(new InvoiceModelDao(invoice), invoiceModelItems, true, new FutureAccountNotifications(dateAndTimeZoneContext, ImmutableMap.<UUID, List<SubscriptionNotification>>of()), internalCallContext);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
index 2bdde60..0695857 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
@@ -72,7 +72,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
public void testDryRunInvoice() throws InvoiceApiException, AccountApiException, CatalogApiException {
final UUID accountId = account.getId();
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
final PlanPhase planPhase = MockPlanPhase.create1USDMonthlyEvergreen();
final DateTime effectiveDate = clock.getUTCNow().minusDays(1);
@@ -114,7 +114,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
@Test(groups = "slow")
public void testWithOverdueEvents() throws Exception {
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
// Initial trial
final MockPlan bicycleTrialEvergreen1USD = MockPlan.createBicycleTrialEvergreen1USD();
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
index 3cc1c21..215d650 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -29,6 +29,7 @@ import javax.inject.Inject;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
+import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountData;
@@ -36,6 +37,7 @@ import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.account.api.AccountUserApi;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.callcontext.MutableInternalCallContext;
import org.killbill.billing.catalog.MockPlan;
import org.killbill.billing.catalog.MockPlanPhase;
import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -76,10 +78,13 @@ import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.config.InvoiceConfig;
import org.killbill.billing.util.currency.KillBillMoney;
+import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.timezone.DefaultAccountDateAndTimeZoneContext;
import org.killbill.clock.Clock;
import org.killbill.commons.locker.GlobalLocker;
@@ -155,7 +160,9 @@ public class TestInvoiceHelper {
private final InvoiceDao invoiceDao;
private final GlobalLocker locker;
private final Clock clock;
- private final InternalCallContext internalCallContext;
+ private final NonEntityDao nonEntityDao;
+ private final CacheControllerDispatcher cacheControllerDispatcher;
+ private final MutableInternalCallContext internalCallContext;
private final InternalCallContextFactory internalCallContextFactory;
private final InvoiceConfig invoiceConfig;
// Low level SqlDao used by the tests to directly insert rows
@@ -166,7 +173,7 @@ public class TestInvoiceHelper {
@Inject
public TestInvoiceHelper(final InvoiceGenerator generator, final IDBI dbi,
final BillingInternalApi billingApi, final AccountInternalApi accountApi, final InvoicePluginDispatcher invoicePluginDispatcher, final AccountUserApi accountUserApi, final SubscriptionBaseInternalApi subscriptionApi, final BusService busService,
- final InvoiceDao invoiceDao, final GlobalLocker locker, final Clock clock, final InternalCallContext internalCallContext, final InvoiceConfig invoiceConfig,
+ final InvoiceDao invoiceDao, final GlobalLocker locker, final Clock clock, final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher, final MutableInternalCallContext internalCallContext, final InvoiceConfig invoiceConfig,
final InternalCallContextFactory internalCallContextFactory) {
this.generator = generator;
this.billingApi = billingApi;
@@ -178,6 +185,8 @@ public class TestInvoiceHelper {
this.invoiceDao = invoiceDao;
this.locker = locker;
this.clock = clock;
+ this.nonEntityDao = nonEntityDao;
+ this.cacheControllerDispatcher = cacheControllerDispatcher;
this.internalCallContext = internalCallContext;
this.internalCallContextFactory = internalCallContextFactory;
this.invoiceItemSqlDao = dbi.onDemand(InvoiceItemSqlDao.class);
@@ -189,7 +198,7 @@ public class TestInvoiceHelper {
final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
Mockito.when(subscription.getId()).thenReturn(UUID.randomUUID());
Mockito.when(subscription.getBundleId()).thenReturn(new UUID(0L, 0L));
- final BillingEventSet events = new MockBillingEventSet();
+ final BillingEventSet events = new MockBillingEventSet(internalCallContext);
final Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
final PlanPhase planPhase = MockPlanPhase.create1USDMonthlyEvergreen();
final DateTime effectiveDate = new DateTime().minusDays(1);
@@ -246,7 +255,13 @@ public class TestInvoiceHelper {
.paymentMethodId(UUID.randomUUID())
.timeZone(DateTimeZone.UTC)
.build();
- return accountUserApi.createAccount(accountData, callContext);
+ final Account account = accountUserApi.createAccount(accountData, callContext);
+
+ final Long accountRecordId = nonEntityDao.retrieveRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
+ internalCallContext.setAccountRecordId(accountRecordId);
+ internalCallContext.setReferenceDateTimeZone(account.getTimeZone());
+
+ return account;
}
public void createInvoiceItem(final InvoiceItem invoiceItem, final InternalCallContext internalCallContext) throws EntityPersistenceException {
@@ -288,7 +303,7 @@ public class TestInvoiceHelper {
}));
// The test does not use the invoice callback notifier hence the empty map
- final DefaultAccountDateAndTimeZoneContext dateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(clock.getUTCNow(), DateTimeZone.UTC);
+ final DefaultAccountDateAndTimeZoneContext dateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(clock.getUTCNow(), internalCallContext);
invoiceDao.createInvoice(invoiceModelDao, invoiceItemModelDaos, isRealInvoiceWithItems, new FutureAccountNotifications(dateAndTimeZoneContext, ImmutableMap.<UUID, List<SubscriptionNotification>>of()), internalCallContext);
}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestSubscriptionConsumableInArrear.java b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestSubscriptionConsumableInArrear.java
index ce4dcb6..506d4ce 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestSubscriptionConsumableInArrear.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestSubscriptionConsumableInArrear.java
@@ -75,7 +75,7 @@ public class TestSubscriptionConsumableInArrear extends TestUsageInArrearBase {
LocalDate targetDate = new LocalDate(2013, 6, 23);
- final AccountDateAndTimeZoneContext accountDateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(clock.getUTCNow(), DateTimeZone.UTC);
+ final AccountDateAndTimeZoneContext accountDateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(clock.getUTCNow(), internalCallContext);
final SubscriptionConsumableInArrear foo = new SubscriptionConsumableInArrear(accountId, invoiceId, billingEvents, ImmutableList.<RawUsage>of(), targetDate, new LocalDate(dt1, DateTimeZone.UTC), accountDateAndTimeZoneContext);
final List<ContiguousIntervalConsumableInArrear> result = foo.computeInArrearUsageInterval();
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
index 8f4d001..1277a52 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
@@ -73,7 +73,7 @@ public abstract class TestUsageInArrearBase extends InvoiceTestSuiteNoDB {
}
protected ContiguousIntervalConsumableInArrear createContiguousIntervalConsumableInArrear(final DefaultUsage usage, List<RawUsage> rawUsages, final LocalDate targetDate, final boolean closedInterval, final BillingEvent... events) {
- final AccountDateAndTimeZoneContext accountDateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(clock.getUTCNow(), DateTimeZone.UTC);
+ final AccountDateAndTimeZoneContext accountDateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(clock.getUTCNow(), internalCallContext);
final ContiguousIntervalConsumableInArrear intervalConsumableInArrear = new ContiguousIntervalConsumableInArrear(usage, accountId, invoiceId, rawUsages, targetDate, new LocalDate(events[0].getEffectiveDate()), accountDateAndTimeZoneContext);
for (BillingEvent event : events) {
intervalConsumableInArrear.addBillingEvent(event);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
index 74b5c2b..1ce8cbb 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
@@ -114,11 +114,11 @@ public class PhasePriceOverrideJson {
return result;
}
- public static List<PlanPhasePriceOverride> toPlanPhasePriceOverrides(final List<PhasePriceOverrideJson> input, final PlanSpecifier spec, final Currency currency) {
- if (input == null || input.isEmpty()) {
+ public static List<PlanPhasePriceOverride> toPlanPhasePriceOverrides(final List<PhasePriceOverrideJson> priceOverrides, final PlanSpecifier spec, final Currency currency) {
+ if (priceOverrides == null || priceOverrides.isEmpty()) {
return ImmutableList.<PlanPhasePriceOverride>of();
}
- return ImmutableList.copyOf(Iterables.transform(input, new Function<PhasePriceOverrideJson, PlanPhasePriceOverride>() {
+ return ImmutableList.copyOf(Iterables.transform(priceOverrides, new Function<PhasePriceOverrideJson, PlanPhasePriceOverride>() {
@Nullable
@Override
public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/IllegalStateExceptionMapper.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/IllegalStateExceptionMapper.java
new file mode 100644
index 0000000..1b9167c
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/IllegalStateExceptionMapper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.jaxrs.mappers;
+
+import javax.inject.Singleton;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.killbill.billing.util.callcontext.InternalCallContextFactory.ObjectDoesNotExist;
+
+@Singleton
+@Provider
+public class IllegalStateExceptionMapper extends ExceptionMapperBase implements ExceptionMapper<IllegalStateException> {
+
+ private final UriInfo uriInfo;
+
+ public IllegalStateExceptionMapper(@Context final UriInfo uriInfo) {
+ this.uriInfo = uriInfo;
+ }
+
+ @Override
+ public Response toResponse(final IllegalStateException exception) {
+ if (exception instanceof ObjectDoesNotExist) {
+ // Likely object for wrong tenant
+ return buildNotFoundResponse(exception, uriInfo);
+ } else {
+ return buildInternalErrorResponse(exception, uriInfo);
+ }
+ }
+}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
index 48d2446..7749b79 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
@@ -47,6 +47,7 @@ import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountUserApi;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
import org.killbill.billing.catalog.api.PlanSpecifier;
@@ -181,11 +182,12 @@ public class SubscriptionResource extends JaxRsResourceBase {
public Entitlement doOperation(final CallContext ctx) throws InterruptedException, TimeoutException, EntitlementApiException, SubscriptionApiException, AccountApiException {
final Account account = getAccountFromSubscriptionJson(entitlement, callContext);
+ final PhaseType phaseType = entitlement.getPhaseType() != null ? PhaseType.valueOf(entitlement.getPhaseType()) : null;
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(entitlement.getProductName(),
ProductCategory.valueOf(entitlement.getProductCategory()),
- BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), null);
+ BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), phaseType);
- final LocalDate inputLocalDate = toLocalDate(account, requestedDate, callContext);
+ final LocalDate inputLocalDate = requestedDate == null ? null : toLocalDate(account, requestedDate, callContext);
final PlanSpecifier planSpec = new PlanSpecifier(entitlement.getProductName(),
ProductCategory.valueOf(entitlement.getProductCategory()),
BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList());
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java
index c11ff57..b55db89 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java
@@ -130,7 +130,6 @@ public class UsageResource extends JaxRsResourceBase {
@QueryParam(QUERY_START_DATE) final String startDate,
@QueryParam(QUERY_END_DATE) final String endDate,
@javax.ws.rs.core.Context final HttpServletRequest request) {
-
if (startDate == null || endDate == null) {
return Response.status(Status.BAD_REQUEST).build();
}
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
index df27149..84b3bc1 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -123,7 +125,7 @@ public class BillCycleDayCalculator {
// TODO - this should be extracted somewhere, along with this code above
final PhaseType initialPhaseType;
final List<EffectiveSubscriptionInternalEvent> transitions = subscriptionApi.getAllTransitions(subscription, context);
- if (transitions.size() == 0) {
+ if (transitions.isEmpty()) {
initialPhaseType = null;
} else {
final DateTime requestedDate = subscription.getStartDate();
@@ -141,10 +143,9 @@ public class BillCycleDayCalculator {
}
final DateTime date = plan.dateOfFirstRecurringNonZeroCharge(subscription.getStartDate(), initialPhaseType);
- final int bcdUTC = date.toDateTime(DateTimeZone.UTC).getDayOfMonth();
- final int bcdLocal = date.toDateTime(account.getTimeZone()).getDayOfMonth();
- log.info("Calculated BCD: subscription id {}, subscription start {}, timezone {}, bcd UTC {}, bcd local {}",
- subscription.getId(), date.toDateTimeISO(), account.getTimeZone(), bcdUTC, bcdLocal);
+ final int bcdLocal = context.toDateTime(date, account.getTimeZone()).getDayOfMonth();
+ log.info("Calculated BCD: subscription id {}, subscription start {}, timezone {}, bcd {}",
+ subscription.getId(), date.toDateTimeISO(), account.getTimeZone(), bcdLocal);
return bcdLocal;
}
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
index 3e36378..b43bd54 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
@@ -1,7 +1,8 @@
/*
- * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -33,8 +34,7 @@ import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
-
-import org.killbill.billing.account.api.Account;
+import org.joda.time.Days;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Currency;
@@ -103,7 +103,6 @@ public class BlockingCalculator {
final SortedSet<BillingEvent> billingEventsToAdd = new TreeSet<BillingEvent>();
final SortedSet<BillingEvent> billingEventsToRemove = new TreeSet<BillingEvent>();
-
final List<BlockingState> blockingEvents = blockingApi.getBlockingAllForAccount(context);
final Iterable<BlockingState> accountBlockingEvents = Iterables.filter(blockingEvents, new Predicate<BlockingState>() {
@@ -118,7 +117,7 @@ public class BlockingCalculator {
for (final UUID bundleId : bundleMap.keySet()) {
- final List<BlockingState> bundleBlockingEvents = perBundleBlockingEvents.get(bundleId) != null ? perBundleBlockingEvents.get(bundleId) : ImmutableList.<BlockingState>of();
+ final List<BlockingState> bundleBlockingEvents = perBundleBlockingEvents.get(bundleId) != null ? perBundleBlockingEvents.get(bundleId) : ImmutableList.<BlockingState>of();
for (final SubscriptionBase subscription : bundleMap.get(bundleId)) {
// Avoid inserting additional events for subscriptions that don't even have a START event
@@ -144,10 +143,9 @@ public class BlockingCalculator {
}
}
-
final List<BlockingState> getAggregateBlockingEventsPerSubscription(final Iterable<BlockingState> subscriptionBlockingEvents, final Iterable<BlockingState> bundleBlockingEvents, final Iterable<BlockingState> accountBlockingEvents) {
final Iterable<BlockingState> tmp = Iterables.concat(subscriptionBlockingEvents, bundleBlockingEvents, accountBlockingEvents);
- final List<BlockingState> result = Lists.newArrayList(tmp);
+ final List<BlockingState> result = Lists.newArrayList(tmp);
Collections.sort(result);
return result;
}
@@ -161,7 +159,7 @@ public class BlockingCalculator {
});
final Map<UUID, List<BlockingState>> perTypeBlockingEvents = new HashMap<UUID, List<BlockingState>>();
- for (final BlockingState cur : bundleBlockingEvents) {
+ for (final BlockingState cur : bundleBlockingEvents) {
if (!perTypeBlockingEvents.containsKey(cur.getBlockedId())) {
perTypeBlockingEvents.put(cur.getBlockedId(), new ArrayList<BlockingState>());
}
@@ -352,7 +350,7 @@ public class BlockingCalculator {
final DateTime endDate = firstNonBlocking == null ? null : firstNonBlocking.getEffectiveDate();
if (lastOne != null && lastOne.getEnd().compareTo(startDate) == 0) {
lastOne.setEnd(endDate);
- } else if (endDate == null || startDate.toLocalDate().compareTo(endDate.toLocalDate()) != 0) {
+ } else if (endDate == null || Days.daysBetween(startDate, endDate).getDays() >= 1) {
// Don't disable for periods less than a day (see https://github.com/killbill/killbill/issues/267)
result.add(new DisabledDuration(startDate, endDate));
}
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEventSet.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEventSet.java
index 3e7cd5b..55b746a 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEventSet.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEventSet.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -26,9 +28,8 @@ import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
-import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
-import org.joda.time.LocalDate;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingMode;
import org.killbill.billing.catalog.api.Usage;
import org.killbill.billing.junction.BillingEvent;
@@ -47,21 +48,21 @@ public class DefaultBillingEventSet extends TreeSet<BillingEvent> implements Sor
private final boolean accountAutoInvoiceOff;
private final List<UUID> subscriptionIdsWithAutoInvoiceOff;
private final BillingMode recurringBillingMode;
- private final DateTimeZone accountTimeZone;
+ private final InternalTenantContext internalTenantContext;
private DefaultAccountDateAndTimeZoneContext dateTimeZoneContext;
- public DefaultBillingEventSet(final boolean accountAutoInvoiceOff, final BillingMode recurringBillingMode, final DateTimeZone timeZone) {
+ public DefaultBillingEventSet(final boolean accountAutoInvoiceOff, final BillingMode recurringBillingMode, final InternalTenantContext internalTenantContext) {
this.accountAutoInvoiceOff = accountAutoInvoiceOff;
this.recurringBillingMode = recurringBillingMode;
- this.accountTimeZone = timeZone;
+ this.internalTenantContext = internalTenantContext;
this.subscriptionIdsWithAutoInvoiceOff = new ArrayList<UUID>();
}
@Override
public boolean add(final BillingEvent e) {
if (dateTimeZoneContext == null) {
- this.dateTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(e.getEffectiveDate(), accountTimeZone);
+ this.dateTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(e.getEffectiveDate(), internalTenantContext);
}
return super.add(e);
}
@@ -69,14 +70,11 @@ public class DefaultBillingEventSet extends TreeSet<BillingEvent> implements Sor
@Override
public boolean addAll(final Collection<? extends BillingEvent> all) {
if (dateTimeZoneContext == null) {
- this.dateTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(all.iterator().next().getEffectiveDate(), accountTimeZone);
+ this.dateTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(all.iterator().next().getEffectiveDate(), internalTenantContext);
}
return super.addAll(all);
}
- /* (non-Javadoc)
- * @see org.killbill.billing.junction.plumbing.billing.BillingEventSet#isAccountAutoInvoiceOff()
- */
@Override
public boolean isAccountAutoInvoiceOff() {
return accountAutoInvoiceOff;
@@ -87,9 +85,6 @@ public class DefaultBillingEventSet extends TreeSet<BillingEvent> implements Sor
return recurringBillingMode;
}
- /* (non-Javadoc)
- * @see org.killbill.billing.junction.plumbing.billing.BillingEventSet#getSubscriptionIdsWithAutoInvoiceOff()
- */
@Override
public List<UUID> getSubscriptionIdsWithAutoInvoiceOff() {
return subscriptionIdsWithAutoInvoiceOff;
@@ -121,7 +116,6 @@ public class DefaultBillingEventSet extends TreeSet<BillingEvent> implements Sor
return result;
}
-
@Override
public String toString() {
return "DefaultBillingEventSet [accountAutoInvoiceOff=" + accountAutoInvoiceOff
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index 71bf65d..359975f 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -17,7 +19,6 @@
package org.killbill.billing.junction.plumbing.billing;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
@@ -25,8 +26,6 @@ import java.util.UUID;
import javax.annotation.Nullable;
-import org.joda.time.DateTimeZone;
-import org.joda.time.LocalDate;
import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountInternalApi;
@@ -92,7 +91,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
final StaticCatalog currentCatalog = catalogService.getCurrentCatalog(context);
final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
- final DefaultBillingEventSet result = new DefaultBillingEventSet(false, currentCatalog.getRecurringBillingMode(), account.getTimeZone());
+ final DefaultBillingEventSet result = new DefaultBillingEventSet(false, currentCatalog.getRecurringBillingMode(), context);
@@ -102,7 +101,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
final List<Tag> accountTags = tagApi.getTags(accountId, ObjectType.ACCOUNT, context);
final boolean found_AUTO_INVOICING_OFF = is_AUTO_INVOICING_OFF(accountTags);
if (found_AUTO_INVOICING_OFF) {
- return new DefaultBillingEventSet(true, currentCatalog.getRecurringBillingMode(), account.getTimeZone()); // billing is off, we are done
+ return new DefaultBillingEventSet(true, currentCatalog.getRecurringBillingMode(), context); // billing is off, we are done
}
addBillingEventsForBundles(bundles, account, dryRunArguments, context, result, skippedSubscriptions);
diff --git a/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java b/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
index 4327199..7c03083 100644
--- a/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
+++ b/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteWithEmbeddedDB.java
@@ -23,6 +23,9 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.killbill.billing.GuicyKillbillTestSuiteWithEmbeddedDB;
+import org.killbill.billing.ObjectType;
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountData;
import org.killbill.billing.account.api.AccountUserApi;
import org.killbill.billing.api.TestApiListener;
@@ -40,7 +43,9 @@ import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
import org.killbill.billing.subscription.api.SubscriptionBaseService;
import org.killbill.billing.subscription.engine.core.DefaultSubscriptionBaseService;
+import org.killbill.billing.util.cache.Cachable.CacheType;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.bus.api.PersistentBus;
import org.killbill.clock.ClockMock;
import org.slf4j.Logger;
@@ -83,6 +88,8 @@ public abstract class JunctionTestSuiteWithEmbeddedDB extends GuicyKillbillTestS
@Inject
protected EntitlementService entitlementService;
@Inject
+ protected NonEntityDao nonEntityDao;
+ @Inject
protected InternalCallContextFactory internalCallContextFactory;
protected Catalog catalog;
@@ -206,6 +213,16 @@ public abstract class JunctionTestSuiteWithEmbeddedDB extends GuicyKillbillTestS
.build();
}
+ protected Account createAccount(final AccountData accountData) throws AccountApiException {
+ final Account account = accountApi.createAccount(accountData, callContext);
+
+ final Long accountRecordId = nonEntityDao.retrieveRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, controlCacheDispatcher.getCacheController(CacheType.RECORD_ID));
+ internalCallContext.setAccountRecordId(accountRecordId);
+ internalCallContext.setReferenceDateTimeZone(account.getTimeZone());
+
+ return account;
+ }
+
protected void assertListenerStatus() {
testListener.assertListenerStatus();
}
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
index d413692..d79b19d 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
@@ -54,8 +54,7 @@ public class TestDefaultInternalBillingApi extends JunctionTestSuiteWithEmbedded
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ final Account account = createAccount(getAccountData(7));
testListener.pushExpectedEvent(NextEvent.CREATE);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
@@ -191,8 +190,7 @@ public class TestDefaultInternalBillingApi extends JunctionTestSuiteWithEmbedded
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
- final Account account = accountApi.createAccount(getAccountData(7), callContext);
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+ final Account account = createAccount(getAccountData(7));
testListener.pushExpectedEvent(NextEvent.CREATE);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java b/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java
index a2701e4..3e6aad6 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/api/DefaultOverdueInternalApi.java
@@ -84,8 +84,8 @@ public class DefaultOverdueInternalApi implements OverdueInternalApi {
@Override
public OverdueState getOverdueStateFor(final ImmutableAccountData overdueable, final TenantContext context) throws OverdueException {
try {
- final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(context);
- final BlockingState blockingStateForService = accessApi.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, internalCallContextFactory.createInternalTenantContext(context));
+ final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(overdueable.getId(), context);
+ final BlockingState blockingStateForService = accessApi.getBlockingStateForService(overdueable.getId(), 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();
@@ -99,7 +99,7 @@ public class DefaultOverdueInternalApi implements OverdueInternalApi {
public BillingState getBillingStateFor(final ImmutableAccountData overdueable, final TenantContext context) throws OverdueException {
log.debug("Billing state of of {} requested", overdueable.getId());
- final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(context);
+ final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(overdueable.getId(), context);
final OverdueWrapper wrapper = factory.createOverdueWrapperFor(overdueable, internalTenantContext);
return wrapper.billingState(internalTenantContext);
}
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
index 2c942f6..91a0e03 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
@@ -318,7 +318,7 @@ public class OverdueStateApplicator {
computeEntitlementsToCancel(account, toBeCancelled, callContext);
try {
- entitlementInternalApi.cancel(toBeCancelled, new LocalDate(clock.getUTCNow(), account.getTimeZone()), actionPolicy, ImmutableList.<PluginProperty>of(), context);
+ entitlementInternalApi.cancel(toBeCancelled, clock.getToday(account.getTimeZone()), actionPolicy, ImmutableList.<PluginProperty>of(), context);
} catch (final EntitlementApiException e) {
throw new OverdueException(e);
}
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/notification/DefaultOverduePosterBase.java b/overdue/src/main/java/org/killbill/billing/overdue/notification/DefaultOverduePosterBase.java
index b737976..463d08c 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/notification/DefaultOverduePosterBase.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/notification/DefaultOverduePosterBase.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -25,6 +25,7 @@ import org.joda.time.DateTime;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.overdue.service.DefaultOverdueService;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
@@ -48,10 +49,10 @@ public abstract class DefaultOverduePosterBase implements OverduePoster {
private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
public DefaultOverduePosterBase(final NotificationQueueService notificationQueueService,
- final IDBI dbi, final Clock clock,
- final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+ final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+ final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
this.notificationQueueService = notificationQueueService;
- this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
+ this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
}
@Override
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusPoster.java b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusPoster.java
index 967d5b6..d6b7a44 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusPoster.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusPoster.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -22,6 +22,7 @@ import java.util.Collection;
import org.joda.time.DateTime;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
import org.killbill.clock.Clock;
@@ -36,9 +37,9 @@ public class OverdueAsyncBusPoster extends DefaultOverduePosterBase {
@Inject
public OverdueAsyncBusPoster(final NotificationQueueService notificationQueueService,
- final IDBI dbi, final Clock clock,
- final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
- super(notificationQueueService, dbi, clock, cacheControllerDispatcher, nonEntityDao);
+ final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+ final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
+ super(notificationQueueService, dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
}
@Override
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckPoster.java b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckPoster.java
index 0c118c4..1119e53 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckPoster.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckPoster.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -22,6 +22,7 @@ import java.util.Collection;
import org.joda.time.DateTime;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
import org.killbill.clock.Clock;
@@ -36,9 +37,9 @@ public class OverdueCheckPoster extends DefaultOverduePosterBase {
@Inject
public OverdueCheckPoster(final NotificationQueueService notificationQueueService,
- final IDBI dbi, final Clock clock,
- final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
- super(notificationQueueService, dbi, clock, cacheControllerDispatcher, nonEntityDao);
+ final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+ final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
+ super(notificationQueueService, dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
}
@Override
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/notification/TestDefaultOverdueCheckPoster.java b/overdue/src/test/java/org/killbill/billing/overdue/notification/TestDefaultOverdueCheckPoster.java
index 8d2a884..03e91fa 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/notification/TestDefaultOverdueCheckPoster.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/notification/TestDefaultOverdueCheckPoster.java
@@ -48,7 +48,7 @@ public class TestDefaultOverdueCheckPoster extends OverdueTestSuiteWithEmbeddedD
@BeforeMethod(groups = "slow")
public void beforeMethod() throws Exception {
super.beforeMethod();
- entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
+ entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
overdueQueue = notificationQueueService.getNotificationQueue(DefaultOverdueService.OVERDUE_SERVICE_NAME,
OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE);
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPayment.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPayment.java
index 14e7ab0..1e7962a 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPayment.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPayment.java
@@ -1,7 +1,8 @@
/*
- * Copyright 2014 Groupon, Inc
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Groupon licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -17,6 +18,8 @@
package org.killbill.billing.payment.api;
import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@@ -28,6 +31,7 @@ import org.killbill.billing.entity.EntityBase;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
public class DefaultPayment extends EntityBase implements Payment {
@@ -40,7 +44,7 @@ public class DefaultPayment extends EntityBase implements Payment {
private final BigDecimal purchasedAmount;
private final BigDecimal creditAmount;
private final BigDecimal refundAmount;
- private final Boolean isVoided;
+ private final Boolean isAuthVoided;
private final Currency currency;
private final List<PaymentTransaction> transactions;
@@ -56,18 +60,40 @@ public class DefaultPayment extends EntityBase implements Payment {
this.paymentNumber = paymentNumber;
this.externalKey = externalKey;
this.transactions = transactions;
- this.authAmount = getAmountForType(transactions, TransactionType.AUTHORIZE);
- this.captureAmount = getAmountForType(transactions, TransactionType.CAPTURE);
- this.purchasedAmount = getAmountForType(transactions, TransactionType.PURCHASE);
- this.creditAmount = getAmountForType(transactions, TransactionType.CREDIT);
- this.refundAmount = getAmountForType(transactions, TransactionType.REFUND);
- this.isVoided = Iterables.filter(transactions, new Predicate<PaymentTransaction>() {
- @Override
- public boolean apply(final PaymentTransaction input) {
- return input.getTransactionType() == TransactionType.VOID && TransactionStatus.SUCCESS.equals(input.getTransactionStatus());
+
+ final Collection<PaymentTransaction> voidedTransactions = new LinkedList<PaymentTransaction>();
+ final Collection<PaymentTransaction> nonVoidedTransactions = new LinkedList<PaymentTransaction>();
+ int nvTxToVoid = 0;
+ for (final PaymentTransaction paymentTransaction : Lists.<PaymentTransaction>reverse(transactions)) {
+ if (TransactionStatus.SUCCESS.equals(paymentTransaction.getTransactionStatus())) {
+ if (paymentTransaction.getTransactionType() == TransactionType.VOID) {
+ nvTxToVoid++;
+ } else {
+ if (nvTxToVoid > 0) {
+ nvTxToVoid--;
+ voidedTransactions.add(paymentTransaction);
+ } else {
+ nonVoidedTransactions.add(paymentTransaction);
+ }
+ }
}
- }).iterator().hasNext();
- this.currency = (transactions != null && !transactions.isEmpty()) ? transactions.get(0).getCurrency() : null;
+ }
+
+ this.authAmount = getAmountForType(nonVoidedTransactions, TransactionType.AUTHORIZE);
+ this.captureAmount = getAmountForType(nonVoidedTransactions, TransactionType.CAPTURE);
+ this.purchasedAmount = getAmountForType(nonVoidedTransactions, TransactionType.PURCHASE);
+ this.creditAmount = getAmountForType(nonVoidedTransactions, TransactionType.CREDIT);
+ this.refundAmount = getAmountForType(nonVoidedTransactions, TransactionType.REFUND);
+
+ this.isAuthVoided = Iterables.<PaymentTransaction>tryFind(voidedTransactions,
+ new Predicate<PaymentTransaction>() {
+ @Override
+ public boolean apply(final PaymentTransaction input) {
+ return input.getTransactionType() == TransactionType.AUTHORIZE && TransactionStatus.SUCCESS.equals(input.getTransactionStatus());
+ }
+ }).isPresent();
+
+ this.currency = !transactions.isEmpty() ? transactions.get(0).getCurrency() : null;
}
private static BigDecimal getAmountForType(final Iterable<PaymentTransaction> transactions, final TransactionType transactiontype) {
@@ -141,7 +167,7 @@ public class DefaultPayment extends EntityBase implements Payment {
@Override
public Boolean isAuthVoided() {
- return isVoided;
+ return isAuthVoided;
}
@Override
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
index 3da498d..ccb946e 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
@@ -26,6 +26,7 @@ import javax.annotation.Nullable;
import javax.inject.Inject;
import org.killbill.billing.ErrorCode;
+import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.api.Currency;
@@ -392,7 +393,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
@Override
public Payment getPayment(final UUID paymentId, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext context) throws PaymentApiException {
- final Payment payment = paymentProcessor.getPayment(paymentId, withPluginInfo, properties, context, internalCallContextFactory.createInternalTenantContext(context));
+ final Payment payment = paymentProcessor.getPayment(paymentId, withPluginInfo, properties, context, internalCallContextFactory.createInternalTenantContext(paymentId, ObjectType.PAYMENT, context));
if (payment == null) {
throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT, paymentId);
}
@@ -431,13 +432,13 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
@Override
public List<PaymentMethod> getAccountPaymentMethods(final UUID accountId, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext context)
throws PaymentApiException {
- return paymentMethodProcessor.getPaymentMethods(accountId, withPluginInfo, properties, context, internalCallContextFactory.createInternalTenantContext(context));
+ return paymentMethodProcessor.getPaymentMethods(accountId, withPluginInfo, properties, context, internalCallContextFactory.createInternalTenantContext(accountId, context));
}
@Override
public PaymentMethod getPaymentMethodById(final UUID paymentMethodId, final boolean includedDeleted, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext context)
throws PaymentApiException {
- return paymentMethodProcessor.getPaymentMethodById(paymentMethodId, includedDeleted, withPluginInfo, properties, context, internalCallContextFactory.createInternalTenantContext(context));
+ return paymentMethodProcessor.getPaymentMethodById(paymentMethodId, includedDeleted, withPluginInfo, properties, context, internalCallContextFactory.createInternalTenantContext(paymentMethodId, ObjectType.PAYMENT_METHOD, context));
}
@Override
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
index a03d1eb..2c849ca 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -43,6 +43,7 @@ import org.killbill.billing.payment.api.PaymentTransaction;
import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.Entity;
import org.killbill.billing.util.entity.Pagination;
@@ -67,7 +68,7 @@ import com.google.common.collect.Iterables;
public class DefaultPaymentDao implements PaymentDao {
- private final static Logger log = LoggerFactory.getLogger(DefaultPaymentDao.class);
+ private static final Logger log = LoggerFactory.getLogger(DefaultPaymentDao.class);
private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
private final DefaultPaginationSqlDaoHelper paginationHelper;
@@ -75,8 +76,9 @@ public class DefaultPaymentDao implements PaymentDao {
private final Clock clock;
@Inject
- public DefaultPaymentDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final PersistentBus eventBus) {
- this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
+ public DefaultPaymentDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+ final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory, final PersistentBus eventBus) {
+ this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
this.paginationHelper = new DefaultPaginationSqlDaoHelper(transactionalSqlDao);
this.eventBus = eventBus;
this.clock = clock;
diff --git a/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml b/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
index ebfa2d2..14146d6 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
+++ b/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
@@ -472,6 +472,30 @@
<finalState>VOID_INIT</finalState>
</linkStateMachine>
<linkStateMachine>
+ <initialStateMachine>VOID</initialStateMachine>
+ <initialState>VOID_SUCCESS</initialState>
+ <finalStateMachine>VOID</finalStateMachine>
+ <finalState>VOID_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
+ <initialStateMachine>VOID</initialStateMachine>
+ <initialState>VOID_SUCCESS</initialState>
+ <finalStateMachine>CAPTURE</finalStateMachine>
+ <finalState>CAPTURE_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
+ <initialStateMachine>VOID</initialStateMachine>
+ <initialState>VOID_SUCCESS</initialState>
+ <finalStateMachine>REFUND</finalStateMachine>
+ <finalState>REFUND_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
+ <initialStateMachine>VOID</initialStateMachine>
+ <initialState>VOID_SUCCESS</initialState>
+ <finalStateMachine>CREDIT</finalStateMachine>
+ <finalState>CREDIT_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
<initialStateMachine>CAPTURE</initialStateMachine>
<initialState>CAPTURE_SUCCESS</initialState>
<finalStateMachine>REFUND</finalStateMachine>
@@ -490,6 +514,12 @@
<finalState>CHARGEBACK_INIT</finalState>
</linkStateMachine>
<linkStateMachine>
+ <initialStateMachine>CAPTURE</initialStateMachine>
+ <initialState>CAPTURE_SUCCESS</initialState>
+ <finalStateMachine>VOID</finalStateMachine>
+ <finalState>VOID_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
<initialStateMachine>REFUND</initialStateMachine>
<initialState>REFUND_SUCCESS</initialState>
<finalStateMachine>REFUND</finalStateMachine>
@@ -502,6 +532,12 @@
<finalState>CHARGEBACK_INIT</finalState>
</linkStateMachine>
<linkStateMachine>
+ <initialStateMachine>REFUND</initialStateMachine>
+ <initialState>REFUND_SUCCESS</initialState>
+ <finalStateMachine>VOID</finalStateMachine>
+ <finalState>VOID_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
<initialStateMachine>PURCHASE</initialStateMachine>
<initialState>PURCHASE_SUCCESS</initialState>
<finalStateMachine>REFUND</finalStateMachine>
@@ -514,6 +550,12 @@
<finalState>CHARGEBACK_INIT</finalState>
</linkStateMachine>
<linkStateMachine>
+ <initialStateMachine>CREDIT</initialStateMachine>
+ <initialState>CREDIT_SUCCESS</initialState>
+ <finalStateMachine>VOID</finalStateMachine>
+ <finalState>VOID_INIT</finalState>
+ </linkStateMachine>
+ <linkStateMachine>
<initialStateMachine>CHARGEBACK</initialStateMachine>
<initialState>CHARGEBACK_SUCCESS</initialState>
<finalStateMachine>CHARGEBACK</finalStateMachine>
diff --git a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
index d6e293e..a3cca2f 100644
--- a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -59,6 +59,7 @@ import com.google.common.collect.ImmutableList;
import static org.killbill.billing.payment.logging.TestLoggingHelper.withSpyLogger;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
@@ -189,19 +190,147 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
assertEquals(payment.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE);
assertNotNull(payment.getTransactions().get(0).getGatewayErrorMsg());
assertNotNull(payment.getTransactions().get(0).getGatewayErrorCode());
+
+ final Payment payment2 = paymentApi.createPurchase(account, account.getPaymentMethodId(), null, requestedAmount, Currency.AED, paymentExternalKey, transactionExternalKey,
+ ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment2.getExternalKey(), paymentExternalKey);
+ assertEquals(payment2.getTransactions().get(0).getExternalKey(), transactionExternalKey);
+ assertEquals(payment2.getTransactions().get(0).getTransactionStatus(), TransactionStatus.PAYMENT_FAILURE);
+ assertEquals(payment2.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE);
+
+ assertEquals(payment2.getTransactions().get(1).getExternalKey(), transactionExternalKey);
+ assertEquals(payment2.getTransactions().get(1).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment2.getTransactions().get(1).getTransactionType(), TransactionType.PURCHASE);
+
}
+
@Test(groups = "slow")
- public void testCreateSuccessAuthCapture() throws PaymentApiException {
+ public void testCreateCancelledPurchase() throws PaymentApiException {
+
+ final BigDecimal requestedAmount = BigDecimal.TEN;
+
+ final String paymentExternalKey = "hgh3";
+ final String transactionExternalKey = "hgh3sss";
+
+ mockPaymentProviderPlugin.makeNextPaymentFailWithCancellation();
+
+ final Payment payment = paymentApi.createPurchase(account, account.getPaymentMethodId(), null, requestedAmount, Currency.AED, paymentExternalKey, transactionExternalKey,
+ ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment.getExternalKey(), paymentExternalKey);
+ assertEquals(payment.getPaymentMethodId(), account.getPaymentMethodId());
+ assertEquals(payment.getAccountId(), account.getId());
+ assertEquals(payment.getAuthAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getCurrency(), Currency.AED);
+
+ assertEquals(payment.getTransactions().size(), 1);
+ assertEquals(payment.getTransactions().get(0).getExternalKey(), transactionExternalKey);
+ assertEquals(payment.getTransactions().get(0).getPaymentId(), payment.getId());
+ assertEquals(payment.getTransactions().get(0).getAmount().compareTo(requestedAmount), 0);
+ assertEquals(payment.getTransactions().get(0).getCurrency(), Currency.AED);
+ assertEquals(payment.getTransactions().get(0).getProcessedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getTransactions().get(0).getProcessedCurrency(), Currency.AED);
+
+ assertEquals(payment.getTransactions().get(0).getTransactionStatus(), TransactionStatus.PLUGIN_FAILURE);
+ assertEquals(payment.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE);
+ assertNotNull(payment.getTransactions().get(0).getGatewayErrorMsg());
+ assertNotNull(payment.getTransactions().get(0).getGatewayErrorCode());
+
+ final Payment payment2 = paymentApi.createPurchase(account, account.getPaymentMethodId(), null, requestedAmount, Currency.AED, paymentExternalKey, transactionExternalKey,
+ ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment2.getExternalKey(), paymentExternalKey);
+ assertEquals(payment2.getTransactions().get(0).getExternalKey(), transactionExternalKey);
+ assertEquals(payment2.getTransactions().get(0).getTransactionStatus(), TransactionStatus.PLUGIN_FAILURE);
+ assertEquals(payment2.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE);
+
+ assertEquals(payment2.getTransactions().get(1).getExternalKey(), transactionExternalKey);
+ assertEquals(payment2.getTransactions().get(1).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment2.getTransactions().get(1).getTransactionType(), TransactionType.PURCHASE);
+
+ }
+
+
+ @Test(groups = "slow")
+ public void testCreateSuccessAuthVoid() throws PaymentApiException {
+ final BigDecimal authAmount = BigDecimal.TEN;
+
+ final String paymentExternalKey = UUID.randomUUID().toString();
+ final String transactionExternalKey = UUID.randomUUID().toString();
+ final String transactionExternalKey2 = UUID.randomUUID().toString();
+
+ final Payment payment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), null, authAmount, Currency.AED,
+ paymentExternalKey, transactionExternalKey,
+ ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment.getExternalKey(), paymentExternalKey);
+ assertEquals(payment.getPaymentMethodId(), account.getPaymentMethodId());
+ assertEquals(payment.getAccountId(), account.getId());
+ assertEquals(payment.getAuthAmount().compareTo(authAmount), 0);
+ assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getCurrency(), Currency.AED);
+ assertFalse(payment.isAuthVoided());
+
+ assertEquals(payment.getTransactions().size(), 1);
+ assertEquals(payment.getTransactions().get(0).getExternalKey(), transactionExternalKey);
+ assertEquals(payment.getTransactions().get(0).getPaymentId(), payment.getId());
+ assertEquals(payment.getTransactions().get(0).getAmount().compareTo(authAmount), 0);
+ assertEquals(payment.getTransactions().get(0).getCurrency(), Currency.AED);
+ assertEquals(payment.getTransactions().get(0).getProcessedAmount().compareTo(authAmount), 0);
+ assertEquals(payment.getTransactions().get(0).getProcessedCurrency(), Currency.AED);
+
+ assertEquals(payment.getTransactions().get(0).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment.getTransactions().get(0).getTransactionType(), TransactionType.AUTHORIZE);
+ assertNotNull(payment.getTransactions().get(0).getGatewayErrorMsg());
+ assertNotNull(payment.getTransactions().get(0).getGatewayErrorCode());
+
+ // Void the authorization
+ final Payment payment2 = paymentApi.createVoid(account, payment.getId(), transactionExternalKey2, ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment2.getExternalKey(), paymentExternalKey);
+ assertEquals(payment2.getPaymentMethodId(), account.getPaymentMethodId());
+ assertEquals(payment2.getAccountId(), account.getId());
+ assertEquals(payment2.getAuthAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment2.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment2.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment2.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment2.getCurrency(), Currency.AED);
+ assertTrue(payment2.isAuthVoided());
+
+ assertEquals(payment2.getTransactions().size(), 2);
+ assertEquals(payment2.getTransactions().get(1).getExternalKey(), transactionExternalKey2);
+ assertEquals(payment2.getTransactions().get(1).getPaymentId(), payment.getId());
+ assertNull(payment2.getTransactions().get(1).getAmount());
+ assertNull(payment2.getTransactions().get(1).getCurrency());
+ assertNull(payment2.getTransactions().get(1).getProcessedAmount());
+ assertNull(payment2.getTransactions().get(1).getProcessedCurrency());
+
+ assertEquals(payment2.getTransactions().get(1).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment2.getTransactions().get(1).getTransactionType(), TransactionType.VOID);
+ assertNotNull(payment2.getTransactions().get(1).getGatewayErrorMsg());
+ assertNotNull(payment2.getTransactions().get(1).getGatewayErrorCode());
+ }
+ @Test(groups = "slow")
+ public void testCreateSuccessAuthCaptureVoidCapture() throws PaymentApiException {
final BigDecimal authAmount = BigDecimal.TEN;
final BigDecimal captureAmount = BigDecimal.ONE;
- final String paymentExternalKey = "bouzou";
- final String transactionExternalKey = "kaput";
- final String transactionExternalKey2 = "kapu2t";
+ final String paymentExternalKey = UUID.randomUUID().toString();
+ final String transactionExternalKey = UUID.randomUUID().toString();
+ final String transactionExternalKey2 = UUID.randomUUID().toString();
+ final String transactionExternalKey3 = UUID.randomUUID().toString();
+ final String transactionExternalKey4 = UUID.randomUUID().toString();
- final Payment payment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), null, authAmount, Currency.AED, paymentExternalKey, transactionExternalKey,
+ final Payment payment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), null, authAmount, Currency.AED,
+ paymentExternalKey, transactionExternalKey,
ImmutableList.<PluginProperty>of(), callContext);
assertEquals(payment.getExternalKey(), paymentExternalKey);
@@ -212,6 +341,7 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
assertEquals(payment.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
assertEquals(payment.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
assertEquals(payment.getCurrency(), Currency.AED);
+ assertFalse(payment.isAuthVoided());
assertEquals(payment.getTransactions().size(), 1);
assertEquals(payment.getTransactions().get(0).getExternalKey(), transactionExternalKey);
@@ -237,6 +367,7 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
assertEquals(payment2.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
assertEquals(payment2.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
assertEquals(payment2.getCurrency(), Currency.AED);
+ assertFalse(payment2.isAuthVoided());
assertEquals(payment2.getTransactions().size(), 2);
assertEquals(payment2.getTransactions().get(1).getExternalKey(), transactionExternalKey2);
@@ -250,6 +381,176 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
assertEquals(payment2.getTransactions().get(1).getTransactionType(), TransactionType.CAPTURE);
assertNotNull(payment2.getTransactions().get(1).getGatewayErrorMsg());
assertNotNull(payment2.getTransactions().get(1).getGatewayErrorCode());
+
+ // Void the capture
+ final Payment payment3 = paymentApi.createVoid(account, payment.getId(), transactionExternalKey3, ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment3.getExternalKey(), paymentExternalKey);
+ assertEquals(payment3.getPaymentMethodId(), account.getPaymentMethodId());
+ assertEquals(payment3.getAccountId(), account.getId());
+ assertEquals(payment3.getAuthAmount().compareTo(authAmount), 0);
+ assertEquals(payment3.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment3.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment3.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment3.getCurrency(), Currency.AED);
+ assertFalse(payment3.isAuthVoided());
+
+ assertEquals(payment3.getTransactions().size(), 3);
+ assertEquals(payment3.getTransactions().get(2).getExternalKey(), transactionExternalKey3);
+ assertEquals(payment3.getTransactions().get(2).getPaymentId(), payment.getId());
+ assertNull(payment3.getTransactions().get(2).getAmount());
+ assertNull(payment3.getTransactions().get(2).getCurrency());
+ assertNull(payment3.getTransactions().get(2).getProcessedAmount());
+ assertNull(payment3.getTransactions().get(2).getProcessedCurrency());
+
+ assertEquals(payment3.getTransactions().get(2).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment3.getTransactions().get(2).getTransactionType(), TransactionType.VOID);
+ assertNotNull(payment3.getTransactions().get(2).getGatewayErrorMsg());
+ assertNotNull(payment3.getTransactions().get(2).getGatewayErrorCode());
+
+ // Capture again
+ final Payment payment4 = paymentApi.createCapture(account, payment.getId(), captureAmount, Currency.AED, transactionExternalKey4,
+ ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment4.getExternalKey(), paymentExternalKey);
+ assertEquals(payment4.getPaymentMethodId(), account.getPaymentMethodId());
+ assertEquals(payment4.getAccountId(), account.getId());
+ assertEquals(payment4.getAuthAmount().compareTo(authAmount), 0);
+ assertEquals(payment4.getCapturedAmount().compareTo(captureAmount), 0);
+ assertEquals(payment4.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment4.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment4.getCurrency(), Currency.AED);
+ assertFalse(payment4.isAuthVoided());
+
+ assertEquals(payment4.getTransactions().size(), 4);
+ assertEquals(payment4.getTransactions().get(3).getExternalKey(), transactionExternalKey4);
+ assertEquals(payment4.getTransactions().get(3).getPaymentId(), payment.getId());
+ assertEquals(payment4.getTransactions().get(3).getAmount().compareTo(captureAmount), 0);
+ assertEquals(payment4.getTransactions().get(3).getCurrency(), Currency.AED);
+ assertEquals(payment4.getTransactions().get(3).getProcessedAmount().compareTo(captureAmount), 0);
+ assertEquals(payment4.getTransactions().get(3).getProcessedCurrency(), Currency.AED);
+
+ assertEquals(payment4.getTransactions().get(3).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment4.getTransactions().get(3).getTransactionType(), TransactionType.CAPTURE);
+ assertNotNull(payment4.getTransactions().get(3).getGatewayErrorMsg());
+ assertNotNull(payment4.getTransactions().get(3).getGatewayErrorCode());
+ }
+
+ @Test(groups = "slow")
+ public void testCreateSuccessAuthCaptureVoidVoid() throws PaymentApiException {
+ final BigDecimal authAmount = BigDecimal.TEN;
+ final BigDecimal captureAmount = BigDecimal.ONE;
+
+ final String paymentExternalKey = UUID.randomUUID().toString();
+ final String transactionExternalKey = UUID.randomUUID().toString();
+ final String transactionExternalKey2 = UUID.randomUUID().toString();
+ final String transactionExternalKey3 = UUID.randomUUID().toString();
+ final String transactionExternalKey4 = UUID.randomUUID().toString();
+
+ final Payment payment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), null, authAmount, Currency.AED,
+ paymentExternalKey, transactionExternalKey,
+ ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment.getExternalKey(), paymentExternalKey);
+ assertEquals(payment.getPaymentMethodId(), account.getPaymentMethodId());
+ assertEquals(payment.getAccountId(), account.getId());
+ assertEquals(payment.getAuthAmount().compareTo(authAmount), 0);
+ assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getCurrency(), Currency.AED);
+ assertFalse(payment.isAuthVoided());
+
+ assertEquals(payment.getTransactions().size(), 1);
+ assertEquals(payment.getTransactions().get(0).getExternalKey(), transactionExternalKey);
+ assertEquals(payment.getTransactions().get(0).getPaymentId(), payment.getId());
+ assertEquals(payment.getTransactions().get(0).getAmount().compareTo(authAmount), 0);
+ assertEquals(payment.getTransactions().get(0).getCurrency(), Currency.AED);
+ assertEquals(payment.getTransactions().get(0).getProcessedAmount().compareTo(authAmount), 0);
+ assertEquals(payment.getTransactions().get(0).getProcessedCurrency(), Currency.AED);
+
+ assertEquals(payment.getTransactions().get(0).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment.getTransactions().get(0).getTransactionType(), TransactionType.AUTHORIZE);
+ assertNotNull(payment.getTransactions().get(0).getGatewayErrorMsg());
+ assertNotNull(payment.getTransactions().get(0).getGatewayErrorCode());
+
+ final Payment payment2 = paymentApi.createCapture(account, payment.getId(), captureAmount, Currency.AED, transactionExternalKey2,
+ ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment2.getExternalKey(), paymentExternalKey);
+ assertEquals(payment2.getPaymentMethodId(), account.getPaymentMethodId());
+ assertEquals(payment2.getAccountId(), account.getId());
+ assertEquals(payment2.getAuthAmount().compareTo(authAmount), 0);
+ assertEquals(payment2.getCapturedAmount().compareTo(captureAmount), 0);
+ assertEquals(payment2.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment2.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment2.getCurrency(), Currency.AED);
+ assertFalse(payment2.isAuthVoided());
+
+ assertEquals(payment2.getTransactions().size(), 2);
+ assertEquals(payment2.getTransactions().get(1).getExternalKey(), transactionExternalKey2);
+ assertEquals(payment2.getTransactions().get(1).getPaymentId(), payment.getId());
+ assertEquals(payment2.getTransactions().get(1).getAmount().compareTo(captureAmount), 0);
+ assertEquals(payment2.getTransactions().get(1).getCurrency(), Currency.AED);
+ assertEquals(payment2.getTransactions().get(1).getProcessedAmount().compareTo(captureAmount), 0);
+ assertEquals(payment2.getTransactions().get(1).getProcessedCurrency(), Currency.AED);
+
+ assertEquals(payment2.getTransactions().get(1).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment2.getTransactions().get(1).getTransactionType(), TransactionType.CAPTURE);
+ assertNotNull(payment2.getTransactions().get(1).getGatewayErrorMsg());
+ assertNotNull(payment2.getTransactions().get(1).getGatewayErrorCode());
+
+ // Void the capture
+ final Payment payment3 = paymentApi.createVoid(account, payment.getId(), transactionExternalKey3, ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment3.getExternalKey(), paymentExternalKey);
+ assertEquals(payment3.getPaymentMethodId(), account.getPaymentMethodId());
+ assertEquals(payment3.getAccountId(), account.getId());
+ assertEquals(payment3.getAuthAmount().compareTo(authAmount), 0);
+ assertEquals(payment3.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment3.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment3.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment3.getCurrency(), Currency.AED);
+ assertFalse(payment3.isAuthVoided());
+
+ assertEquals(payment3.getTransactions().size(), 3);
+ assertEquals(payment3.getTransactions().get(2).getExternalKey(), transactionExternalKey3);
+ assertEquals(payment3.getTransactions().get(2).getPaymentId(), payment.getId());
+ assertNull(payment3.getTransactions().get(2).getAmount());
+ assertNull(payment3.getTransactions().get(2).getCurrency());
+ assertNull(payment3.getTransactions().get(2).getProcessedAmount());
+ assertNull(payment3.getTransactions().get(2).getProcessedCurrency());
+
+ assertEquals(payment3.getTransactions().get(2).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment3.getTransactions().get(2).getTransactionType(), TransactionType.VOID);
+ assertNotNull(payment3.getTransactions().get(2).getGatewayErrorMsg());
+ assertNotNull(payment3.getTransactions().get(2).getGatewayErrorCode());
+
+ // Void the authorization
+ final Payment payment4 = paymentApi.createVoid(account, payment.getId(), transactionExternalKey4, ImmutableList.<PluginProperty>of(), callContext);
+
+ assertEquals(payment4.getExternalKey(), paymentExternalKey);
+ assertEquals(payment4.getPaymentMethodId(), account.getPaymentMethodId());
+ assertEquals(payment4.getAccountId(), account.getId());
+ assertEquals(payment4.getAuthAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment4.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment4.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment4.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment4.getCurrency(), Currency.AED);
+ assertTrue(payment4.isAuthVoided());
+
+ assertEquals(payment4.getTransactions().size(), 4);
+ assertEquals(payment4.getTransactions().get(3).getExternalKey(), transactionExternalKey4);
+ assertEquals(payment4.getTransactions().get(3).getPaymentId(), payment.getId());
+ assertNull(payment4.getTransactions().get(3).getAmount());
+ assertNull(payment4.getTransactions().get(3).getCurrency());
+ assertNull(payment4.getTransactions().get(3).getProcessedAmount());
+ assertNull(payment4.getTransactions().get(3).getProcessedCurrency());
+
+ assertEquals(payment4.getTransactions().get(3).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment4.getTransactions().get(3).getTransactionType(), TransactionType.VOID);
+ assertNotNull(payment4.getTransactions().get(3).getGatewayErrorMsg());
+ assertNotNull(payment4.getTransactions().get(3).getGatewayErrorCode());
}
@Test(groups = "slow")
@@ -414,6 +715,82 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
@Test(groups = "slow")
+ public void testCreateCancelledPurchaseWithPaymentControl() throws PaymentApiException, InvoiceApiException, EventBusException {
+
+ final BigDecimal requestedAmount = BigDecimal.TEN;
+ final UUID subscriptionId = UUID.randomUUID();
+ final UUID bundleId = UUID.randomUUID();
+ final LocalDate now = clock.getUTCToday();
+
+ final Invoice invoice = testHelper.createTestInvoice(account, now, Currency.USD);
+
+ final String paymentExternalKey = invoice.getId().toString();
+ final String transactionExternalKey = "hgjhgjgjhg33";
+
+ mockPaymentProviderPlugin.makeNextPaymentFailWithCancellation();
+
+ invoice.addInvoiceItem(new MockRecurringInvoiceItem(invoice.getId(), account.getId(),
+ subscriptionId,
+ bundleId,
+ "test plan", "test phase", null,
+ now,
+ now.plusMonths(1),
+ requestedAmount,
+ new BigDecimal("1.0"),
+ Currency.USD));
+ try {
+ paymentApi.createPurchaseWithPaymentControl(account, account.getPaymentMethodId(), null, requestedAmount, Currency.USD, paymentExternalKey, transactionExternalKey,
+ createPropertiesForInvoice(invoice), INVOICE_PAYMENT, callContext);
+ } catch (final PaymentApiException expected) {
+ assertTrue(true);
+ }
+
+
+ final List<Payment> accountPayments = paymentApi.getAccountPayments(account.getId(), false, ImmutableList.<PluginProperty>of(), callContext);
+ assertEquals(accountPayments.size(), 1);
+ final Payment payment = accountPayments.get(0);
+ assertEquals(payment.getExternalKey(), paymentExternalKey);
+ assertEquals(payment.getPaymentMethodId(), account.getPaymentMethodId());
+ assertEquals(payment.getAccountId(), account.getId());
+ assertEquals(payment.getAuthAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getCurrency(), Currency.USD);
+
+ assertEquals(payment.getTransactions().size(), 1);
+ assertEquals(payment.getTransactions().get(0).getExternalKey(), transactionExternalKey);
+ assertEquals(payment.getTransactions().get(0).getPaymentId(), payment.getId());
+ assertEquals(payment.getTransactions().get(0).getAmount().compareTo(requestedAmount), 0);
+ assertEquals(payment.getTransactions().get(0).getCurrency(), Currency.USD);
+ assertEquals(payment.getTransactions().get(0).getProcessedAmount().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(payment.getTransactions().get(0).getProcessedCurrency(), Currency.USD);
+
+ assertEquals(payment.getTransactions().get(0).getTransactionStatus(), TransactionStatus.PLUGIN_FAILURE);
+ assertEquals(payment.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE);
+
+ // Make sure we can retry and that works
+ paymentApi.createPurchaseWithPaymentControl(account, account.getPaymentMethodId(), null, requestedAmount, Currency.USD, paymentExternalKey, transactionExternalKey,
+ createPropertiesForInvoice(invoice), INVOICE_PAYMENT, callContext);
+
+
+ final List<Payment> accountPayments2 = paymentApi.getAccountPayments(account.getId(), false, ImmutableList.<PluginProperty>of(), callContext);
+ assertEquals(accountPayments2.size(), 1);
+ final Payment payment2 = accountPayments2.get(0);
+ assertEquals(payment2.getTransactions().size(), 2);
+
+ assertEquals(payment2.getTransactions().get(0).getExternalKey(), transactionExternalKey);
+ assertEquals(payment2.getTransactions().get(0).getTransactionStatus(), TransactionStatus.PLUGIN_FAILURE);
+ assertEquals(payment2.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE);
+
+ assertEquals(payment2.getTransactions().get(1).getExternalKey(), transactionExternalKey);
+ assertEquals(payment2.getTransactions().get(1).getTransactionStatus(), TransactionStatus.SUCCESS);
+ assertEquals(payment2.getTransactions().get(1).getTransactionType(), TransactionType.PURCHASE);
+
+ }
+
+
+ @Test(groups = "slow")
public void testCreateAbortedPurchaseWithPaymentControl() throws InvoiceApiException, EventBusException {
final BigDecimal requestedAmount = BigDecimal.TEN;
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
index 1717dc4..106c179 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
@@ -1,8 +1,8 @@
/*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Groupon licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -121,7 +121,7 @@ public class TestPaymentLeavingStateCallback extends PaymentTestSuiteWithEmbedde
transactions.get(0).getId(), TransactionStatus.SUCCESS, BigDecimal.ONE, Currency.BRL,
"foo", "bar", internalCallContext);
- final InternalCallContext internalCallContextForOtherAccount = new InternalCallContext(paymentStateContext.getInternalCallContext(), 123L);
+ internalCallContext.setAccountRecordId(123L);
paymentStateContext = new PaymentStateContext(true,
paymentId,
@@ -137,7 +137,7 @@ public class TestPaymentLeavingStateCallback extends PaymentTestSuiteWithEmbedde
paymentStateContext.shouldLockAccountAndDispatch(),
paymentStateContext.getOverridePluginOperationResult(),
paymentStateContext.getProperties(),
- internalCallContextForOtherAccount,
+ internalCallContext,
callContext);
callback.leavingState(state);
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentProcessor.java b/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentProcessor.java
index caa98f1..f5f71c6 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentProcessor.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentProcessor.java
@@ -1,8 +1,8 @@
/*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Groupon licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -27,7 +27,6 @@ import java.util.concurrent.Callable;
import javax.annotation.Nullable;
import org.killbill.billing.account.api.Account;
-import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.events.BusInternalEvent;
import org.killbill.billing.events.PaymentErrorInternalEvent;
@@ -63,7 +62,6 @@ public class TestPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
@BeforeMethod(groups = "slow")
public void setUp() throws Exception {
account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
- internalCallContext = new InternalCallContext(internalCallContext, 1L);
paymentBusListener = new PaymentBusListener();
eventBus.register(paymentBusListener);
@@ -140,7 +138,7 @@ public class TestPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
final String voidKey = UUID.randomUUID().toString();
final Payment voidTransaction = paymentProcessor.createVoid(true, null, account, paymentId, voidKey,
SHOULD_LOCK_ACCOUNT, PLUGIN_PROPERTIES, callContext, internalCallContext);
- verifyPayment(voidTransaction, paymentExternalKey, TEN, ZERO, ZERO, 2);
+ verifyPayment(voidTransaction, paymentExternalKey, ZERO, ZERO, ZERO, 2);
verifyPaymentTransaction(voidTransaction.getTransactions().get(1), voidKey, TransactionType.VOID, null, paymentId);
paymentBusListener.verify(2, account.getId(), paymentId, null);
}
@@ -243,7 +241,7 @@ public class TestPaymentProcessor extends PaymentTestSuiteWithEmbeddedDB {
Assert.assertEquals(event.getPaymentId(), paymentId);
Assert.assertEquals(event.getAccountId(), accountId);
if (amount == null) {
- Assert.assertEquals(event.getAmount().compareTo(BigDecimal.ZERO), 0);
+ Assert.assertNull(event.getAmount());
} else {
Assert.assertEquals(event.getAmount().compareTo(amount), 0);
}
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
index 13e8891..ac1860e 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
@@ -1,8 +1,8 @@
/*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Groupon licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -21,6 +21,7 @@ import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
+import org.joda.time.DateTimeZone;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
@@ -42,21 +43,21 @@ public class TestDefaultPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
public void testPaymentCRUDForAccount(final UUID accountId, final int accountNb) {
// We need to create specific call contexts to make the account_record_id magic work
- final InternalCallContext accountCallContext = new InternalCallContext(internalCallContext, (long) accountNb);
+ internalCallContext.setAccountRecordId((long) accountNb);
final PaymentModelDao specifiedFirstPaymentModelDao = generatePaymentModelDao(accountId);
final PaymentTransactionModelDao specifiedFirstPaymentTransactionModelDao = generatePaymentTransactionModelDao(specifiedFirstPaymentModelDao.getId());
// Create and verify the payment and transaction
- final PaymentModelDao firstPaymentModelDao = paymentDao.insertPaymentWithFirstTransaction(specifiedFirstPaymentModelDao, specifiedFirstPaymentTransactionModelDao, accountCallContext);
+ final PaymentModelDao firstPaymentModelDao = paymentDao.insertPaymentWithFirstTransaction(specifiedFirstPaymentModelDao, specifiedFirstPaymentTransactionModelDao, internalCallContext);
verifyPayment(firstPaymentModelDao, specifiedFirstPaymentModelDao);
- verifyPaymentAndTransactions(accountCallContext, specifiedFirstPaymentModelDao, specifiedFirstPaymentTransactionModelDao);
+ verifyPaymentAndTransactions(internalCallContext, specifiedFirstPaymentModelDao, specifiedFirstPaymentTransactionModelDao);
// Create a second transaction for the same payment
final PaymentTransactionModelDao specifiedSecondPaymentTransactionModelDao = generatePaymentTransactionModelDao(specifiedFirstPaymentModelDao.getId());
- final PaymentTransactionModelDao secondTransactionModelDao = paymentDao.updatePaymentWithNewTransaction(specifiedFirstPaymentTransactionModelDao.getPaymentId(), specifiedSecondPaymentTransactionModelDao, accountCallContext);
+ final PaymentTransactionModelDao secondTransactionModelDao = paymentDao.updatePaymentWithNewTransaction(specifiedFirstPaymentTransactionModelDao.getPaymentId(), specifiedSecondPaymentTransactionModelDao, internalCallContext);
verifyPaymentTransaction(secondTransactionModelDao, specifiedSecondPaymentTransactionModelDao);
- verifyPaymentAndTransactions(accountCallContext, specifiedFirstPaymentModelDao, specifiedFirstPaymentTransactionModelDao, specifiedSecondPaymentTransactionModelDao);
+ verifyPaymentAndTransactions(internalCallContext, specifiedFirstPaymentModelDao, specifiedFirstPaymentTransactionModelDao, specifiedSecondPaymentTransactionModelDao);
// Update the latest transaction
final BigDecimal processedAmount = new BigDecimal("902341.23232");
@@ -74,9 +75,9 @@ public class TestDefaultPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
processedCurrency,
gatewayErrorCode,
gatewayErrorMsg,
- accountCallContext);
+ internalCallContext);
- final PaymentTransactionModelDao updatedSecondPaymentTransactionModelDao = paymentDao.getPaymentTransaction(specifiedSecondPaymentTransactionModelDao.getId(), accountCallContext);
+ final PaymentTransactionModelDao updatedSecondPaymentTransactionModelDao = paymentDao.getPaymentTransaction(specifiedSecondPaymentTransactionModelDao.getId(), internalCallContext);
Assert.assertEquals(updatedSecondPaymentTransactionModelDao.getTransactionStatus(), TransactionStatus.PAYMENT_FAILURE);
Assert.assertEquals(updatedSecondPaymentTransactionModelDao.getGatewayErrorMsg(), gatewayErrorMsg);
Assert.assertEquals(updatedSecondPaymentTransactionModelDao.getGatewayErrorMsg(), gatewayErrorMsg);
@@ -86,14 +87,14 @@ public class TestDefaultPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
final PaymentModelDao paymentModelDao = generatePaymentModelDao(accountId);
final PaymentTransactionModelDao paymentTransactionModelDao = generatePaymentTransactionModelDao(paymentModelDao.getId());
- final PaymentModelDao insertedPaymentModelDao = paymentDao.insertPaymentWithFirstTransaction(paymentModelDao, paymentTransactionModelDao, accountCallContext);
+ final PaymentModelDao insertedPaymentModelDao = paymentDao.insertPaymentWithFirstTransaction(paymentModelDao, paymentTransactionModelDao, internalCallContext);
verifyPayment(insertedPaymentModelDao, paymentModelDao);
// Verify search APIs
Assert.assertEquals(ImmutableList.<PaymentModelDao>copyOf(paymentDao.searchPayments(paymentModelDao.getPaymentMethodId().toString(), 0L, 100L, internalCallContext).iterator()).size(), 1);
Assert.assertEquals(ImmutableList.<PaymentModelDao>copyOf(paymentDao.searchPayments(paymentModelDao.getExternalKey(), 0L, 100L, internalCallContext).iterator()).size(), 1);
}
- Assert.assertEquals(paymentDao.getPaymentsForAccount(specifiedFirstPaymentModelDao.getAccountId(), accountCallContext).size(), 4);
+ Assert.assertEquals(paymentDao.getPaymentsForAccount(specifiedFirstPaymentModelDao.getAccountId(), internalCallContext).size(), 4);
// Verify search APIs
Assert.assertEquals(ImmutableList.<PaymentModelDao>copyOf(paymentDao.searchPayments(accountId.toString(), 0L, 100L, internalCallContext).iterator()).size(), 4);
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
index 94d024a..d75b656 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -23,6 +25,7 @@ import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
@@ -286,16 +289,14 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
clock.addDays(1);
final DateTime newTime = clock.getUTCNow();
- final InternalCallContext internalCallContextWithNewTime = new InternalCallContext(InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID, 1687L, UUID.randomUUID(),
- UUID.randomUUID().toString(), CallOrigin.TEST,
- UserType.TEST, "Testing", "This is a test",
- newTime, newTime);
+ internalCallContext.setCreatedDate(newTime);
+ internalCallContext.setUpdatedDate(newTime);
final PaymentTransactionModelDao transaction4 = new PaymentTransactionModelDao(initialTime, initialTime, null, transactionExternalKey4,
paymentModelDao.getId(), TransactionType.AUTHORIZE, newTime,
TransactionStatus.PENDING, BigDecimal.TEN, Currency.AED,
"pending", "");
- paymentDao.updatePaymentWithNewTransaction(paymentModelDao.getId(), transaction4, internalCallContextWithNewTime);
+ paymentDao.updatePaymentWithNewTransaction(paymentModelDao.getId(), transaction4, internalCallContext);
final List<PaymentTransactionModelDao> result = getPendingTransactions(paymentModelDao.getId());
Assert.assertEquals(result.size(), 3);
@@ -363,17 +364,10 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- final InternalCallContext context1 = new InternalCallContext(1L,
- 1L,
- internalCallContext.getUserToken(),
- internalCallContext.getCreatedBy(),
- internalCallContext.getCallOrigin(),
- internalCallContext.getContextUserType(),
- internalCallContext.getReasonCode(),
- internalCallContext.getComments(),
- createdDate1,
- createdDate1);
- paymentDao.insertPaymentWithFirstTransaction(paymentModelDao1, transaction1, context1);
+ internalCallContext.setAccountRecordId(1L);
+ internalCallContext.setCreatedDate(createdDate1);
+ internalCallContext.setUpdatedDate(createdDate1);
+ paymentDao.insertPaymentWithFirstTransaction(paymentModelDao1, transaction1, internalCallContext);
// Right after createdAfterDate, so it should be returned
final DateTime createdDate2 = createdAfterDate.plusHours(1);
@@ -384,17 +378,10 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- final InternalCallContext context2 = new InternalCallContext(2L,
- 2L,
- internalCallContext.getUserToken(),
- internalCallContext.getCreatedBy(),
- internalCallContext.getCallOrigin(),
- internalCallContext.getContextUserType(),
- internalCallContext.getReasonCode(),
- internalCallContext.getComments(),
- createdDate2,
- createdDate2);
- paymentDao.insertPaymentWithFirstTransaction(paymentModelDao2, transaction2, context2);
+ internalCallContext.setAccountRecordId(2L);
+ internalCallContext.setCreatedDate(createdDate2);
+ internalCallContext.setUpdatedDate(createdDate2);
+ paymentDao.insertPaymentWithFirstTransaction(paymentModelDao2, transaction2, internalCallContext);
// Right before createdBeforeDate, so it should be returned
final DateTime createdDate3 = createdBeforeDate.minusDays(1);
@@ -405,18 +392,10 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- final InternalCallContext context3 = new InternalCallContext(3L,
- 3L,
- internalCallContext.getUserToken(),
- internalCallContext.getCreatedBy(),
- internalCallContext.getCallOrigin(),
- internalCallContext.getContextUserType(),
- internalCallContext.getReasonCode(),
- internalCallContext.getComments(),
- createdDate3,
- createdDate3);
-
- paymentDao.insertPaymentWithFirstTransaction(paymentModelDao3, transaction3, context3);
+ internalCallContext.setAccountRecordId(3L);
+ internalCallContext.setCreatedDate(createdDate3);
+ internalCallContext.setUpdatedDate(createdDate3);
+ paymentDao.insertPaymentWithFirstTransaction(paymentModelDao3, transaction3, internalCallContext);
// Right before createdBeforeDate but with a SUCCESS state so it should NOT be returned
final DateTime createdDate4 = createdBeforeDate.minusDays(1);
@@ -427,18 +406,10 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- final InternalCallContext context4 = new InternalCallContext(4L,
- 4L,
- internalCallContext.getUserToken(),
- internalCallContext.getCreatedBy(),
- internalCallContext.getCallOrigin(),
- internalCallContext.getContextUserType(),
- internalCallContext.getReasonCode(),
- internalCallContext.getComments(),
- createdDate4,
- createdDate4);
-
- paymentDao.insertPaymentWithFirstTransaction(paymentModelDao4, transaction4, context4);
+ internalCallContext.setAccountRecordId(4L);
+ internalCallContext.setCreatedDate(createdDate4);
+ internalCallContext.setUpdatedDate(createdDate4);
+ paymentDao.insertPaymentWithFirstTransaction(paymentModelDao4, transaction4, internalCallContext);
// Right after createdBeforeDate, so it should NOT be returned
final DateTime createdDate5 = createdBeforeDate.plusDays(1);
@@ -449,18 +420,10 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- final InternalCallContext context5 = new InternalCallContext(5L,
- 5L,
- internalCallContext.getUserToken(),
- internalCallContext.getCreatedBy(),
- internalCallContext.getCallOrigin(),
- internalCallContext.getContextUserType(),
- internalCallContext.getReasonCode(),
- internalCallContext.getComments(),
- createdDate5,
- createdDate5);
-
- paymentDao.insertPaymentWithFirstTransaction(paymentModelDao5, transaction5, context5);
+ internalCallContext.setAccountRecordId(5L);
+ internalCallContext.setCreatedDate(createdDate5);
+ internalCallContext.setUpdatedDate(createdDate5);
+ paymentDao.insertPaymentWithFirstTransaction(paymentModelDao5, transaction5, internalCallContext);
final String[] errorStates = {"AUTH_ERRORED", "CAPTURE_ERRORED", "REFUND_ERRORED", "CREDIT_ERRORED"};
final List<PaymentModelDao> result = paymentDao.getPaymentsByStatesAcrossTenants(errorStates, createdBeforeDate, createdAfterDate, 10);
@@ -480,17 +443,10 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- final InternalCallContext context1 = new InternalCallContext(1L,
- 1L,
- internalCallContext.getUserToken(),
- internalCallContext.getCreatedBy(),
- internalCallContext.getCallOrigin(),
- internalCallContext.getContextUserType(),
- internalCallContext.getReasonCode(),
- internalCallContext.getComments(),
- createdDate1,
- createdDate1);
- paymentDao.insertPaymentWithFirstTransaction(paymentModelDao1, transaction1, context1);
+ internalCallContext.setAccountRecordId(1L);
+ internalCallContext.setCreatedDate(createdDate1);
+ internalCallContext.setUpdatedDate(createdDate1);
+ paymentDao.insertPaymentWithFirstTransaction(paymentModelDao1, transaction1, internalCallContext);
}
final Pagination<PaymentTransactionModelDao> result = paymentDao.getByTransactionStatusAcrossTenants(ImmutableList.of(TransactionStatus.UNKNOWN), clock.getUTCNow(), createdDate1, 0L, new Long(NB_ENTRIES));
@@ -529,29 +485,15 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
UUID.randomUUID(), transactionExternalKey2, TransactionType.AUTHORIZE, stateName, BigDecimal.ONE, Currency.USD,
ImmutableList.<String>of(pluginName), null);
- final InternalCallContext context1 = new InternalCallContext(1L,
- 1L,
- internalCallContext.getUserToken(),
- internalCallContext.getCreatedBy(),
- internalCallContext.getCallOrigin(),
- internalCallContext.getContextUserType(),
- internalCallContext.getReasonCode(),
- internalCallContext.getComments(),
- createdAfterDate,
- createdAfterDate);
- paymentDao.insertPaymentAttemptWithProperties(attempt1, context1);
-
- final InternalCallContext context2 = new InternalCallContext(2L,
- 2L,
- internalCallContext.getUserToken(),
- internalCallContext.getCreatedBy(),
- internalCallContext.getCallOrigin(),
- internalCallContext.getContextUserType(),
- internalCallContext.getReasonCode(),
- internalCallContext.getComments(),
- createdAfterDate,
- createdAfterDate);
- paymentDao.insertPaymentAttemptWithProperties(attempt2, context2);
+ internalCallContext.setAccountRecordId(1L);
+ internalCallContext.setCreatedDate(createdAfterDate);
+ internalCallContext.setUpdatedDate(createdAfterDate);
+ paymentDao.insertPaymentAttemptWithProperties(attempt1, internalCallContext);
+
+ internalCallContext.setAccountRecordId(2L);
+ internalCallContext.setCreatedDate(createdAfterDate);
+ internalCallContext.setUpdatedDate(createdAfterDate);
+ paymentDao.insertPaymentAttemptWithProperties(attempt2, internalCallContext);
final Pagination<PaymentAttemptModelDao> result = paymentDao.getPaymentAttemptsByStateAcrossTenants(stateName, createdBeforeDate, 0L, 2L);
Assert.assertEquals(result.getTotalNbRecords().longValue(), 2L);
diff --git a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
index 14072c3..dc7b36f 100644
--- a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
@@ -34,6 +34,7 @@ import org.killbill.billing.payment.plugin.api.PaymentPluginApi;
import org.killbill.billing.payment.provider.MockPaymentProviderPlugin;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.util.config.PaymentConfig;
+import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.bus.api.PersistentBus;
import org.killbill.commons.profiling.Profiling;
import org.testng.annotations.AfterMethod;
@@ -73,6 +74,8 @@ public abstract class PaymentTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
protected TestPaymentHelper testHelper;
@Inject
protected PaymentExecutors paymentExecutors;
+ @Inject
+ protected NonEntityDao nonEntityDao;
@Override
protected KillbillConfigSource getConfigSource() {
diff --git a/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentProviderPlugin.java b/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentProviderPlugin.java
index cc8c6e1..d6fb5f3 100644
--- a/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentProviderPlugin.java
+++ b/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentProviderPlugin.java
@@ -68,9 +68,10 @@ public class MockPaymentProviderPlugin implements PaymentPluginApi {
public static final String PLUGIN_NAME = "__NO_OP__";
- private final AtomicBoolean makeNextInvoiceFailWithError = new AtomicBoolean(false);
- private final AtomicBoolean makeNextInvoiceFailWithException = new AtomicBoolean(false);
- private final AtomicBoolean makeAllInvoicesFailWithError = new AtomicBoolean(false);
+ private final AtomicBoolean makeNextPaymentFailWithError = new AtomicBoolean(false);
+ private final AtomicBoolean makeNextPaymentFailWithCancellation = new AtomicBoolean(false);
+ private final AtomicBoolean makeNextPaymentFailWithException = new AtomicBoolean(false);
+ private final AtomicBoolean makeAllPaymentsFailWithError = new AtomicBoolean(false);
private final AtomicInteger makePluginWaitSomeMilliseconds = new AtomicInteger(0);
private final AtomicReference<BigDecimal> overrideNextProcessedAmount = new AtomicReference<BigDecimal>();
private final AtomicReference<Currency> overrideNextProcessedCurrency = new AtomicReference<Currency>();
@@ -194,9 +195,10 @@ public class MockPaymentProviderPlugin implements PaymentPluginApi {
}
public void clear() {
- makeNextInvoiceFailWithException.set(false);
- makeAllInvoicesFailWithError.set(false);
- makeNextInvoiceFailWithError.set(false);
+ makeNextPaymentFailWithException.set(false);
+ makeAllPaymentsFailWithError.set(false);
+ makeNextPaymentFailWithError.set(false);
+ makeNextPaymentFailWithCancellation.set(false);
makePluginWaitSomeMilliseconds.set(0);
overrideNextProcessedAmount.set(null);
paymentMethods.clear();
@@ -206,15 +208,19 @@ public class MockPaymentProviderPlugin implements PaymentPluginApi {
}
public void makeNextPaymentFailWithError() {
- makeNextInvoiceFailWithError.set(true);
+ makeNextPaymentFailWithError.set(true);
+ }
+
+ public void makeNextPaymentFailWithCancellation() {
+ makeNextPaymentFailWithCancellation.set(true);
}
public void makeNextPaymentFailWithException() {
- makeNextInvoiceFailWithException.set(true);
+ makeNextPaymentFailWithException.set(true);
}
public void makeAllInvoicesFailWithError(final boolean failure) {
- makeAllInvoicesFailWithError.set(failure);
+ makeAllPaymentsFailWithError.set(failure);
}
public void makePluginWaitSomeMilliseconds(final int milliseconds) {
@@ -255,7 +261,7 @@ public class MockPaymentProviderPlugin implements PaymentPluginApi {
@Override
public PaymentTransactionInfoPlugin voidPayment(final UUID kbAccountId, final UUID kbPaymentId, final UUID kbTransactionId, final UUID kbPaymentMethodId, final Iterable<PluginProperty> properties, final CallContext context)
throws PaymentPluginApiException {
- return getPaymentTransactionInfoPluginResult(kbPaymentId, kbTransactionId, TransactionType.VOID, BigDecimal.ZERO, null, properties);
+ return getPaymentTransactionInfoPluginResult(kbPaymentId, kbTransactionId, TransactionType.VOID, null, null, properties);
}
@Override
@@ -358,7 +364,7 @@ public class MockPaymentProviderPlugin implements PaymentPluginApi {
return getPaymentTransactionInfoPluginResult(kbPaymentId, kbTransactionId, TransactionType.REFUND, refundAmount, currency, properties);
}
- private PaymentTransactionInfoPlugin getPaymentTransactionInfoPluginResult(final UUID kbPaymentId, final UUID kbTransactionId, final TransactionType type, final BigDecimal amount, @Nullable final Currency currency, final Iterable<PluginProperty> pluginProperties) throws PaymentPluginApiException {
+ private PaymentTransactionInfoPlugin getPaymentTransactionInfoPluginResult(final UUID kbPaymentId, final UUID kbTransactionId, final TransactionType type, @Nullable final BigDecimal amount, @Nullable final Currency currency, final Iterable<PluginProperty> pluginProperties) throws PaymentPluginApiException {
if (makePluginWaitSomeMilliseconds.get() > 0) {
try {
Thread.sleep(makePluginWaitSomeMilliseconds.get());
@@ -368,7 +374,7 @@ public class MockPaymentProviderPlugin implements PaymentPluginApi {
}
}
- if (makeNextInvoiceFailWithException.getAndSet(false)) {
+ if (makeNextPaymentFailWithException.getAndSet(false)) {
throw new PaymentPluginApiException("", "test error");
}
@@ -382,8 +388,12 @@ public class MockPaymentProviderPlugin implements PaymentPluginApi {
final PaymentPluginStatus status;
if (paymentPluginStatusOverride != null && paymentPluginStatusOverride.getValue() != null) {
status = PaymentPluginStatus.valueOf(paymentPluginStatusOverride.getValue().toString());
+ } else if (makeAllPaymentsFailWithError.get() || makeNextPaymentFailWithError.getAndSet(false)) {
+ status = PaymentPluginStatus.ERROR;
+ } else if (makeNextPaymentFailWithCancellation.getAndSet(false)) {
+ status = PaymentPluginStatus.CANCELED;
} else {
- status = (makeAllInvoicesFailWithError.get() || makeNextInvoiceFailWithError.getAndSet(false)) ? PaymentPluginStatus.ERROR : PaymentPluginStatus.PROCESSED;
+ status = PaymentPluginStatus.PROCESSED;
}
final String errorCode = status == PaymentPluginStatus.PROCESSED ? "" : GATEWAY_ERROR_CODE;
final String error = status == PaymentPluginStatus.PROCESSED ? "" : GATEWAY_ERROR;
@@ -394,7 +404,8 @@ public class MockPaymentProviderPlugin implements PaymentPluginApi {
payments.put(kbPaymentId.toString(), info);
}
- final BigDecimal processedAmount = MoreObjects.firstNonNull(overrideNextProcessedAmount.getAndSet(null), amount);
+ final BigDecimal overrideNextProcessedAmount = this.overrideNextProcessedAmount.getAndSet(null);
+ final BigDecimal processedAmount = overrideNextProcessedAmount != null ? overrideNextProcessedAmount : amount;
Currency processedCurrency = overrideNextProcessedCurrency.getAndSet(null);
if (processedCurrency == null) {
processedCurrency = currency;
diff --git a/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java b/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java
index 0ba6343..ccf0a1c 100644
--- a/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java
+++ b/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java
@@ -288,7 +288,6 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
testListener.assertListenerStatus();
// Artificially move the transaction status to UNKNOWN
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
final String paymentStateName = paymentSMHelper.getErroredStateForTransaction(TransactionType.AUTHORIZE).toString();
testListener.pushExpectedEvent(NextEvent.PAYMENT_PLUGIN_ERROR);
paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
@@ -321,7 +320,6 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
testListener.assertListenerStatus();
// Artificially move the transaction status to UNKNOWN
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
final String paymentStateName = paymentSMHelper.getErroredStateForTransaction(TransactionType.AUTHORIZE).toString();
testListener.pushExpectedEvent(NextEvent.PAYMENT_PLUGIN_ERROR);
paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
@@ -367,8 +365,6 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
final Payment payment = paymentApi.getPaymentByExternalKey(paymentExternalKey, false, ImmutableList.<PluginProperty>of(), callContext);
// Artificially move the transaction status to UNKNOWN
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
-
final String paymentStateName = paymentSMHelper.getErroredStateForTransaction(TransactionType.AUTHORIZE).toString();
testListener.pushExpectedEvent(NextEvent.PAYMENT_PLUGIN_ERROR);
paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
@@ -401,8 +397,6 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
transactionExternalKey, ImmutableList.<PluginProperty>of(), callContext);
testListener.assertListenerStatus();
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
-
// Artificially move the transaction status to PENDING
final String paymentStateName = paymentSMHelper.getPendingStateForTransaction(TransactionType.AUTHORIZE).toString();
testListener.pushExpectedEvent(NextEvent.PAYMENT);
@@ -434,8 +428,6 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
transactionExternalKey, ImmutableList.<PluginProperty>of(), callContext);
testListener.assertListenerStatus();
- final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
-
// Artificially move the transaction status to PENDING AND update state on the plugin as well
final List<PaymentTransactionInfoPlugin> paymentTransactions = mockPaymentProviderPlugin.getPaymentInfo(account.getId(), payment.getId(), ImmutableList.<PluginProperty>of(), callContext);
final PaymentTransactionInfoPlugin oTx = paymentTransactions.remove(0);
diff --git a/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java b/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
index 2aaa167..f32c37e 100644
--- a/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
+++ b/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
@@ -21,11 +21,13 @@ package org.killbill.billing.payment;
import java.util.UUID;
import org.joda.time.LocalDate;
+import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.account.api.AccountUserApi;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.callcontext.MutableInternalCallContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.dao.MockNonEntityDao;
import org.killbill.billing.events.InvoiceCreationInternalEvent;
@@ -38,7 +40,10 @@ import org.killbill.billing.payment.api.PaymentMethodPlugin;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.provider.DefaultNoOpPaymentMethodPlugin;
import org.killbill.billing.payment.provider.MockPaymentProviderPlugin;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.bus.api.PersistentBus;
import org.killbill.bus.api.PersistentBus.EventBusException;
import org.killbill.clock.Clock;
@@ -55,8 +60,10 @@ public class TestPaymentHelper {
protected PaymentApi paymentApi;
private final PersistentBus eventBus;
private final Clock clock;
+ private final NonEntityDao nonEntityDao;
private final MockNonEntityDao mockNonEntityDao;
- private final InternalCallContext internalCallContext;
+ private final CacheControllerDispatcher cacheControllerDispatcher;
+ private final MutableInternalCallContext internalCallContext;
private final CallContext context;
@Inject
@@ -66,8 +73,10 @@ public class TestPaymentHelper {
final PaymentApi paymentApi,
final PersistentBus eventBus,
final Clock clock,
+ final NonEntityDao nonEntityDao,
final MockNonEntityDao mockNonEntityDao,
- final InternalCallContext internalCallContext,
+ final CacheControllerDispatcher cacheControllerDispatcher,
+ final MutableInternalCallContext internalCallContext,
final CallContext context) {
this.accountApi = accountApi;
this.eventBus = eventBus;
@@ -75,7 +84,9 @@ public class TestPaymentHelper {
this.invoiceApi = invoiceApi;
this.paymentApi = paymentApi;
this.clock = clock;
+ this.nonEntityDao = nonEntityDao;
this.mockNonEntityDao = mockNonEntityDao;
+ this.cacheControllerDispatcher = cacheControllerDispatcher;
this.internalCallContext = internalCallContext;
this.context = context;
}
@@ -140,8 +151,13 @@ public class TestPaymentHelper {
mockNonEntityDao.addAccountRecordIdMapping(account.getId(), internalCallContext);
} else {
account = accountApi.createAccount(accountData, context);
+
+ final Long accountRecordId = nonEntityDao.retrieveRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
+ internalCallContext.setAccountRecordId(accountRecordId);
}
+ internalCallContext.setReferenceDateTimeZone(account.getTimeZone());
+
if (addPaymentMethod) {
final PaymentMethodPlugin pm = new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), true, null);
account = addTestPaymentMethod(account, pm);
diff --git a/payment/src/test/java/org/killbill/billing/payment/TestRetryService.java b/payment/src/test/java/org/killbill/billing/payment/TestRetryService.java
index f289f57..b5462f5 100644
--- a/payment/src/test/java/org/killbill/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/org/killbill/billing/payment/TestRetryService.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -75,7 +75,6 @@ public class TestRetryService extends PaymentTestSuiteNoDB {
mockPaymentProviderPlugin.clear();
retryService.initialize();
retryService.start();
-
}
@Override
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index b2ad9be..60d9ae1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
<parent>
<artifactId>killbill-oss-parent</artifactId>
<groupId>org.kill-bill.billing</groupId>
- <version>0.83</version>
+ <version>0.86</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.16.3-SNAPSHOT</version>
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java b/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
index 3c6c6ce..7f2a2bb 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
@@ -131,6 +131,8 @@ public class TenantFilter implements Filter {
isTenantCreationRequest(path, httpMethod) ||
// Retrieve user permissions should not require tenant info since this is cross tenants
isPermissionRequest(path, httpMethod) ||
+ // Node request are cross tenant
+ isNodeCreationRequest(path, httpMethod) ||
// Metrics servlets
isMetricsRequest(path, httpMethod) ||
// See KillBillShiroWebModule#CorsBasicHttpAuthenticationFilter
@@ -157,6 +159,10 @@ public class TenantFilter implements Filter {
return JaxrsResource.TENANTS_PATH.equals(path) && "POST".equals(httpMethod);
}
+ private boolean isNodeCreationRequest(final String path, final String httpMethod) {
+ return JaxrsResource.NODES_INFO_PATH.equals(path) && "POST".equals(httpMethod);
+ }
+
private boolean isMetricsRequest(final String path, final String httpMethod) {
return KillbillGuiceListener.METRICS_SERVLETS_PATHS.contains(path) && "GET".equals(httpMethod);
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java
index e9bc2be..fbc8a31 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -74,12 +74,7 @@ public class TestBundle extends TestJaxrsBase {
public void testBundleNonExistent() throws Exception {
final Account accountJson = createAccount();
- try {
- killBillClient.getBundle(UUID.randomUUID());
- Assert.fail();
- } catch (final KillBillClientException e) {
- Assert.assertEquals(e.getBillingException().getClassName(), "org.killbill.billing.util.callcontext.InternalCallContextFactory$ObjectDoesNotExist");
- }
+ Assert.assertNull(killBillClient.getBundle(UUID.randomUUID()));
Assert.assertTrue(killBillClient.getAccountBundles(accountJson.getAccountId(), "98374982743892").isEmpty());
Assert.assertTrue(killBillClient.getAccountBundles(accountJson.getAccountId()).isEmpty());
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCredit.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCredit.java
index 5bc85f0..48c3748 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCredit.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCredit.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -26,7 +26,6 @@ import org.killbill.billing.client.KillBillClientException;
import org.killbill.billing.client.model.Account;
import org.killbill.billing.client.model.Credit;
import org.killbill.billing.client.model.Invoice;
-import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -88,11 +87,6 @@ public class TestCredit extends TestJaxrsBase {
@Test(groups = "slow", description = "Cannot retrieve a non existing credit")
public void testCreditDoesNotExist() throws Exception {
- try {
- killBillClient.getCredit(UUID.randomUUID());
- Assert.fail();
- } catch (final KillBillClientException e) {
- Assert.assertEquals(e.getBillingException().getClassName(), "org.killbill.billing.util.callcontext.InternalCallContextFactory$ObjectDoesNotExist");
- }
+ assertNull(killBillClient.getCredit(UUID.randomUUID()));
}
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
index c795c16..1d3cb3f 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
@@ -145,26 +145,11 @@ public class TestEntitlement extends TestJaxrsBase {
subscription.setBillingPeriod(BillingPeriod.ANNUAL);
subscription.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
- try {
- killBillClient.updateSubscription(subscription, CALL_COMPLETION_TIMEOUT_SEC, createdBy, reason, comment);
- Assert.fail();
- } catch (final KillBillClientException e) {
- Assert.assertEquals(e.getBillingException().getClassName(), "org.killbill.billing.util.callcontext.InternalCallContextFactory$ObjectDoesNotExist");
- }
-
- try {
- killBillClient.cancelSubscription(subscriptionId, createdBy, reason, comment);
- Assert.fail();
- } catch (final KillBillClientException e) {
- Assert.assertEquals(e.getBillingException().getClassName(), "org.killbill.billing.util.callcontext.InternalCallContextFactory$ObjectDoesNotExist");
- }
-
- try {
- killBillClient.getSubscription(subscriptionId);
- Assert.fail();
- } catch (final KillBillClientException e) {
- Assert.assertEquals(e.getBillingException().getClassName(), "org.killbill.billing.util.callcontext.InternalCallContextFactory$ObjectDoesNotExist");
- }
+ assertNull(killBillClient.updateSubscription(subscription, CALL_COMPLETION_TIMEOUT_SEC, createdBy, reason, comment));
+
+ killBillClient.cancelSubscription(subscriptionId, createdBy, reason, comment);
+
+ assertNull(killBillClient.getSubscription(subscriptionId));
}
@Test(groups = "slow", description = "Can override billing policy on change")
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
index 4457006..3d52e07 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -91,6 +91,105 @@ public class TestInvoice extends TestJaxrsBase {
final Invoice firstInvoiceByNumberJson = killBillClient.getInvoice(invoiceJson.getInvoiceNumber());
assertEquals(firstInvoiceByNumberJson, invoiceJson);
+ // Check we can retrieve the HTML version
+ final String htmlInvoice = killBillClient.getInvoiceAsHtml(invoiceJson.getInvoiceId());
+ assertEquals(htmlInvoice, "<html>\n" +
+ " <head>\n" +
+ " <style type=\"text/css\">\n" +
+ " th {align=left; width=225px; border-bottom: solid 2px black;}\n" +
+ " </style>\n" +
+ " </head>\n" +
+ " <body>\n" +
+ " <h1>invoiceTitle</h1>\n" +
+ " <table>\n" +
+ " <tr>\n" +
+ " <td rowspan=3 width=350px>Insert image here</td>\n" +
+ " <td width=100px/>\n" +
+ " <td width=225px/>\n" +
+ " <td width=225px/>\n" +
+ " </tr>\n" +
+ " <tr>\n" +
+ " <td />\n" +
+ " <td align=right>invoiceDate</td>\n" +
+ " <td>25 avr. 2012</td>\n" +
+ " </tr>\n" +
+ " <tr>\n" +
+ " <td />\n" +
+ " <td align=right>invoiceNumber</td>\n" +
+ " <td>1</td>\n" +
+ " </tr>\n" +
+ " <tr>\n" +
+ " <td>companyName</td>\n" +
+ " <td></td>\n" +
+ " <td align=right>accountOwnerName</td>\n" +
+ " <td>" + accountJson.getName() + "</td>\n" +
+ " </tr>\n" +
+ " <tr>\n" +
+ " <td>companyAddress</td>\n" +
+ " <td />\n" +
+ " <td />\n" +
+ " <td>" + accountJson.getEmail() + "</td>\n" +
+ " </tr>\n" +
+ " <tr>\n" +
+ " <td>companyCityProvincePostalCode</td>\n" +
+ " <td />\n" +
+ " <td />\n" +
+ " <td>" + accountJson.getPhone() + "</td>\n" +
+ " </tr>\n" +
+ " <tr>\n" +
+ " <td>companyCountry</td>\n" +
+ " <td />\n" +
+ " <td />\n" +
+ " <td />\n" +
+ " </tr>\n" +
+ " <tr>\n" +
+ " <td><companyUrl</td>\n" +
+ " <td />\n" +
+ " <td />\n" +
+ " <td />\n" +
+ " </tr>\n" +
+ " </table>\n" +
+ " <br />\n" +
+ " <br />\n" +
+ " <br />\n" +
+ " <table>\n" +
+ " <tr>\n" +
+ " <th>invoiceItemBundleName</td>\n" +
+ " <th>invoiceItemDescription</td>\n" +
+ " <th>invoiceItemServicePeriod</td>\n" +
+ " <th>invoiceItemAmount</td>\n" +
+ " </tr>\n" +
+ " \n" +
+ " <tr>\n" +
+ " <td>shotgun-monthly-trial</td>\n" +
+ " <td>Monthly shotgun plan</td>\n" +
+ " <td>25 avr. 2012</td>\n" +
+ " <td>USD 0E-9</td>\n" +
+ " </tr>\n" +
+ " \n" +
+ " <tr>\n" +
+ " <td colspan=4 />\n" +
+ " </tr>\n" +
+ " <tr>\n" +
+ " <td colspan=2 />\n" +
+ " <td align=right><strong>invoiceAmount</strong></td>\n" +
+ " <td align=right><strong>0.00</strong></td>\n" +
+ " </tr>\n" +
+ " <tr>\n" +
+ " <td colspan=2 />\n" +
+ " <td align=right><strong>invoiceAmountPaid</strong></td>\n" +
+ " <td align=right><strong>0</strong></td>\n" +
+ " </tr>\n" +
+ " <tr>\n" +
+ " <td colspan=2 />\n" +
+ " <td align=right><strong>invoiceBalance</strong></td>\n" +
+ " <td align=right><strong>0.00</strong></td>\n" +
+ " </tr>\n" +
+ " </table>\n" +
+ " </body>\n" +
+ "</html>\n" +
+ "\n");
+
// Then create a dryRun for next upcoming invoice
final InvoiceDryRun dryRunArg = new InvoiceDryRun(DryRunType.UPCOMING_INVOICE, null,
null, null, null, null, null, null, null, null, null, null);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestUsage.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestUsage.java
new file mode 100644
index 0000000..2e9dd6a
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestUsage.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.jaxrs;
+
+import java.util.UUID;
+
+import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.PriceListSet;
+import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.client.model.Account;
+import org.killbill.billing.client.model.Bundle;
+import org.killbill.billing.client.model.RolledUpUsage;
+import org.killbill.billing.client.model.Subscription;
+import org.killbill.billing.client.model.SubscriptionUsageRecord;
+import org.killbill.billing.client.model.UnitUsageRecord;
+import org.killbill.billing.client.model.UsageRecord;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class TestUsage extends TestJaxrsBase {
+
+ @Test(groups = "slow", description = "Can record and retrieve usage data")
+ public void testRecordUsage() throws Exception {
+ final Account accountJson = createAccountWithDefaultPaymentMethod();
+
+ final Subscription base = new Subscription();
+ base.setAccountId(accountJson.getAccountId());
+ base.setProductName("Pistol");
+ base.setProductCategory(ProductCategory.BASE);
+ base.setBillingPeriod(BillingPeriod.MONTHLY);
+ base.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
+
+ final Subscription addOn = new Subscription();
+ addOn.setAccountId(accountJson.getAccountId());
+ addOn.setProductName("Bullets");
+ addOn.setProductCategory(ProductCategory.ADD_ON);
+ addOn.setBillingPeriod(BillingPeriod.NO_BILLING_PERIOD);
+ addOn.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
+
+ final Bundle bundle = killBillClient.createSubscriptionWithAddOns(ImmutableList.<Subscription>of(base, addOn),
+ null,
+ DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC,
+ createdBy,
+ reason,
+ comment);
+ final UUID addOnSubscriptionId = Iterables.<Subscription>find(bundle.getSubscriptions(),
+ new Predicate<Subscription>() {
+ @Override
+ public boolean apply(final Subscription input) {
+ return ProductCategory.ADD_ON.equals(input.getProductCategory());
+ }
+ }).getSubscriptionId();
+
+ clock.addDays(1);
+
+ final UsageRecord usageRecord1 = new UsageRecord();
+ usageRecord1.setAmount(10L);
+ usageRecord1.setRecordDate(clock.getUTCToday().minusDays(1));
+
+ final UsageRecord usageRecord2 = new UsageRecord();
+ usageRecord2.setAmount(5L);
+ usageRecord2.setRecordDate(clock.getUTCToday());
+
+ final UnitUsageRecord unitUsageRecord = new UnitUsageRecord();
+ unitUsageRecord.setUnitType("bullets");
+ unitUsageRecord.setUsageRecords(ImmutableList.<UsageRecord>of(usageRecord1, usageRecord2));
+
+ final SubscriptionUsageRecord usage = new SubscriptionUsageRecord();
+ usage.setSubscriptionId(addOnSubscriptionId);
+ usage.setUnitUsageRecords(ImmutableList.<UnitUsageRecord>of(unitUsageRecord));
+
+ killBillClient.createSubscriptionUsageRecord(usage, createdBy, reason, comment);
+
+ final RolledUpUsage retrievedUsage1 = killBillClient.getRolledUpUsage(addOnSubscriptionId, unitUsageRecord.getUnitType(), clock.getUTCToday().minusDays(1), clock.getUTCToday());
+ Assert.assertEquals(retrievedUsage1.getSubscriptionId(), usage.getSubscriptionId());
+ Assert.assertEquals(retrievedUsage1.getRolledUpUnits().size(), 1);
+ Assert.assertEquals(retrievedUsage1.getRolledUpUnits().get(0).getUnitType(), unitUsageRecord.getUnitType());
+ // endDate is excluded
+ Assert.assertEquals((long) retrievedUsage1.getRolledUpUnits().get(0).getAmount(), 10);
+
+ final RolledUpUsage retrievedUsage2 = killBillClient.getRolledUpUsage(addOnSubscriptionId, unitUsageRecord.getUnitType(), clock.getUTCToday().minusDays(1), clock.getUTCToday().plusDays(1));
+ Assert.assertEquals(retrievedUsage2.getSubscriptionId(), usage.getSubscriptionId());
+ Assert.assertEquals(retrievedUsage2.getRolledUpUnits().size(), 1);
+ Assert.assertEquals(retrievedUsage2.getRolledUpUnits().get(0).getUnitType(), unitUsageRecord.getUnitType());
+ Assert.assertEquals((long) retrievedUsage2.getRolledUpUnits().get(0).getAmount(), 15);
+
+ final RolledUpUsage retrievedUsage3 = killBillClient.getRolledUpUsage(addOnSubscriptionId, unitUsageRecord.getUnitType(), clock.getUTCToday(), clock.getUTCToday().plusDays(1));
+ Assert.assertEquals(retrievedUsage3.getSubscriptionId(), usage.getSubscriptionId());
+ Assert.assertEquals(retrievedUsage3.getRolledUpUnits().size(), 1);
+ Assert.assertEquals(retrievedUsage3.getRolledUpUnits().get(0).getUnitType(), unitUsageRecord.getUnitType());
+ Assert.assertEquals((long) retrievedUsage3.getRolledUpUnits().get(0).getAmount(), 5);
+
+ final RolledUpUsage retrievedUsage4 = killBillClient.getRolledUpUsage(addOnSubscriptionId, null, clock.getUTCToday(), clock.getUTCToday().plusDays(1));
+ Assert.assertEquals(retrievedUsage4.getSubscriptionId(), usage.getSubscriptionId());
+ Assert.assertEquals(retrievedUsage4.getRolledUpUnits().size(), 1);
+ Assert.assertEquals(retrievedUsage4.getRolledUpUnits().get(0).getUnitType(), "bullets");
+ Assert.assertEquals((long) retrievedUsage4.getRolledUpUnits().get(0).getAmount(), 5);
+ }
+}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/ServerTestSuiteNoDB.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/ServerTestSuiteNoDB.java
index f2328af..7bdf408 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/server/log/ServerTestSuiteNoDB.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/ServerTestSuiteNoDB.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -17,7 +17,18 @@
package org.killbill.billing.server.log;
+import org.killbill.billing.GuicyKillbillTestModule;
import org.killbill.billing.GuicyKillbillTestSuiteNoDB;
+import org.testng.annotations.BeforeClass;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
public abstract class ServerTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
+
+ @BeforeClass(groups = "fast")
+ protected void beforeClass() throws Exception {
+ final Injector injector = Guice.createInjector(new GuicyKillbillTestModule(configSource));
+ injector.injectMembers(this);
+ }
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestKillbillJdbcTenantRealm.java b/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestKillbillJdbcTenantRealm.java
index a82fe1e..b5b51ce 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestKillbillJdbcTenantRealm.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/security/TestKillbillJdbcTenantRealm.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -30,7 +30,9 @@ import org.killbill.billing.jaxrs.TestJaxrsBase;
import org.killbill.billing.tenant.api.DefaultTenant;
import org.killbill.billing.tenant.dao.DefaultTenantDao;
import org.killbill.billing.tenant.dao.TenantModelDao;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.DefaultNonEntityDao;
+import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -49,7 +51,7 @@ public class TestKillbillJdbcTenantRealm extends TestJaxrsBase {
super.beforeMethod();
// Create the tenant
- final DefaultTenantDao tenantDao = new DefaultTenantDao(dbi, clock, cacheControllerDispatcher, new DefaultNonEntityDao(dbi), securityConfig);
+ final DefaultTenantDao tenantDao = new DefaultTenantDao(dbi, clock, cacheControllerDispatcher, new DefaultNonEntityDao(dbi), Mockito.mock(InternalCallContextFactory.class), securityConfig);
tenant = new DefaultTenant(UUID.randomUUID(), null, null, UUID.randomUUID().toString(),
UUID.randomUUID().toString(), UUID.randomUUID().toString());
tenantDao.create(new TenantModelDao(tenant), internalCallContext);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index 1e6c118..16e6090 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -78,6 +78,7 @@ import org.killbill.billing.subscription.events.user.ApiEventType;
import org.killbill.billing.subscription.exceptions.SubscriptionBaseError;
import org.killbill.billing.util.UUIDs;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.Pagination;
import org.killbill.billing.util.entity.dao.DefaultPaginationSqlDaoHelper.PaginationIteratorBuilder;
@@ -118,8 +119,8 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
@Inject
public DefaultSubscriptionDao(final IDBI dbi, final Clock clock, final AddonUtils addonUtils,
final NotificationQueueService notificationQueueService, final PersistentBus eventBus, final CatalogService catalogService,
- final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), BundleSqlDao.class);
+ final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), BundleSqlDao.class);
this.clock = clock;
this.notificationQueueService = notificationQueueService;
this.addonUtils = addonUtils;
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/TestEventJson.java b/subscription/src/test/java/org/killbill/billing/subscription/api/TestEventJson.java
index 90b3822..cee8006 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/TestEventJson.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/TestEventJson.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -19,16 +21,15 @@ package org.killbill.billing.subscription.api;
import java.util.UUID;
import org.joda.time.DateTime;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import org.killbill.billing.GuicyKillbillTestSuiteNoDB;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
-import org.killbill.billing.subscription.api.user.DefaultEffectiveSubscriptionEvent;
import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
+import org.killbill.billing.subscription.SubscriptionTestSuiteNoDB;
+import org.killbill.billing.subscription.api.user.DefaultEffectiveSubscriptionEvent;
import org.killbill.billing.util.jackson.ObjectMapper;
+import org.testng.Assert;
+import org.testng.annotations.Test;
-public class TestEventJson extends GuicyKillbillTestSuiteNoDB {
+public class TestEventJson extends SubscriptionTestSuiteNoDB {
private final ObjectMapper mapper = new ObjectMapper();
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
index 6483634..721183d 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -22,6 +22,7 @@ import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
+import org.killbill.billing.account.api.AccountInternalApi;
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
@@ -64,10 +65,9 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
super.beforeMethod();
final NonEntityDao nonEntityDao = Mockito.mock(NonEntityDao.class);
final SubscriptionDao dao = Mockito.mock(SubscriptionDao.class);
- final CatalogService catalogService = new MockCatalogService(new MockCatalog(), cacheControllerDispatcher);
+ final CatalogService catalogService = new MockCatalogService(new MockCatalog(), cacheControllerDispatcher);
final SubscriptionBaseApiService apiService = Mockito.mock(SubscriptionBaseApiService.class);
final SubscriptionBaseTimelineApi timelineApi = Mockito.mock(SubscriptionBaseTimelineApi.class);
- final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(clock, nonEntityDao, new CacheControllerDispatcher());
transferApi = new DefaultSubscriptionBaseTransferApi(clock, dao, timelineApi, catalogService, apiService, internalCallContextFactory);
}
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java
index 4751213..cce6cb0 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java
@@ -61,12 +61,14 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
// Note: this will cleanup all tables
super.beforeMethod();
- final AccountData accountData = subscriptionTestInitializer.initAccountData();
- final Account account = accountUserApi.createAccount(accountData, callContext);
- newAccountId = account.getId();
final AccountData accountData2 = subscriptionTestInitializer.initAccountData();
- final Account account2 = accountUserApi.createAccount(accountData2, callContext);
+ final Account account2 = createAccount(accountData2);
finalNewAccountId = account2.getId();
+
+ // internal context will be configured for newAccountId
+ final AccountData accountData = subscriptionTestInitializer.initAccountData();
+ final Account account = createAccount(accountData);
+ newAccountId = account.getId();
}
@Test(groups = "slow")
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoSql.java b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoSql.java
index 4dd3357..2261e0b 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoSql.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoSql.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -16,6 +18,7 @@
package org.killbill.billing.subscription.engine.dao;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.skife.jdbi.v2.IDBI;
import org.killbill.bus.api.PersistentBus;
@@ -32,7 +35,8 @@ public class MockSubscriptionDaoSql extends DefaultSubscriptionDao {
@Inject
public MockSubscriptionDaoSql(final IDBI dbi, final Clock clock, final AddonUtils addonUtils, final NotificationQueueService notificationQueueService,
- final PersistentBus eventBus, final CatalogService catalogService, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
- super(dbi, clock, addonUtils, notificationQueueService, eventBus, catalogService, cacheControllerDispatcher, nonEntityDao);
+ final PersistentBus eventBus, final CatalogService catalogService, final CacheControllerDispatcher cacheControllerDispatcher,
+ final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
+ super(dbi, clock, addonUtils, notificationQueueService, eventBus, catalogService, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
}
}
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/glue/TestDefaultSubscriptionModuleNoDB.java b/subscription/src/test/java/org/killbill/billing/subscription/glue/TestDefaultSubscriptionModuleNoDB.java
index 1bb0955..571f6ff 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/glue/TestDefaultSubscriptionModuleNoDB.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/glue/TestDefaultSubscriptionModuleNoDB.java
@@ -20,6 +20,7 @@ package org.killbill.billing.subscription.glue;
import org.killbill.billing.GuicyKillbillTestNoDBModule;
import org.killbill.billing.account.api.AccountUserApi;
+import org.killbill.billing.mock.glue.MockAccountModule;
import org.killbill.billing.mock.glue.MockNonEntityDaoModule;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.subscription.engine.dao.MockSubscriptionDaoMemory;
@@ -40,8 +41,7 @@ public class TestDefaultSubscriptionModuleNoDB extends TestDefaultSubscriptionMo
@Override
protected void configure() {
install(new GuicyKillbillTestNoDBModule(configSource));
-
- bind(AccountUserApi.class).toInstance(Mockito.mock(AccountUserApi.class));
+ install(new MockAccountModule(configSource));
super.configure();
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java
index 9b74d30..c57adde 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteNoDB.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -41,6 +41,7 @@ import org.killbill.billing.subscription.engine.dao.MockSubscriptionDaoMemory;
import org.killbill.billing.subscription.engine.dao.SubscriptionDao;
import org.killbill.billing.subscription.glue.TestDefaultSubscriptionModuleNoDB;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.config.SubscriptionConfig;
import org.killbill.clock.ClockMock;
import org.mockito.Mockito;
@@ -101,6 +102,9 @@ public class SubscriptionTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
@Inject
protected MockNonEntityDao mockNonEntityDao;
+ @Inject
+ protected InternalCallContextFactory internalCallContextFactory;
+
protected Catalog catalog;
protected AccountData accountData;
protected SubscriptionBaseBundle bundle;
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
index e335d8f..0dc88d7 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
@@ -21,7 +21,9 @@ package org.killbill.billing.subscription;
import javax.inject.Inject;
import org.killbill.billing.GuicyKillbillTestSuiteWithEmbeddedDB;
+import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountData;
import org.killbill.billing.account.api.AccountUserApi;
import org.killbill.billing.api.TestApiListener;
@@ -38,7 +40,9 @@ import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
import org.killbill.billing.subscription.api.user.TestSubscriptionHelper;
import org.killbill.billing.subscription.engine.dao.SubscriptionDao;
import org.killbill.billing.subscription.glue.TestDefaultSubscriptionModuleWithEmbeddedDB;
+import org.killbill.billing.util.cache.Cachable.CacheType;
import org.killbill.billing.util.config.SubscriptionConfig;
+import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.clock.ClockMock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -88,6 +92,9 @@ public class SubscriptionTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteW
@Inject
protected SubscriptionTestInitializer subscriptionTestInitializer;
+ @Inject
+ protected NonEntityDao nonEntityDao;
+
protected Catalog catalog;
protected AccountData accountData;
protected SubscriptionBaseBundle bundle;
@@ -111,7 +118,7 @@ public class SubscriptionTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteW
this.catalog = subscriptionTestInitializer.initCatalog(catalogService, internalCallContext);
this.accountData = subscriptionTestInitializer.initAccountData();
- final Account account = accountUserApi.createAccount(accountData, callContext);
+ final Account account = createAccount(accountData);
this.bundle = subscriptionTestInitializer.initBundle(account.getId(), subscriptionInternalApi, internalCallContext);
// Make sure we start with a clean state
@@ -126,6 +133,16 @@ public class SubscriptionTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteW
subscriptionTestInitializer.stopTestFramework(testListener, busService, subscriptionBaseService);
}
+ protected Account createAccount(final AccountData accountData) throws AccountApiException {
+ final Account account = accountUserApi.createAccount(accountData, callContext);
+
+ final Long accountRecordId = nonEntityDao.retrieveRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, controlCacheDispatcher.getCacheController(CacheType.RECORD_ID));
+ internalCallContext.setAccountRecordId(accountRecordId);
+ internalCallContext.setReferenceDateTimeZone(account.getTimeZone());
+
+ return account;
+ }
+
protected void assertListenerStatus() {
testListener.assertListenerStatus();
}
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/api/TenantCacheInvalidation.java b/tenant/src/main/java/org/killbill/billing/tenant/api/TenantCacheInvalidation.java
index 02ac812..a49f041 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/api/TenantCacheInvalidation.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/api/TenantCacheInvalidation.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -178,7 +178,7 @@ public class TenantCacheInvalidation {
if (tenantKeyAndCookie != null) {
final CacheInvalidationCallback callback = parent.getCacheInvalidation(tenantKeyAndCookie.getTenantKey());
if (callback != null) {
- final InternalTenantContext tenantContext = new InternalTenantContext(cur.getTenantRecordId(), null);
+ final InternalTenantContext tenantContext = new InternalTenantContext(cur.getTenantRecordId());
callback.invalidateCache(tenantKeyAndCookie.getTenantKey(), tenantKeyAndCookie.getCookie(), tenantContext);
final Long tenantKvsTargetRecordId = cur.getTargetRecordId();
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/api/user/DefaultTenantUserApi.java b/tenant/src/main/java/org/killbill/billing/tenant/api/user/DefaultTenantUserApi.java
index 3c1c575..f8fc8a0 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/api/user/DefaultTenantUserApi.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/api/user/DefaultTenantUserApi.java
@@ -102,7 +102,7 @@ public class DefaultTenantUserApi implements TenantUserApi {
@Override
public Tenant getTenantById(final UUID id) throws TenantApiException {
// TODO - API cleanup?
- final TenantModelDao tenant = tenantDao.getById(id, new InternalTenantContext(null, null));
+ final TenantModelDao tenant = tenantDao.getById(id, new InternalTenantContext(null));
if (tenant == null) {
throw new TenantApiException(ErrorCode.TENANT_DOES_NOT_EXIST_FOR_ID, id);
}
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantBroadcastDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantBroadcastDao.java
index 0ac2964..5fa4996 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantBroadcastDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantBroadcastDao.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -24,6 +24,7 @@ import javax.inject.Inject;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.tenant.api.TenantApiException;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.Entity;
import org.killbill.billing.util.entity.dao.EntityDaoBase;
@@ -31,12 +32,12 @@ import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper
import org.killbill.clock.Clock;
import org.skife.jdbi.v2.IDBI;
-
public class DefaultTenantBroadcastDao extends EntityDaoBase<TenantBroadcastModelDao, Entity, TenantApiException> implements TenantBroadcastDao {
@Inject
- public DefaultTenantBroadcastDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), TenantBroadcastSqlDao.class);
+ public DefaultTenantBroadcastDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+ final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), TenantBroadcastSqlDao.class);
}
@Override
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java
index 4d929d4..1e12715 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/DefaultTenantDao.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -37,6 +37,7 @@ import org.killbill.billing.tenant.api.TenantApiException;
import org.killbill.billing.tenant.api.TenantKV.TenantKey;
import org.killbill.billing.util.UUIDs;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.config.SecurityConfig;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.dao.EntityDaoBase;
@@ -62,8 +63,9 @@ public class DefaultTenantDao extends EntityDaoBase<TenantModelDao, Tenant, Tena
private final SecurityConfig securityConfig;
@Inject
- public DefaultTenantDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final SecurityConfig securityConfig) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao), TenantSqlDao.class);
+ public DefaultTenantDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+ final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory, final SecurityConfig securityConfig) {
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), TenantSqlDao.class);
this.securityConfig = securityConfig;
}
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantBroadcastDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantBroadcastDao.java
index 750a60f..eef661e 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantBroadcastDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantBroadcastDao.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -21,10 +21,13 @@ import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
+import javax.inject.Named;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.tenant.api.TenantApiException;
+import org.killbill.billing.tenant.glue.DefaultTenantModule;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.entity.Entity;
import org.killbill.billing.util.entity.Pagination;
import org.killbill.billing.util.entity.dao.EntityDaoBase;
@@ -37,8 +40,8 @@ import org.skife.jdbi.v2.IDBI;
public class NoCachingTenantBroadcastDao extends EntityDaoBase<TenantBroadcastModelDao, Entity, TenantApiException> implements TenantBroadcastDao {
@Inject
- public NoCachingTenantBroadcastDao(final IDBI dbi, final Clock clock) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, null, null), TenantBroadcastSqlDao.class);
+ public NoCachingTenantBroadcastDao(final IDBI dbi, final Clock clock, @Named(DefaultTenantModule.NO_CACHING_TENANT) final InternalCallContextFactory internalCallContextFactory) {
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, null, null, internalCallContextFactory), TenantBroadcastSqlDao.class);
}
@Override
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java
index a491f09..3913ae2 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/NoCachingTenantDao.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -21,10 +21,14 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import javax.inject.Named;
+
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.tenant.api.Tenant;
import org.killbill.billing.tenant.api.TenantApiException;
+import org.killbill.billing.tenant.glue.DefaultTenantModule;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.entity.Pagination;
import org.killbill.billing.util.entity.dao.EntityDaoBase;
import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
@@ -35,7 +39,6 @@ import org.skife.jdbi.v2.IDBI;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
/**
@@ -51,8 +54,8 @@ import com.google.inject.Inject;
public class NoCachingTenantDao extends EntityDaoBase<TenantModelDao, Tenant, TenantApiException> implements TenantDao {
@Inject
- public NoCachingTenantDao(final IDBI dbi, final Clock clock) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, null, null), TenantSqlDao.class);
+ public NoCachingTenantDao(final IDBI dbi, final Clock clock, @Named(DefaultTenantModule.NO_CACHING_TENANT) final InternalCallContextFactory internalCallContextFactory) {
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, null, null, internalCallContextFactory), TenantSqlDao.class);
}
@Override
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/glue/DefaultTenantModule.java b/tenant/src/main/java/org/killbill/billing/tenant/glue/DefaultTenantModule.java
index af1c9f7..c85a96f 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/glue/DefaultTenantModule.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/glue/DefaultTenantModule.java
@@ -34,8 +34,10 @@ import org.killbill.billing.tenant.dao.NoCachingTenantBroadcastDao;
import org.killbill.billing.tenant.dao.NoCachingTenantDao;
import org.killbill.billing.tenant.dao.TenantBroadcastDao;
import org.killbill.billing.tenant.dao.TenantDao;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.config.TenantConfig;
import org.killbill.billing.util.glue.KillBillModule;
+import org.killbill.billing.util.glue.NoCachingInternalCallContextFactoryProvider;
import org.skife.config.ConfigurationObjectFactory;
import com.google.inject.name.Names;
@@ -59,6 +61,7 @@ public class DefaultTenantModule extends KillBillModule implements TenantModule
bind(TenantDao.class).annotatedWith(Names.named(NO_CACHING_TENANT)).to(NoCachingTenantDao.class).asEagerSingleton();
bind(TenantBroadcastDao.class).to(DefaultTenantBroadcastDao.class).asEagerSingleton();
bind(TenantBroadcastDao.class).annotatedWith(Names.named(NO_CACHING_TENANT)).to(NoCachingTenantBroadcastDao.class).asEagerSingleton();
+ bind(InternalCallContextFactory.class).annotatedWith(Names.named(NO_CACHING_TENANT)).toProvider(NoCachingInternalCallContextFactoryProvider.class).asEagerSingleton();
}
public void installTenantUserApi() {
diff --git a/tenant/src/test/java/org/killbill/billing/tenant/dao/TestNoCachingTenantBroadcastDao.java b/tenant/src/test/java/org/killbill/billing/tenant/dao/TestNoCachingTenantBroadcastDao.java
index 4d6a43a..8796587 100644
--- a/tenant/src/test/java/org/killbill/billing/tenant/dao/TestNoCachingTenantBroadcastDao.java
+++ b/tenant/src/test/java/org/killbill/billing/tenant/dao/TestNoCachingTenantBroadcastDao.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -20,10 +20,7 @@ package org.killbill.billing.tenant.dao;
import java.util.List;
import java.util.UUID;
-import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.tenant.TenantTestSuiteWithEmbeddedDb;
-import org.killbill.billing.util.callcontext.CallOrigin;
-import org.killbill.billing.util.callcontext.UserType;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -33,13 +30,15 @@ public class TestNoCachingTenantBroadcastDao extends TenantTestSuiteWithEmbedded
public void testBasic() throws Exception {
final TenantBroadcastModelDao model = new TenantBroadcastModelDao(0L, "foo", UUID.randomUUID());
- final InternalCallContext context79 = createContext(79L);
- tenantBroadcastDao.create(model, context79);
+ internalCallContext.setTenantRecordId(79L);
+ tenantBroadcastDao.create(model, internalCallContext);
- final TenantBroadcastModelDao result1 = tenantBroadcastDao.getById(model.getId(), context79);
+ final TenantBroadcastModelDao result1 = tenantBroadcastDao.getById(model.getId(), internalCallContext);
Assert.assertEquals(result1.getTenantRecordId(), new Long(79L));
Assert.assertEquals(result1.getType(), "foo");
+ internalCallContext.reset();
+
final TenantBroadcastModelDao resultNull = tenantBroadcastDao.getById(model.getId(), internalCallContext);
Assert.assertNull(resultNull);
@@ -50,15 +49,15 @@ public class TestNoCachingTenantBroadcastDao extends TenantTestSuiteWithEmbedded
@Test(groups = "slow")
public void testLatestEntries() throws Exception {
+ internalCallContext.setTenantRecordId(81L);
- final InternalCallContext context79 = createContext(81L);
TenantBroadcastModelDao latestInsert = null;
for (int i = 0; i < 100; i++) {
final TenantBroadcastModelDao model = new TenantBroadcastModelDao(0L, "foo-" + i, UUID.randomUUID());
- tenantBroadcastDao.create(model, context79);
+ tenantBroadcastDao.create(model, internalCallContext);
latestInsert = model;
}
- final TenantBroadcastModelDao latestInsertRefreshed = tenantBroadcastDao.getById(latestInsert.getId(), context79);
+ final TenantBroadcastModelDao latestInsertRefreshed = tenantBroadcastDao.getById(latestInsert.getId(), internalCallContext);
final TenantBroadcastModelDao lastEntry = noCachingTenantBroadcastDao.getLatestEntry();
Assert.assertEquals(lastEntry.getRecordId(), latestInsertRefreshed.getRecordId());
@@ -69,17 +68,8 @@ public class TestNoCachingTenantBroadcastDao extends TenantTestSuiteWithEmbedded
Assert.assertEquals(result.size(), expectedEntries);
long i = 0;
- for (TenantBroadcastModelDao cur : result) {
+ for (final TenantBroadcastModelDao cur : result) {
Assert.assertEquals(cur.getRecordId().longValue(), (fromRecordId + i++ + 1L));
}
-
- }
-
- private InternalCallContext createContext(final Long tenantRecordId) {
- return new InternalCallContext(tenantRecordId, 0L, UUID.randomUUID(),
- UUID.randomUUID().toString(), CallOrigin.TEST,
- UserType.TEST, "Testing TestNoCachingTenantBroadcastDao", "This is a test for TestNoCachingTenantBroadcastDao",
- clock.getUTCNow(), clock.getUTCNow());
-
}
}
diff --git a/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModuleWithEmbeddedDB.java b/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModuleWithEmbeddedDB.java
index 0bae0d1..8c14902 100644
--- a/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModuleWithEmbeddedDB.java
+++ b/tenant/src/test/java/org/killbill/billing/tenant/glue/TestTenantModuleWithEmbeddedDB.java
@@ -19,6 +19,7 @@
package org.killbill.billing.tenant.glue;
import org.killbill.billing.GuicyKillbillTestWithEmbeddedDBModule;
+import org.killbill.billing.mock.glue.MockAccountModule;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.util.glue.NonEntityDaoModule;
import org.killbill.billing.util.glue.SecurityModule;
@@ -38,5 +39,6 @@ public class TestTenantModuleWithEmbeddedDB extends TestTenantModule {
install(new NonEntityDaoModule(configSource));
install(new SecurityModule(configSource));
install(new ShiroModuleNoDB(configSource));
+ install(new MockAccountModule(configSource));
}
}
diff --git a/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java b/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java
index 1feb447..45b0146 100644
--- a/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java
+++ b/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java
@@ -64,7 +64,7 @@ public class DefaultUsageUserApi implements UsageUserApi {
@Override
public RolledUpUsage getUsageForSubscription(final UUID subscriptionId, final String unitType, final LocalDate startDate, final LocalDate endDate, final TenantContext tenantContext) {
- final List<RolledUpUsageModelDao> usageForSubscription = rolledUpUsageDao.getUsageForSubscription(subscriptionId, startDate, endDate, unitType, internalCallContextFactory.createInternalTenantContext(tenantContext));
+ final List<RolledUpUsageModelDao> usageForSubscription = rolledUpUsageDao.getUsageForSubscription(subscriptionId, startDate, endDate, unitType, internalCallContextFactory.createInternalTenantContext(subscriptionId, ObjectType.SUBSCRIPTION, tenantContext));
final List<RolledUpUnit> rolledUpAmount = getRolledUpUnits(usageForSubscription);
return new DefaultRolledUpUsage(subscriptionId, startDate, endDate, rolledUpAmount);
}
diff --git a/util/src/main/java/org/killbill/billing/util/audit/dao/DefaultAuditDao.java b/util/src/main/java/org/killbill/billing/util/audit/dao/DefaultAuditDao.java
index 12a33e9..13b75f5 100644
--- a/util/src/main/java/org/killbill/billing/util/audit/dao/DefaultAuditDao.java
+++ b/util/src/main/java/org/killbill/billing/util/audit/dao/DefaultAuditDao.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2012 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -33,6 +35,7 @@ import org.killbill.billing.util.audit.DefaultAccountAuditLogs;
import org.killbill.billing.util.audit.DefaultAccountAuditLogsForObjectType;
import org.killbill.billing.util.audit.DefaultAuditLog;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.dao.NonEntitySqlDao;
import org.killbill.billing.util.dao.RecordIdIdMappings;
@@ -55,9 +58,9 @@ public class DefaultAuditDao implements AuditDao {
private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
@Inject
- public DefaultAuditDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+ public DefaultAuditDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
this.nonEntitySqlDao = dbi.onDemand(NonEntitySqlDao.class);
- this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
+ this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
}
@Override
diff --git a/util/src/main/java/org/killbill/billing/util/cache/OverriddenPlanCacheLoader.java b/util/src/main/java/org/killbill/billing/util/cache/OverriddenPlanCacheLoader.java
index ab2e833..52c4a07 100644
--- a/util/src/main/java/org/killbill/billing/util/cache/OverriddenPlanCacheLoader.java
+++ b/util/src/main/java/org/killbill/billing/util/cache/OverriddenPlanCacheLoader.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -17,15 +17,12 @@
package org.killbill.billing.util.cache;
-import java.util.List;
-
import javax.inject.Inject;
import javax.inject.Singleton;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.StaticCatalog;
-import org.killbill.billing.tenant.api.TenantInternalApi;
import org.killbill.billing.util.cache.Cachable.CacheType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,9 +32,8 @@ public class OverriddenPlanCacheLoader extends BaseCacheLoader {
private final Logger log = LoggerFactory.getLogger(OverriddenPlanCacheLoader.class);
-
@Inject
- public OverriddenPlanCacheLoader(final TenantInternalApi tenantApi) {
+ public OverriddenPlanCacheLoader() {
super();
}
diff --git a/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java b/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java
index d4367b5..0460fd4 100644
--- a/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java
+++ b/util/src/main/java/org/killbill/billing/util/callcontext/InternalCallContextFactory.java
@@ -24,7 +24,12 @@ import javax.annotation.Nullable;
import javax.inject.Inject;
import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
import org.killbill.billing.ObjectType;
+import org.killbill.billing.account.api.AccountApiException;
+import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
+import org.killbill.billing.account.api.ImmutableAccountInternalApi;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.util.cache.Cachable.CacheType;
@@ -32,19 +37,24 @@ import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.clock.Clock;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
// Internal contexts almost always expect accountRecordId and tenantRecordId to be populated
public class InternalCallContextFactory {
public static final long INTERNAL_TENANT_RECORD_ID = 0L;
+ private final ImmutableAccountInternalApi accountInternalApi;
private final Clock clock;
private final NonEntityDao nonEntityDao;
private final CacheControllerDispatcher cacheControllerDispatcher;
@Inject
- public InternalCallContextFactory(final Clock clock, final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher) {
+ public InternalCallContextFactory(@Nullable final ImmutableAccountInternalApi accountInternalApi,
+ final Clock clock,
+ final NonEntityDao nonEntityDao,
+ @Nullable final CacheControllerDispatcher cacheControllerDispatcher) {
+ this.accountInternalApi = accountInternalApi;
this.clock = clock;
this.nonEntityDao = nonEntityDao;
this.cacheControllerDispatcher = cacheControllerDispatcher;
@@ -120,8 +130,11 @@ public class InternalCallContextFactory {
* @return internal tenant callcontext
*/
public InternalTenantContext createInternalTenantContext(final Long tenantRecordId, @Nullable final Long accountRecordId) {
- //Preconditions.checkNotNull(tenantRecordId, "tenantRecordId cannot be null");
- return new InternalTenantContext(tenantRecordId, accountRecordId);
+ if (accountRecordId == null) {
+ return new InternalTenantContext(tenantRecordId);
+ } else {
+ return new InternalTenantContext(tenantRecordId, accountRecordId, getAccountTimeZone(tenantRecordId, accountRecordId));
+ }
}
//
@@ -175,17 +188,16 @@ public class InternalCallContextFactory {
* This is used by notification queue and persistent bus - accountRecordId is expected to be non null
*
* @param tenantRecordId tenant record id - if null, the default tenant record id value will be used
- * @param accountRecordId account record id (cannot be null)
+ * @param accountRecordId account record id (can be null in specific use-cases, e.g. config change events in BeatrixListener)
* @param userName user name
* @param callOrigin call origin
* @param userType user type
* @param userToken user token, if any
* @return internal call callcontext
*/
- public InternalCallContext createInternalCallContext(@Nullable final Long tenantRecordId, final Long accountRecordId, final String userName,
+ public InternalCallContext createInternalCallContext(@Nullable final Long tenantRecordId, @Nullable final Long accountRecordId, final String userName,
final CallOrigin callOrigin, final UserType userType, @Nullable final UUID userToken) {
- return new InternalCallContext(tenantRecordId, accountRecordId, userToken, userName, callOrigin, userType, null, null,
- clock.getUTCNow(), clock.getUTCNow());
+ return createInternalCallContext(tenantRecordId, accountRecordId, userName, callOrigin, userType, userToken, null, null, clock.getUTCNow(), clock.getUTCNow());
}
/**
@@ -200,14 +212,13 @@ public class InternalCallContextFactory {
public InternalCallContext createInternalCallContext(final CallContext context) {
// If tenant id is null, this will default to the default tenant record id (multi-tenancy disabled)
final Long tenantRecordId = getTenantRecordIdSafe(context);
- return new InternalCallContext(tenantRecordId, null, context);
+ return new InternalCallContext(tenantRecordId, context);
}
// Used when we need to re-hydrate the callcontext with the account_record_id (when creating the account)
public InternalCallContext createInternalCallContext(final Long accountRecordId, final InternalCallContext context) {
- return new InternalCallContext(context.getTenantRecordId(), accountRecordId, context.getUserToken(), context.getCreatedBy(),
- context.getCallOrigin(), context.getContextUserType(), context.getReasonCode(), context.getComments(),
- context.getCreatedDate(), context.getUpdatedDate());
+ final DateTimeZone accountTimeZone = getAccountTimeZone(context.getTenantRecordId(), accountRecordId);
+ return new InternalCallContext(context, accountRecordId, accountTimeZone);
}
private InternalCallContext createInternalCallContext(final UUID objectId, final ObjectType objectType, final String userName,
@@ -220,17 +231,33 @@ public class InternalCallContextFactory {
reasonCode, comment, createdDate, updatedDate);
}
- private InternalCallContext createInternalCallContext(@Nullable final Long tenantRecordId, final Long accountRecordId, final String userName,
+ private InternalCallContext createInternalCallContext(@Nullable final Long tenantRecordId, @Nullable final Long accountRecordId, final String userName,
final CallOrigin callOrigin, final UserType userType, @Nullable final UUID userToken,
@Nullable final String reasonCode, @Nullable final String comment, final DateTime createdDate,
final DateTime updatedDate) {
- //Preconditions.checkNotNull(accountRecordId, "accountRecordId cannot be null");
- final Long nonNulTenantRecordId = Objects.firstNonNull(tenantRecordId, INTERNAL_TENANT_RECORD_ID);
+ final Long nonNulTenantRecordId = MoreObjects.firstNonNull(tenantRecordId, INTERNAL_TENANT_RECORD_ID);
+ final DateTimeZone accountTimeZone = getAccountTimeZone(tenantRecordId, accountRecordId);
- return new InternalCallContext(nonNulTenantRecordId, accountRecordId, userToken, userName, callOrigin, userType, reasonCode, comment,
+ return new InternalCallContext(nonNulTenantRecordId, accountRecordId, accountTimeZone, userToken, userName, callOrigin, userType, reasonCode, comment,
createdDate, updatedDate);
}
+ private DateTimeZone getAccountTimeZone(final Long tenantRecordId, @Nullable final Long accountRecordId) {
+ if (accountRecordId == null || accountInternalApi == null) {
+ return null;
+ }
+
+ final InternalTenantContext tmp = new InternalTenantContext(tenantRecordId, accountRecordId, null);
+
+ try {
+ final ImmutableAccountData immutableAccountData = accountInternalApi.getImmutableAccountDataByRecordId(accountRecordId, tmp);
+ // Will be null while creating the account
+ return immutableAccountData == null ? null : immutableAccountData.getTimeZone();
+ } catch (final AccountApiException e) {
+ return null;
+ }
+ }
+
//
// Safe NonEntityDao public wrappers
//
@@ -239,7 +266,7 @@ public class InternalCallContextFactory {
public UUID getAccountId(final UUID objectId, final ObjectType objectType, final TenantContext context) {
final Long accountRecordId = getAccountRecordIdSafe(objectId, objectType, context);
if (accountRecordId != null) {
- return nonEntityDao.retrieveIdFromObject(accountRecordId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+ return nonEntityDao.retrieveIdFromObject(accountRecordId, ObjectType.ACCOUNT, cacheControllerDispatcher == null ? null : cacheControllerDispatcher.getCacheController(CacheType.OBJECT_ID));
} else {
return null;
}
@@ -249,7 +276,7 @@ public class InternalCallContextFactory {
public Long getRecordIdFromObject(final UUID objectId, final ObjectType objectType, final TenantContext context) {
try {
if (objectBelongsToTheRightTenant(objectId, objectType, context)) {
- return nonEntityDao.retrieveRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
+ return nonEntityDao.retrieveRecordIdFromObject(objectId, objectType, cacheControllerDispatcher == null ? null : cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
} else {
return null;
}
@@ -290,7 +317,7 @@ public class InternalCallContextFactory {
}
private UUID getTenantIdSafe(final InternalTenantContext context) {
- return nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, cacheControllerDispatcher.getCacheController(CacheType.OBJECT_ID));
+ return nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT, cacheControllerDispatcher == null ? null : cacheControllerDispatcher.getCacheController(CacheType.OBJECT_ID));
}
//
@@ -318,14 +345,14 @@ public class InternalCallContextFactory {
//
private Long getAccountRecordIdUnsafe(final UUID objectId, final ObjectType objectType) {
- return nonEntityDao.retrieveAccountRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID));
+ return nonEntityDao.retrieveAccountRecordIdFromObject(objectId, objectType, cacheControllerDispatcher == null ? null : cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID));
}
private Long getTenantRecordIdUnsafe(final UUID objectId, final ObjectType objectType) {
- return nonEntityDao.retrieveTenantRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.TENANT_RECORD_ID));
+ return nonEntityDao.retrieveTenantRecordIdFromObject(objectId, objectType, cacheControllerDispatcher == null ? null : cacheControllerDispatcher.getCacheController(CacheType.TENANT_RECORD_ID));
}
- private static final class ObjectDoesNotExist extends IllegalStateException {
+ public static final class ObjectDoesNotExist extends IllegalStateException {
public ObjectDoesNotExist(final String s) {
super(s);
diff --git a/util/src/main/java/org/killbill/billing/util/customfield/dao/DefaultCustomFieldDao.java b/util/src/main/java/org/killbill/billing/util/customfield/dao/DefaultCustomFieldDao.java
index c4ac0b2..1416fb4 100644
--- a/util/src/main/java/org/killbill/billing/util/customfield/dao/DefaultCustomFieldDao.java
+++ b/util/src/main/java/org/killbill/billing/util/customfield/dao/DefaultCustomFieldDao.java
@@ -1,7 +1,9 @@
/*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -22,6 +24,7 @@ import java.util.UUID;
import javax.annotation.Nullable;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.skife.jdbi.v2.IDBI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -60,8 +63,9 @@ public class DefaultCustomFieldDao extends EntityDaoBase<CustomFieldModelDao, Cu
private final PersistentBus bus;
@Inject
- public DefaultCustomFieldDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao, final PersistentBus bus) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao), CustomFieldSqlDao.class);
+ public DefaultCustomFieldDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher controllerDispatcher,
+ final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory, final PersistentBus bus) {
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao, internalCallContextFactory), CustomFieldSqlDao.class);
this.bus = bus;
}
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java
index 8be616a..e70fcba 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoTransactionalJdbiWrapper.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2012 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -19,6 +19,7 @@
package org.killbill.billing.util.entity.dao;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.Entity;
import org.killbill.clock.Clock;
@@ -37,12 +38,15 @@ public class EntitySqlDaoTransactionalJdbiWrapper {
private final Clock clock;
private final CacheControllerDispatcher cacheControllerDispatcher;
private final NonEntityDao nonEntityDao;
+ private final InternalCallContextFactory internalCallContextFactory;
- public EntitySqlDaoTransactionalJdbiWrapper(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+ public EntitySqlDaoTransactionalJdbiWrapper(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
+ final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
this.dbi = dbi;
this.clock = clock;
this.cacheControllerDispatcher = cacheControllerDispatcher;
this.nonEntityDao = nonEntityDao;
+ this.internalCallContextFactory = internalCallContextFactory;
}
class JdbiTransaction<ReturnType, M extends EntityModelDao<E>, E extends Entity> implements Transaction<ReturnType, EntitySqlDao<M, E>> {
@@ -57,7 +61,7 @@ public class EntitySqlDaoTransactionalJdbiWrapper {
@Override
public ReturnType inTransaction(final EntitySqlDao<M, E> transactionalSqlDao, final TransactionStatus status) throws Exception {
- final EntitySqlDaoWrapperFactory factoryEntitySqlDao = new EntitySqlDaoWrapperFactory(h, clock, cacheControllerDispatcher, nonEntityDao);
+ final EntitySqlDaoWrapperFactory factoryEntitySqlDao = new EntitySqlDaoWrapperFactory(h, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
return entitySqlDaoTransactionWrapper.inTransaction(factoryEntitySqlDao);
}
}
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java
index 0dc33c6..2d29ee7 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperFactory.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2012 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -21,6 +21,7 @@ package org.killbill.billing.util.entity.dao;
import java.lang.reflect.Proxy;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.entity.Entity;
import org.killbill.clock.Clock;
@@ -40,12 +41,14 @@ public class EntitySqlDaoWrapperFactory {
private final CacheControllerDispatcher cacheControllerDispatcher;
private final NonEntityDao nonEntityDao;
+ private final InternalCallContextFactory internalCallContextFactory;
- public EntitySqlDaoWrapperFactory(final Handle handle, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+ public EntitySqlDaoWrapperFactory(final Handle handle, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
this.handle = handle;
this.clock = clock;
this.cacheControllerDispatcher = cacheControllerDispatcher;
this.nonEntityDao = nonEntityDao;
+ this.internalCallContextFactory = internalCallContextFactory;
}
/**
@@ -73,7 +76,7 @@ public class EntitySqlDaoWrapperFactory {
final ClassLoader classLoader = newSqlDao.getClass().getClassLoader();
final Class[] interfacesToImplement = {newSqlDaoClass};
final EntitySqlDaoWrapperInvocationHandler<NewSqlDao, NewEntityModelDao, NewEntity> wrapperInvocationHandler =
- new EntitySqlDaoWrapperInvocationHandler<NewSqlDao, NewEntityModelDao, NewEntity>(newSqlDaoClass, newSqlDao, handle, clock, cacheControllerDispatcher, nonEntityDao);
+ new EntitySqlDaoWrapperInvocationHandler<NewSqlDao, NewEntityModelDao, NewEntity>(newSqlDaoClass, newSqlDao, handle, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
final Object newSqlDaoObject = Proxy.newProxyInstance(classLoader, interfacesToImplement, wrapperInvocationHandler);
return newSqlDaoClass.cast(newSqlDaoObject);
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
index 9793364..dde8ec7 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2012 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -43,6 +43,7 @@ import org.killbill.billing.util.cache.CachableKey;
import org.killbill.billing.util.cache.CacheController;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.cache.CacheLoaderArgument;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.EntityAudit;
import org.killbill.billing.util.dao.EntityHistoryModelDao;
import org.killbill.billing.util.dao.NonEntityDao;
@@ -89,6 +90,7 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>,
private final CacheControllerDispatcher cacheControllerDispatcher;
private final Clock clock;
private final NonEntityDao nonEntityDao;
+ private final InternalCallContextFactory internalCallContextFactory;
private final Profiling prof;
public EntitySqlDaoWrapperInvocationHandler(final Class<S> sqlDaoClass,
@@ -97,13 +99,15 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>,
final Clock clock,
// Special DAO that don't require caching can invoke EntitySqlDaoWrapperInvocationHandler with no caching (e.g NoCachingTenantDao)
@Nullable final CacheControllerDispatcher cacheControllerDispatcher,
- @Nullable final NonEntityDao nonEntityDao) {
+ @Nullable final NonEntityDao nonEntityDao,
+ final InternalCallContextFactory internalCallContextFactory) {
this.sqlDaoClass = sqlDaoClass;
this.sqlDao = sqlDao;
this.handle = handle;
this.clock = clock;
this.cacheControllerDispatcher = cacheControllerDispatcher;
this.nonEntityDao = nonEntityDao;
+ this.internalCallContextFactory = internalCallContextFactory;
this.prof = new Profiling<Object, Throwable>();
}
@@ -465,7 +469,7 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>,
final InternalCallContext context;
// Populate the account record id when creating the account record
if (TableName.ACCOUNT.equals(tableName) && ChangeType.INSERT.equals(changeType)) {
- context = new InternalCallContext(contextMaybeWithoutAccountRecordId, entityRecordId);
+ context = internalCallContextFactory.createInternalCallContext(entityRecordId, contextMaybeWithoutAccountRecordId);
} else {
context = contextMaybeWithoutAccountRecordId;
}
diff --git a/util/src/main/java/org/killbill/billing/util/glue/NoCachingInternalCallContextFactoryProvider.java b/util/src/main/java/org/killbill/billing/util/glue/NoCachingInternalCallContextFactoryProvider.java
new file mode 100644
index 0000000..51aa352
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/glue/NoCachingInternalCallContextFactoryProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.util.glue;
+
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.dao.NonEntityDao;
+import org.killbill.clock.Clock;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class NoCachingInternalCallContextFactoryProvider implements Provider<InternalCallContextFactory> {
+
+ private final Clock clock;
+ private final NonEntityDao nonEntityDao;
+
+ @Inject
+ public NoCachingInternalCallContextFactoryProvider(final Clock clock, final NonEntityDao nonEntityDao) {
+ this.clock = clock;
+ this.nonEntityDao = nonEntityDao;
+ }
+
+ @Override
+ public InternalCallContextFactory get() {
+ return new InternalCallContextFactory(null, clock, nonEntityDao, null);
+ }
+}
diff --git a/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDao.java b/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDao.java
index 865af9d..62543e5 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDao.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDao.java
@@ -1,7 +1,9 @@
/*
- * Copyright 2010-2012 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -20,6 +22,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.UUID;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.skife.jdbi.v2.IDBI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -62,8 +65,8 @@ public class DefaultTagDao extends EntityDaoBase<TagModelDao, Tag, TagApiExcepti
@Inject
public DefaultTagDao(final IDBI dbi, final TagEventBuilder tagEventBuilder, final PersistentBus bus, final Clock clock,
- final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao), TagSqlDao.class);
+ final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao, internalCallContextFactory), TagSqlDao.class);
this.tagEventBuilder = tagEventBuilder;
this.bus = bus;
}
diff --git a/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java b/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java
index 2eb20fd..9039976 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/dao/DefaultTagDefinitionDao.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2011 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -22,6 +24,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.skife.jdbi.v2.IDBI;
import org.skife.jdbi.v2.exceptions.TransactionFailedException;
import org.slf4j.Logger;
@@ -60,8 +63,8 @@ public class DefaultTagDefinitionDao extends EntityDaoBase<TagDefinitionModelDao
@Inject
public DefaultTagDefinitionDao(final IDBI dbi, final TagEventBuilder tagEventBuilder, final PersistentBus bus, final Clock clock,
- final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao) {
- super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao), TagDefinitionSqlDao.class);
+ final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory) {
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao, internalCallContextFactory), TagDefinitionSqlDao.class);
this.tagEventBuilder = tagEventBuilder;
this.bus = bus;
}
diff --git a/util/src/main/java/org/killbill/billing/util/timezone/DefaultAccountDateAndTimeZoneContext.java b/util/src/main/java/org/killbill/billing/util/timezone/DefaultAccountDateAndTimeZoneContext.java
index 2562fc2..3239ee1 100644
--- a/util/src/main/java/org/killbill/billing/util/timezone/DefaultAccountDateAndTimeZoneContext.java
+++ b/util/src/main/java/org/killbill/billing/util/timezone/DefaultAccountDateAndTimeZoneContext.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -18,62 +20,32 @@ package org.killbill.billing.util.timezone;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
-import org.joda.time.Days;
import org.joda.time.LocalDate;
-import org.joda.time.LocalTime;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.util.AccountDateAndTimeZoneContext;
/**
- * Used by entitlement and invoice to calculate:
+ * Used by junction and invoice to calculate:
* - a LocalDate from DateTime and the timeZone set on the account
* - A DateTime from a LocalDate and the referenceTime attached to the account.
*/
public final class DefaultAccountDateAndTimeZoneContext implements AccountDateAndTimeZoneContext {
- private final LocalTime referenceTime;
- private final int offsetFromUtc;
- private final DateTimeZone accountTimeZone;
+ private final DateTime referenceTime;
+ private final InternalTenantContext internalTenantContext;
- /// effectiveDateTime is compute from first billing event and so offsetFromUtc will remain constant with regard to daylight saving time
- public DefaultAccountDateAndTimeZoneContext(final DateTime effectiveDateTime, final DateTimeZone accountTimeZone) {
- this.referenceTime = effectiveDateTime != null ? effectiveDateTime.toLocalTime() : null;
- this.accountTimeZone = accountTimeZone;
- this.offsetFromUtc = computeOffsetFromUtc(effectiveDateTime, accountTimeZone);
- }
-
- static int computeOffsetFromUtc(final DateTime effectiveDateTime, final DateTimeZone accountTimeZone) {
- final LocalDate localDateInAccountTimeZone = new LocalDate(effectiveDateTime, accountTimeZone);
- final LocalDate localDateInUTC = new LocalDate(effectiveDateTime, DateTimeZone.UTC);
- return Days.daysBetween(localDateInUTC, localDateInAccountTimeZone).getDays();
+ public DefaultAccountDateAndTimeZoneContext(final DateTime referenceTime, final InternalTenantContext internalTenantContext) {
+ this.referenceTime = referenceTime;
+ this.internalTenantContext = internalTenantContext;
}
@Override
public LocalDate computeLocalDateFromFixedAccountOffset(final DateTime targetDateTime) {
- final DateTime dateWithOriginalAccountTimeZoneOffset = targetDateTime.plusDays(offsetFromUtc);
- return dateWithOriginalAccountTimeZoneOffset.toLocalDate();
+ return internalTenantContext.toLocalDate(targetDateTime, referenceTime);
}
@Override
public DateTime computeUTCDateTimeFromLocalDate(final LocalDate invoiceItemEndDate) {
- //
- // Since we create the targetDate for next invoice using the date from the notificationQ, we need to make sure
- // that this datetime once transformed into a LocalDate points to the correct day.
- //
- // All we need to do is figure if the transformation from DateTime (point in time) to LocalDate (date in account time zone)
- // changed the day; if so, when we recompute a UTC date from LocalDate (date in account time zone), we can simply chose a reference
- // time and apply the offset backward to end up on the right day
- //
- // We use clock.getUTCNow() to get the offset with account timezone but that may not be correct
- // when we transition from standard time and daylight saving time. We could end up with a result
- // that is slightly in advance and therefore results in a null invoice.
- // We will fix that by re-inserting ourselves in the notificationQ if we detect that there is no invoice
- // and yet the subscription is recurring and not cancelled.
- //
- return invoiceItemEndDate.toDateTime(referenceTime, DateTimeZone.UTC).plusDays(-offsetFromUtc);
- }
-
- @Override
- public DateTimeZone getAccountTimeZone() {
- return accountTimeZone;
+ return internalTenantContext.toUTCDateTime(invoiceItemEndDate, referenceTime);
}
}
diff --git a/util/src/test/java/org/killbill/billing/api/TestApiListener.java b/util/src/test/java/org/killbill/billing/api/TestApiListener.java
index 690707a..d710a92 100644
--- a/util/src/test/java/org/killbill/billing/api/TestApiListener.java
+++ b/util/src/test/java/org/killbill/billing/api/TestApiListener.java
@@ -37,6 +37,7 @@ import org.killbill.billing.events.InvoiceCreationInternalEvent;
import org.killbill.billing.events.InvoiceNotificationInternalEvent;
import org.killbill.billing.events.InvoicePaymentErrorInternalEvent;
import org.killbill.billing.events.InvoicePaymentInfoInternalEvent;
+import org.killbill.billing.events.NullInvoiceInternalEvent;
import org.killbill.billing.events.PaymentErrorInternalEvent;
import org.killbill.billing.events.PaymentInfoInternalEvent;
import org.killbill.billing.events.PaymentPluginErrorInternalEvent;
@@ -113,6 +114,7 @@ public class TestApiListener {
RESUME,
PHASE,
BLOCK,
+ NULL_INVOICE,
INVOICE,
INVOICE_NOTIFICATION,
INVOICE_ADJUSTMENT,
@@ -239,6 +241,13 @@ public class TestApiListener {
}
@Subscribe
+ public void handleNullInvoiceEvents(final NullInvoiceInternalEvent event) {
+ log.info(String.format("Got Null Invoice event %s", event.toString()));
+ assertEqualsNicely(NextEvent.NULL_INVOICE);
+ notifyIfStackEmpty();
+ }
+
+ @Subscribe
public void handleInvoiceEvents(final InvoiceCreationInternalEvent event) {
log.info(String.format("Got Invoice event %s", event.toString()));
assertEqualsNicely(NextEvent.INVOICE);
diff --git a/util/src/test/java/org/killbill/billing/callcontext/MutableInternalCallContext.java b/util/src/test/java/org/killbill/billing/callcontext/MutableInternalCallContext.java
new file mode 100644
index 0000000..6882a8b
--- /dev/null
+++ b/util/src/test/java/org/killbill/billing/callcontext/MutableInternalCallContext.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.callcontext;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.killbill.billing.util.callcontext.CallOrigin;
+import org.killbill.billing.util.callcontext.UserType;
+
+public class MutableInternalCallContext extends InternalCallContext {
+
+ private final Long initialAccountRecordId;
+ private final Long initialTenantRecordId;
+ private final DateTimeZone initialReferenceDateTimeZone;
+ private final DateTime initialCreatedDate;
+ private final DateTime initialUpdatedDate;
+
+ private Long accountRecordId;
+ private Long tenantRecordId;
+ private DateTimeZone referenceDateTimeZone;
+ private DateTime createdDate;
+ private DateTime updatedDate;
+
+ public MutableInternalCallContext(final Long tenantRecordId,
+ @Nullable final Long accountRecordId,
+ @Nullable final DateTimeZone referenceDateTimeZone,
+ final UUID userToken,
+ final String userName,
+ final CallOrigin callOrigin,
+ final UserType userType,
+ final String reasonCode,
+ final String comment,
+ final DateTime createdDate,
+ final DateTime updatedDate) {
+ super(tenantRecordId, accountRecordId, referenceDateTimeZone, userToken, userName, callOrigin, userType, reasonCode, comment, createdDate, updatedDate);
+ this.initialAccountRecordId = accountRecordId;
+ this.initialTenantRecordId = tenantRecordId;
+ this.initialReferenceDateTimeZone = referenceDateTimeZone;
+ this.initialCreatedDate = createdDate;
+ this.initialUpdatedDate = updatedDate;
+
+ reset();
+ }
+
+ @Override
+ public Long getAccountRecordId() {
+ return accountRecordId;
+ }
+
+ public void setAccountRecordId(final Long accountRecordId) {
+ this.accountRecordId = accountRecordId;
+ }
+
+ @Override
+ public Long getTenantRecordId() {
+ return tenantRecordId;
+ }
+
+ public void setTenantRecordId(final Long tenantRecordId) {
+ this.tenantRecordId = tenantRecordId;
+ }
+
+ @Override
+ public DateTimeZone getReferenceDateTimeZone() {
+ return referenceDateTimeZone;
+ }
+
+ public void setReferenceDateTimeZone(final DateTimeZone referenceDateTimeZone) {
+ this.referenceDateTimeZone = referenceDateTimeZone;
+ }
+
+ @Override
+ public DateTime getCreatedDate() {
+ return createdDate;
+ }
+
+ public void setCreatedDate(final DateTime createdDate) {
+ this.createdDate = createdDate;
+ }
+
+ @Override
+ public DateTime getUpdatedDate() {
+ return updatedDate;
+ }
+
+ public void setUpdatedDate(final DateTime updatedDate) {
+ this.updatedDate = updatedDate;
+ }
+
+ public void reset() {
+ setAccountRecordId(initialAccountRecordId);
+ setTenantRecordId(initialTenantRecordId);
+ setReferenceDateTimeZone(initialReferenceDateTimeZone);
+ setCreatedDate(initialCreatedDate);
+ setUpdatedDate(initialUpdatedDate);
+ }
+}
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestModule.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestModule.java
index 7cda860..65f7fa7 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestModule.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestModule.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -20,7 +20,9 @@ package org.killbill.billing;
import java.util.UUID;
+import org.joda.time.DateTimeZone;
import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.MutableInternalCallContext;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.CallOrigin;
@@ -37,10 +39,17 @@ public class GuicyKillbillTestModule extends KillBillModule {
// That we we have only one clock and all internalContext/callcontext are consistent
//
- private final InternalCallContext internalCallContext = new InternalCallContext(InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID, 1687L, UUID.randomUUID(),
- UUID.randomUUID().toString(), CallOrigin.TEST,
- UserType.TEST, "Testing", "This is a test",
- GuicyKillbillTestSuite.getClock().getUTCNow(), GuicyKillbillTestSuite.getClock().getUTCNow());
+ private final MutableInternalCallContext internalCallContext = new MutableInternalCallContext(InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID,
+ 1687L,
+ DateTimeZone.UTC,
+ UUID.randomUUID(),
+ UUID.randomUUID().toString(),
+ CallOrigin.TEST,
+ UserType.TEST,
+ "Testing",
+ "This is a test",
+ GuicyKillbillTestSuite.getClock().getUTCNow(),
+ GuicyKillbillTestSuite.getClock().getUTCNow());
private final CallContext callContext = internalCallContext.toCallContext(null);
@@ -53,6 +62,7 @@ public class GuicyKillbillTestModule extends KillBillModule {
bind(ClockMock.class).toInstance(GuicyKillbillTestSuite.getClock());
bind(Clock.class).to(ClockMock.class);
bind(InternalCallContext.class).toInstance(internalCallContext);
+ bind(MutableInternalCallContext.class).toInstance(internalCallContext);
bind(CallContext.class).toInstance(callContext);
}
}
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
index 7debdc2..b4c5538 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -22,7 +22,7 @@ import java.lang.reflect.Method;
import javax.inject.Inject;
-import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.MutableInternalCallContext;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.platform.test.config.TestKillbillConfigSource;
import org.killbill.billing.util.callcontext.CallContext;
@@ -44,7 +44,7 @@ public class GuicyKillbillTestSuite {
private boolean hasFailed = false;
@Inject
- protected InternalCallContext internalCallContext;
+ protected MutableInternalCallContext internalCallContext;
@Inject
protected CallContext callContext;
@@ -100,6 +100,8 @@ public class GuicyKillbillTestSuite {
log.info("***************************************************************************************************");
log.info("*** Starting test {}:{}", method.getDeclaringClass().getName(), method.getName());
log.info("***************************************************************************************************");
+
+ internalCallContext.reset();
}
@AfterMethod(alwaysRun = true)
diff --git a/util/src/test/java/org/killbill/billing/KillbillTestSuite.java b/util/src/test/java/org/killbill/billing/KillbillTestSuite.java
index 7af49d2..ebb0d5b 100644
--- a/util/src/test/java/org/killbill/billing/KillbillTestSuite.java
+++ b/util/src/test/java/org/killbill/billing/KillbillTestSuite.java
@@ -1,7 +1,9 @@
/*
- * Copyright 2010-2012 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -17,22 +19,15 @@
package org.killbill.billing;
import java.lang.reflect.Method;
-import java.util.UUID;
+import org.killbill.clock.Clock;
+import org.killbill.clock.ClockMock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
-import org.killbill.billing.util.callcontext.CallContext;
-import org.killbill.billing.util.callcontext.CallOrigin;
-import org.killbill.billing.callcontext.InternalCallContext;
-import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.killbill.billing.util.callcontext.UserType;
-import org.killbill.clock.Clock;
-import org.killbill.clock.ClockMock;
-
public class KillbillTestSuite {
// Use the simple name here to save screen real estate
@@ -42,12 +37,6 @@ public class KillbillTestSuite {
protected Clock clock = new ClockMock();
- protected final InternalCallContext internalCallContext = new InternalCallContext(InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID, 1687L, UUID.randomUUID(),
- UUID.randomUUID().toString(), CallOrigin.TEST,
- UserType.TEST, "Testing", "This is a test",
- clock.getUTCNow(), clock.getUTCNow());
- protected final CallContext callContext = internalCallContext.toCallContext(null);
-
@BeforeMethod(alwaysRun = true)
public void startTestSuite(final Method method) throws Exception {
log.info("***************************************************************************************************");
diff --git a/util/src/test/java/org/killbill/billing/mock/glue/MockAccountModule.java b/util/src/test/java/org/killbill/billing/mock/glue/MockAccountModule.java
index 5efae87..3fc2521 100644
--- a/util/src/test/java/org/killbill/billing/mock/glue/MockAccountModule.java
+++ b/util/src/test/java/org/killbill/billing/mock/glue/MockAccountModule.java
@@ -18,12 +18,19 @@
package org.killbill.billing.mock.glue;
+import org.joda.time.DateTimeZone;
+import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.account.api.AccountUserApi;
+import org.killbill.billing.account.api.ImmutableAccountData;
+import org.killbill.billing.account.api.ImmutableAccountInternalApi;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.glue.AccountModule;
+import org.killbill.billing.mock.api.MockAccountUserApi;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.util.glue.KillBillModule;
import org.mockito.Mockito;
+import org.testng.Assert;
public class MockAccountModule extends KillBillModule implements AccountModule {
@@ -39,11 +46,23 @@ public class MockAccountModule extends KillBillModule implements AccountModule {
@Override
public void installAccountUserApi() {
- bind(AccountUserApi.class).toInstance(Mockito.mock(AccountUserApi.class));
+ bind(AccountUserApi.class).toInstance(new MockAccountUserApi());
}
@Override
public void installInternalApi() {
- bind(AccountInternalApi.class).toInstance(Mockito.mock(AccountInternalApi.class));
+ final ImmutableAccountData immutableAccountData = Mockito.mock(ImmutableAccountData.class);
+ Mockito.when(immutableAccountData.getTimeZone()).thenReturn(DateTimeZone.UTC);
+
+ final AccountInternalApi accountInternalApi = Mockito.mock(AccountInternalApi.class);
+ final ImmutableAccountInternalApi immutableAccountInternalApi = Mockito.mock(ImmutableAccountInternalApi.class);
+ try {
+ Mockito.when(accountInternalApi.getImmutableAccountDataByRecordId(Mockito.anyLong(), Mockito.<InternalTenantContext>any())).thenReturn(immutableAccountData);
+ Mockito.when(immutableAccountInternalApi.getImmutableAccountDataByRecordId(Mockito.anyLong(), Mockito.<InternalTenantContext>any())).thenReturn(immutableAccountData);
+ } catch (final AccountApiException e) {
+ Assert.fail(e.getMessage());
+ }
+ bind(AccountInternalApi.class).toInstance(accountInternalApi);
+ bind(ImmutableAccountInternalApi.class).toInstance(immutableAccountInternalApi);
}
}
diff --git a/util/src/test/java/org/killbill/billing/util/cache/TestCache.java b/util/src/test/java/org/killbill/billing/util/cache/TestCache.java
index 98b84d9..d24810c 100644
--- a/util/src/test/java/org/killbill/billing/util/cache/TestCache.java
+++ b/util/src/test/java/org/killbill/billing/util/cache/TestCache.java
@@ -60,7 +60,7 @@ public class TestCache extends UtilTestSuiteWithEmbeddedDB {
@Test(groups = "slow")
public void testCacheRecordId() throws Exception {
- this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controlCacheDispatcher, nonEntityDao);
+ this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controlCacheDispatcher, nonEntityDao, internalCallContextFactory);
final TagModelDao tag = new TagModelDao(clock.getUTCNow(), UUID.randomUUID(), UUID.randomUUID(), ObjectType.TAG);
// Verify we start with nothing in the cache
@@ -88,7 +88,7 @@ public class TestCache extends UtilTestSuiteWithEmbeddedDB {
@Test(groups = "slow")
public void testAllCachesAfterGetById() throws Exception {
- this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controlCacheDispatcher, nonEntityDao);
+ this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controlCacheDispatcher, nonEntityDao, internalCallContextFactory);
final TagModelDao tag = new TagModelDao(clock.getUTCNow(), UUID.randomUUID(), UUID.randomUUID(), ObjectType.TAG);
insertTag(tag);
diff --git a/util/src/test/java/org/killbill/billing/util/glue/TestUtilModule.java b/util/src/test/java/org/killbill/billing/util/glue/TestUtilModule.java
index 9dee2b4..030cd05 100644
--- a/util/src/test/java/org/killbill/billing/util/glue/TestUtilModule.java
+++ b/util/src/test/java/org/killbill/billing/util/glue/TestUtilModule.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -18,6 +18,7 @@
package org.killbill.billing.util.glue;
+import org.killbill.billing.mock.glue.MockAccountModule;
import org.killbill.billing.mock.glue.MockTenantModule;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimelineApi;
@@ -29,9 +30,12 @@ public class TestUtilModule extends KillBillModule {
super(configSource);
}
- // TODO STEPH this is bad-- because DefaultAuditUserApi is using SubscriptionBaseTimeline API
- public void installHack() {
+ // TODO this is bad!
+ public void installHacks() {
+ // DefaultAuditUserApi is using SubscriptionBaseTimeline API
bind(SubscriptionBaseTimelineApi.class).toInstance(Mockito.mock(SubscriptionBaseTimelineApi.class));
+ // InternalCallContextFactory is using AccountInternalApi
+ install(new MockAccountModule(configSource));
}
@Override
@@ -39,6 +43,6 @@ public class TestUtilModule extends KillBillModule {
//install(new CallContextModule());
install(new CacheModule(configSource));
install(new MockTenantModule(configSource));
- installHack();
+ installHacks();
}
}
diff --git a/util/src/test/java/org/killbill/billing/util/timezone/TestDateAndTimeZoneContext.java b/util/src/test/java/org/killbill/billing/util/timezone/TestDateAndTimeZoneContext.java
index ba6b67f..c37c115 100644
--- a/util/src/test/java/org/killbill/billing/util/timezone/TestDateAndTimeZoneContext.java
+++ b/util/src/test/java/org/killbill/billing/util/timezone/TestDateAndTimeZoneContext.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -21,9 +23,9 @@ import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
-import org.testng.annotations.Test;
-
+import org.killbill.billing.util.AccountDateAndTimeZoneContext;
import org.killbill.billing.util.UtilTestSuiteNoDB;
+import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@@ -37,135 +39,46 @@ import static org.testng.Assert.assertTrue;
public class TestDateAndTimeZoneContext extends UtilTestSuiteNoDB {
private final DateTimeFormatter DATE_TIME_FORMATTER = ISODateTimeFormat.dateTimeParser();
-
- final String effectiveDateTime1 = "2012-01-20T07:30:42.000Z";
- final String effectiveDateTime2 = "2012-01-20T08:00:00.000Z";
- final String effectiveDateTime3 = "2012-01-20T08:45:33.000Z";
-
- final String effectiveDateTimeA = "2012-01-20T16:30:42.000Z";
- final String effectiveDateTimeB = "2012-01-20T16:00:00.000Z";
- final String effectiveDateTimeC = "2012-01-20T15:30:42.000Z";
-
-
- //
- // Take an negative timezone offset and a reference time that is less than the offset (07:30:42 < 8)
- // => to expect a negative offset of one day
- //
- @Test(groups = "fast")
- public void testComputeOffset1() {
-
- final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
- final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime1);
-
- int offset = DefaultAccountDateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
- assertEquals(offset, -1);
- }
-
- //
- // Take an negative timezone offset and a reference time that is equal than the offset (08:00:00 = 8)
- // => to expect an offset of 0
- //
- @Test(groups = "fast")
- public void testComputeOffset2() {
-
- final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
- final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime2);
-
- int offset = DefaultAccountDateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
- assertEquals(offset, 0);
- }
-
- //
- // Take an negative timezone offset and a reference time that is greater than the offset (08:45:33 > 8)
- // => to expect an offset of 0
- //
- @Test(groups = "fast")
- public void testComputeOffset3() {
-
- final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
- final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime3);
-
- int offset = DefaultAccountDateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
- assertEquals(offset, 0);
- }
-
- //
- // Take an positive timezone offset and a reference time that closer to the end of the day than the timezone (16:30:42 + 8 > 24)
- // => to expect a positive offset of one day
- //
- @Test(groups = "fast")
- public void testComputeOffsetA() {
-
- final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
- final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeA);
-
- int offset = DefaultAccountDateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
- assertEquals(offset, 1);
- }
-
- //
- // Take an positive timezone offset and a reference time that brings us exactly at the end of the day (16:00:00 + 8 = 24)
- // => to expect an offset of 1
- //
- @Test(groups = "fast")
- public void testComputeOffsetB() {
-
- final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
- final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeB);
-
- int offset = DefaultAccountDateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
- assertEquals(offset, 1);
- }
-
- //
- // Take an positive timezone offset and a reference time that further away to the end of the day (15:30:42 + 8 < 24)
- // => to expect an offset of 0
- //
- @Test(groups = "fast")
- public void testComputeOffsetC() {
-
- final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
- final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeC);
-
- int offset = DefaultAccountDateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
- assertEquals(offset, 0);
- }
+ private final String effectiveDateTime1 = "2012-01-20T07:30:42.000Z";
+ private final String effectiveDateTime2 = "2012-01-20T08:00:00.000Z";
+ private final String effectiveDateTime3 = "2012-01-20T08:45:33.000Z";
+ private final String effectiveDateTimeA = "2012-01-20T16:30:42.000Z";
+ private final String effectiveDateTimeB = "2012-01-20T16:00:00.000Z";
+ private final String effectiveDateTimeC = "2012-01-20T15:30:42.000Z";
@Test(groups = "fast")
public void testComputeUTCDateTimeFromLocalDate1() {
-
final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime1);
final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
- final DefaultAccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, timeZone);
+ internalCallContext.setReferenceDateTimeZone(timeZone);
+ final AccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, internalCallContext);
final LocalDate endDate = new LocalDate(2013, 01, 19);
final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
assertTrue(endDateTimeInUTC.compareTo(effectiveDateTime.plusYears(1)) == 0);
}
-
@Test(groups = "fast")
public void testComputeUTCDateTimeFromLocalDate2() {
-
final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime2);
final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
- final DefaultAccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, timeZone);
+ internalCallContext.setReferenceDateTimeZone(timeZone);
+ final AccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, internalCallContext);
final LocalDate endDate = new LocalDate(2013, 01, 20);
final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
assertTrue(endDateTimeInUTC.compareTo(effectiveDateTime.plusYears(1)) == 0);
}
-
@Test(groups = "fast")
public void testComputeUTCDateTimeFromLocalDate3() {
-
final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime3);
final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
- final DefaultAccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, timeZone);
+ internalCallContext.setReferenceDateTimeZone(timeZone);
+ final AccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, internalCallContext);
final LocalDate endDate = new LocalDate(2013, 01, 20);
final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
@@ -174,11 +87,11 @@ public class TestDateAndTimeZoneContext extends UtilTestSuiteNoDB {
@Test(groups = "fast")
public void testComputeUTCDateTimeFromLocalDateA() {
-
final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeA);
final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
- final DefaultAccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, timeZone);
+ internalCallContext.setReferenceDateTimeZone(timeZone);
+ final AccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, internalCallContext);
final LocalDate endDate = new LocalDate(2013, 01, 21);
final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
@@ -187,11 +100,11 @@ public class TestDateAndTimeZoneContext extends UtilTestSuiteNoDB {
@Test(groups = "fast")
public void testComputeUTCDateTimeFromLocalDateB() {
-
final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeB);
final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
- final DefaultAccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, timeZone);
+ internalCallContext.setReferenceDateTimeZone(timeZone);
+ final AccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, internalCallContext);
final LocalDate endDate = new LocalDate(2013, 01, 21);
final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
@@ -200,40 +113,39 @@ public class TestDateAndTimeZoneContext extends UtilTestSuiteNoDB {
@Test(groups = "fast")
public void testComputeUTCDateTimeFromLocalDateC() {
-
final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeC);
final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
- final DefaultAccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, timeZone);
+ internalCallContext.setReferenceDateTimeZone(timeZone);
+ final AccountDateAndTimeZoneContext dateContext = new DefaultAccountDateAndTimeZoneContext(effectiveDateTime, internalCallContext);
final LocalDate endDate = new LocalDate(2013, 01, 20);
final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
assertTrue(endDateTimeInUTC.compareTo(effectiveDateTime.plusYears(1)) == 0);
}
-
@Test(groups = "fast")
- public void testComputeTargetDateWithDayLigthSaving() {
+ public void testComputeTargetDateWithDayLightSaving() {
+ final DateTime dateTime1 = new DateTime("2015-01-01T08:01:01.000Z");
+ final DateTime dateTime2 = new DateTime("2015-09-01T08:01:01.000Z");
+ final DateTime dateTime3 = new DateTime("2015-12-01T08:01:01.000Z");
+ // Alaska Standard Time
final DateTimeZone tz = DateTimeZone.forID("America/Juneau");
- final DateTime originalDateTime = new DateTime("2015-09-01T08:01:01.000Z");
-
- final DefaultAccountDateAndTimeZoneContext dateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(originalDateTime, tz);
-
-
- final LocalDate l1 = dateAndTimeZoneContext.computeLocalDateFromFixedAccountOffset(originalDateTime);
- assertEquals(l1, new LocalDate("2015-09-01"));
-
- final LocalDate l1ComputedFromAccountTz = new LocalDate(originalDateTime, tz);
- assertEquals(l1ComputedFromAccountTz, new LocalDate("2015-09-01"));
-
- final DateTime newDateTime = new DateTime("2015-12-01T08:01:01.000Z");
-
- final LocalDate l2 = dateAndTimeZoneContext.computeLocalDateFromFixedAccountOffset(newDateTime);
- assertEquals(l2, new LocalDate("2015-12-01"));
-
- final LocalDate l2ComputedFromAccountTz = new LocalDate(newDateTime, tz);
- assertEquals(l2ComputedFromAccountTz, new LocalDate("2015-11-30"));
-
+ internalCallContext.setReferenceDateTimeZone(tz);
+
+ // Time zone is AKDT (UTC-8h) between March and November
+ final DateTime referenceDateTimeWithDST = new DateTime("2015-09-01T08:01:01.000Z");
+ final AccountDateAndTimeZoneContext tzContextWithDST = new DefaultAccountDateAndTimeZoneContext(referenceDateTimeWithDST, internalCallContext);
+ assertEquals(tzContextWithDST.computeLocalDateFromFixedAccountOffset(dateTime1), new LocalDate("2015-01-01"));
+ assertEquals(tzContextWithDST.computeLocalDateFromFixedAccountOffset(dateTime2), new LocalDate("2015-09-01"));
+ assertEquals(tzContextWithDST.computeLocalDateFromFixedAccountOffset(dateTime3), new LocalDate("2015-12-01"));
+
+ // Time zone is AKST (UTC-9h) otherwise
+ final DateTime referenceDateTimeWithoutDST = new DateTime("2015-02-01T08:01:01.000Z");
+ final AccountDateAndTimeZoneContext tzContextWithoutDST = new DefaultAccountDateAndTimeZoneContext(referenceDateTimeWithoutDST, internalCallContext);
+ assertEquals(tzContextWithoutDST.computeLocalDateFromFixedAccountOffset(dateTime1), new LocalDate("2014-12-31"));
+ assertEquals(tzContextWithoutDST.computeLocalDateFromFixedAccountOffset(dateTime2), new LocalDate("2015-08-31"));
+ assertEquals(tzContextWithoutDST.computeLocalDateFromFixedAccountOffset(dateTime3), new LocalDate("2015-11-30"));
}
}