killbill-aplcache
Changes
analytics/pom.xml 6(+6 -0)
bin/db-helper 157(+157 -0)
catalog/pom.xml 6(+6 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java 34(+9 -25)
entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java 20(+14 -6)
entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java 6(+2 -4)
entitlement/src/main/java/com/ning/billing/entitlement/api/billing/OverdueEventCalculator.java 283(+283 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/overdue/DefaultOverdueChecker.java 59(+59 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java 21(+11 -10)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java 51(+43 -8)
entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java 2(+1 -1)
entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java 34(+23 -11)
entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java 771(+771 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java 1(+1 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/MockOverdueChecker.java 29(+12 -17)
entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/TestEntitlementOverdueApi.java 58(+0 -58)
entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java 197(+197 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java 2(+2 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java 2(+2 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java 4(+3 -1)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java 2(+2 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java 1(+1 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java 1(+1 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java 3(+2 -1)
invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java 2(+1 -1)
invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java 55(+35 -20)
overdue/pom.xml 7(+6 -1)
overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java 6(+3 -3)
Details
analytics/pom.xml 6(+6 -0)
diff --git a/analytics/pom.xml b/analytics/pom.xml
index b6f27c9..e7e0e94 100644
--- a/analytics/pom.xml
+++ b/analytics/pom.xml
@@ -75,6 +75,12 @@
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
+ <artifactId>killbill-entitlement</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
<artifactId>killbill-invoice</artifactId>
<scope>test</scope>
</dependency>
diff --git a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
index 1aafa7c..4d26ac0 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
@@ -16,25 +16,24 @@
package com.ning.billing.analytics;
-import com.ning.billing.invoice.glue.InvoiceModule;
-import com.ning.billing.payment.setup.PaymentModule;
-import com.ning.billing.util.glue.CallContextModule;
-import com.ning.billing.util.glue.FieldStoreModule;
-import com.ning.billing.util.tag.dao.TagDefinitionSqlDao;
import org.skife.jdbi.v2.IDBI;
+
import com.ning.billing.account.glue.AccountModule;
import com.ning.billing.analytics.setup.AnalyticsModule;
-import com.ning.billing.catalog.glue.CatalogModule;
import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.entitlement.api.overdue.MockOverdueChecker;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
import com.ning.billing.entitlement.glue.EntitlementModule;
-
+import com.ning.billing.invoice.glue.InvoiceModule;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+import com.ning.billing.payment.setup.PaymentModule;
import com.ning.billing.util.glue.BusModule;
-
+import com.ning.billing.util.glue.CallContextModule;
import com.ning.billing.util.glue.ClockModule;
+import com.ning.billing.util.glue.FieldStoreModule;
import com.ning.billing.util.glue.NotificationQueueModule;
import com.ning.billing.util.glue.TagStoreModule;
-
-import java.lang.reflect.Field;
+import com.ning.billing.util.tag.dao.TagDefinitionSqlDao;
public class AnalyticsTestModule extends AnalyticsModule
{
@@ -49,10 +48,17 @@ public class AnalyticsTestModule extends AnalyticsModule
install(new FieldStoreModule());
install(new TagStoreModule());
install(new AccountModule());
- install(new CatalogModule());
install(new BusModule());
- install(new EntitlementModule());
+ install(new EntitlementModule() {
+
+ @Override
+ protected void installOverdueChecker() {
+ bind(OverdueChecker.class).to(MockOverdueChecker.class).asEagerSingleton();
+ }
+
+ });
install(new InvoiceModule());
+ install(new MockOverdueAccessModule());
install(new PaymentModule());
install(new TagStoreModule());
install(new NotificationQueueModule());
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
index 59ad218..a3040fd 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
@@ -51,6 +51,7 @@ import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
import com.ning.billing.analytics.dao.BusinessAccountDao;
import com.ning.billing.analytics.dao.BusinessSubscriptionTransitionDao;
+import com.ning.billing.catalog.MockCatalogModule;
import com.ning.billing.catalog.MockPriceList;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.catalog.api.PhaseType;
@@ -89,7 +90,7 @@ import com.ning.billing.util.tag.DescriptiveTag;
import com.ning.billing.util.tag.Tag;
import com.ning.billing.util.tag.dao.TagDefinitionSqlDao;
-@Guice(modules = AnalyticsTestModule.class)
+@Guice(modules = {AnalyticsTestModule.class, MockCatalogModule.class})
public class TestAnalyticsService {
private static final UUID ID = UUID.randomUUID();
private static final String KEY = "12345";
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java
index 6f80e03..533367f 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java
@@ -124,4 +124,9 @@ public class MockIEntitlementUserApi implements EntitlementUserApi
public DateTime getNextBillingDate(UUID account) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public Subscription getBaseSubscription(UUID bundleId) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/api/src/main/java/com/ning/billing/catalog/api/overdue/Overdueable.java b/api/src/main/java/com/ning/billing/catalog/api/overdue/Overdueable.java
index 9910c7e..d11c353 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/overdue/Overdueable.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/overdue/Overdueable.java
@@ -18,11 +18,31 @@ package com.ning.billing.catalog.api.overdue;
import java.util.UUID;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+
public interface Overdueable {
public enum Type {
- ACCOUNT,
- SUBSCRIPTION_BUNDLE
+ //Not currently supported
+ // ACCOUNT,
+ SUBSCRIPTION_BUNDLE;
+
+ public static Type get(Overdueable o) throws CatalogApiException{
+ if (o instanceof SubscriptionBundle){
+ return SUBSCRIPTION_BUNDLE;
+ }
+ throw new CatalogApiException(ErrorCode.CAT_NO_OVERDUEABLE_TYPE , o.getClass().getName());
+ }
+
+ public static Type get(String type) throws CatalogApiException {
+ if (type.equalsIgnoreCase(SUBSCRIPTION_BUNDLE.name())) {
+ return SUBSCRIPTION_BUNDLE;
+ }
+ throw new CatalogApiException(ErrorCode.CAT_NO_OVERDUEABLE_TYPE , type);
+ }
+
}
public UUID getId();
diff --git a/api/src/main/java/com/ning/billing/catalog/api/overdue/OverdueState.java b/api/src/main/java/com/ning/billing/catalog/api/overdue/OverdueState.java
index d9596e4..856d048 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/overdue/OverdueState.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/overdue/OverdueState.java
@@ -25,9 +25,9 @@ public interface OverdueState<T extends Overdueable> {
public int getDaysBetweenPaymentRetries();
- public boolean entitlementDisabledAndChangesBlocked();
+ public boolean disableEntitlementAndChangesBlocked();
- public boolean changesBlocked();
+ public boolean blockChanges();
public boolean isClearState();
}
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java b/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
index bb7f632..2f8646c 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
@@ -81,6 +81,5 @@ public interface StaticCatalog {
public abstract boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException;
public abstract OverdueStateSet<SubscriptionBundle> currentBundleOverdueStateSet() throws CatalogApiException;
- public abstract OverdueStateSet<Account> currentAccountOverdueStateSet() throws CatalogApiException;
}
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java b/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java
index 6340560..a0d8e93 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java
@@ -16,21 +16,26 @@
package com.ning.billing.entitlement.api.billing;
-import com.ning.billing.catalog.api.Currency;
+import java.math.BigDecimal;
+
import org.joda.time.DateTime;
+import com.ning.billing.account.api.Account;
import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.InternationalPrice;
+import com.ning.billing.catalog.api.Currency;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
-import java.math.BigDecimal;
-
public interface BillingEvent extends Comparable<BillingEvent> {
/**
+ * @return the account that this billing event is associated with
+ */
+ public Account getAccount();
+
+ /**
*
* @return the billCycleDay as seen for that subscription at that time
*
@@ -109,4 +114,4 @@ public interface BillingEvent extends Comparable<BillingEvent> {
*/
public Long getTotalOrdering();
-}
+ }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
index 1867cfe..162b92e 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
@@ -35,6 +35,8 @@ public interface EntitlementUserApi {
public List<Subscription> getSubscriptionsForBundle(UUID bundleId);
public List<Subscription> getSubscriptionsForKey(String bundleKey);
+
+ public Subscription getBaseSubscription(UUID bundleId);
public SubscriptionBundle createBundleForAccount(UUID accountId, String bundleKey)
throws EntitlementUserApiException;
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index 0a8bfd5..db73376 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -115,6 +115,7 @@ public enum ErrorCode {
*/
CAT_NO_SUCH_OVEDUE_STATE(2070, "No such overdue state '%s'"),
CAT_MISSING_CLEAR_STATE(2071, "Missing a clear state"),
+ CAT_NO_OVERDUEABLE_TYPE(2072, "No such overdueable type: "),
/*
*
* Range 3000 : ACCOUNT
@@ -165,7 +166,7 @@ public enum ErrorCode {
*
*/
OVERDUE_OVERDUEABLE_NOT_SUPPORTED(5001, "The Overdueable type '%s' is not supported"),
- OVERDUE_CAT_ERROR_ENCOUNTERED(5002,"Catalog error encountered when attempting to refresh the state of Overdueable: id='%s', type='%s'")
+ OVERDUE_CAT_ERROR_ENCOUNTERED(5002,"Catalog error encountered on Overdueable: id='%s', type='%s'"),
;
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
index 304cb0b..0e8063d 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
@@ -45,6 +45,7 @@ import com.ning.billing.entitlement.glue.EntitlementModule;
import com.ning.billing.invoice.api.InvoiceService;
import com.ning.billing.invoice.glue.InvoiceModule;
import com.ning.billing.lifecycle.KillbillService;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
import com.ning.billing.payment.api.PaymentService;
import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
import com.ning.billing.payment.setup.PaymentConfig;
@@ -93,6 +94,7 @@ public class MockModule extends AbstractModule {
install(new EntitlementModule());
install(new InvoiceModule());
install(new PaymentMockModule());
+ install(new MockOverdueAccessModule());
}
private static final class PaymentMockModule extends PaymentModule {
diff --git a/beatrix/src/test/resources/catalogSample.xml b/beatrix/src/test/resources/catalogSample.xml
index 5b7aeaf..fabda9d 100644
--- a/beatrix/src/test/resources/catalogSample.xml
+++ b/beatrix/src/test/resources/catalogSample.xml
@@ -184,7 +184,15 @@ Use Cases to do:
</priceListCase>
</priceList>
</rules>
-
+
+ <overdueRules>
+ <bundleOverdueStates>
+ <state name="Clear">
+ <isClearState>true</isClearState>
+ </state>
+ </bundleOverdueStates>
+ </overdueRules>
+
<plans>
<plan name="pistol-monthly-no-trial">
<product>Pistol</product>
bin/db-helper 157(+157 -0)
diff --git a/bin/db-helper b/bin/db-helper
new file mode 100755
index 0000000..cd99dc8
--- /dev/null
+++ b/bin/db-helper
@@ -0,0 +1,157 @@
+#! /usr/bin/env bash
+
+
+###################################################################################
+# #
+# Copyright 2010-2011 Ning, Inc. #
+# #
+# Ning 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. #
+# #
+###################################################################################
+
+#set -x
+
+HERE=`cd \`dirname $0\`; pwd`
+TOP=$HERE/..
+
+POM="$TOP/pom.xml"
+
+ACTION=
+DATABASE="killbill"
+USER="root"
+PWD="root"
+TEST_ALSO=
+
+DDL_FILE=
+CLEAN_FILE=
+
+function usage() {
+ echo -n "./db_helper "
+ echo -n " -a <create|clean|dump>"
+ echo -n " -d database_name (default = killbill)"
+ echo -n " -u user_name (default = root)"
+ echo -n " -p password (default = root)"
+ echo -n " -t (also include test ddl)"
+ echo -n "-h this message"
+ echo
+ exit 1
+}
+
+function get_modules() {
+ local modules=`grep module $POM | grep -v modules | cut -d '>' -f 2 | cut -d '<' -f 1`
+ echo $modules
+}
+
+function find_test_ddl() {
+
+ local modules=`get_modules`
+ local ddl_test=
+
+ local cur_ddl=
+ for m in $modules; do
+ cur_ddl=`find $m/src/test/resources/ -name ddl_test.sql 2>/dev/null`
+ ddl_test="$ddl_test $cur_ddl"
+ done
+ echo "$ddl_test"
+
+}
+function find_src_ddl() {
+
+ local modules=`get_modules`
+ local ddl_src=
+
+ local cur_ddl=
+ for m in $modules; do
+ cur_ddl=`find $m/src/main/resources/ -name ddl.sql 2>/dev/null`
+ ddl_src="$ddl_src $cur_ddl"
+ done
+ echo "$ddl_src"
+}
+
+
+function create_clean_file() {
+ local ddl_file=$1
+ local tables=`cat $ddl_file | grep -i "create table" | awk ' { print $3 } '`
+
+ local tmp="/tmp/clean-$DATABASE.$$"
+ echo "use $DATABASE;" >> $tmp
+ echo "" >> $tmp
+ for t in $tables; do
+ echo "truncate $t;" >> $tmp
+ done
+ echo $tmp
+}
+
+function create_ddl_file() {
+ local ddls=`find_src_ddl`
+ local test_ddls=
+ if [ ! -z $TEST_ALSO ]; then
+ test_ddls=`find_test_ddl`
+ ddls="$ddls $test_ddls"
+ fi
+
+ local tmp="/tmp/ddl-$DATABASE.$$"
+ touch $tmp
+ echo "use $DATABASE;" >> $tmp
+ echo "" >> $tmp
+ for d in $ddls; do
+ cat $d >> $tmp
+ echo "" >> $tmp
+ done
+ echo $tmp
+}
+
+function cleanup() {
+ rm -f "/tmp/*.$$"
+}
+
+
+while getopts ":a:d:u:pt" options; do
+ case $options in
+ a ) ACTION=$OPTARG;;
+ d ) DATABASE=$OPTARG;;
+ u ) USER=$OPTARG;;
+ p ) PWD=$OPTARG;;
+ t ) TEST_ALSO=1;;
+ h ) usage;;
+ * ) usage;;
+ esac
+done
+
+
+
+if [ -z $ACTION ]; then
+ echo "Need to specify an action <CREATE|CLEAN>"
+ usage
+fi
+
+
+if [ $ACTION == "dump" ]; then
+ DDL_FILE=`create_ddl_file`
+ cat $DDL_FILE
+fi
+
+if [ $ACTION == "create" ]; then
+ DDL_FILE=`create_ddl_file`
+ echo "Applying new schema $tmp to database $DATABASE"
+ mysql -u $USER --password=$PWD < $DDL_FILE
+fi
+
+if [ $ACTION == "clean" ]; then
+ DDL_FILE=`create_ddl_file`
+ CLEAN_FILE=`create_clean_file $DDL_FILE`
+ echo "Cleaning db tables on database $DATABASE"
+ mysql -u $USER --password=$PWD < $DDL_FILE
+fi
+
+cleanup
catalog/pom.xml 6(+6 -0)
diff --git a/catalog/pom.xml b/catalog/pom.xml
index dee138d..60984c5 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -33,6 +33,12 @@
<artifactId>killbill-util</artifactId>
</dependency>
<dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-util</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueState.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueState.java
index 579b759..081edd6 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueState.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueState.java
@@ -44,15 +44,18 @@ public class DefaultOverdueState<T extends Overdueable> extends ValidatingConfig
@XmlElement(required=false, name="externalMessage")
private String externalMessage = "";
- @XmlElement(required=false, name="overrideEntitlementAndChangesBlocked")
- private Boolean overrideEntitlement = false;
+ @XmlElement(required=false, name="disableEntitlementAndChangesBlocked")
+ private Boolean disableEntitlement = false;
- @XmlElement(required=false, name="changesBlocked")
- private Boolean changesBlocked = false;
+ @XmlElement(required=false, name="blockChanges")
+ private Boolean blockChanges = false;
@XmlElement(required=false, name="daysBetweenPaymentRetries")
private Integer daysBetweenPaymentRetries = 8;
+ @XmlElement(required=false, name="isClearState")
+ private Boolean isClearState = false;
+
//Other actions could include
// - send email
// - trigger payment retry?
@@ -78,21 +81,19 @@ public class DefaultOverdueState<T extends Overdueable> extends ValidatingConfig
}
@Override
- public boolean changesBlocked() {
- return changesBlocked && overrideEntitlement;
+ public boolean blockChanges() {
+ return blockChanges || disableEntitlement;
}
/* (non-Javadoc)
* @see com.ning.billing.catalog.overdue.OverdueState#applyCancel()
*/
@Override
- public boolean entitlementDisabledAndChangesBlocked() {
- return overrideEntitlement;
+ public boolean disableEntitlementAndChangesBlocked() {
+ return disableEntitlement;
}
-
-
protected DefaultCondition<T> getCondition() {
return condition;
}
@@ -107,10 +108,15 @@ public class DefaultOverdueState<T extends Overdueable> extends ValidatingConfig
return this;
}
- protected DefaultOverdueState<T> setCancel(boolean cancel) {
- this.overrideEntitlement = cancel;
- return this;
- }
+ protected DefaultOverdueState<T> setDisableEntitlement(boolean cancel) {
+ this.disableEntitlement = cancel;
+ return this;
+ }
+
+ protected DefaultOverdueState<T> setBlockChanges(boolean cancel) {
+ this.blockChanges = cancel;
+ return this;
+ }
protected DefaultOverdueState<T> setCondition(DefaultCondition<T> condition) {
this.condition = condition;
@@ -119,7 +125,7 @@ public class DefaultOverdueState<T extends Overdueable> extends ValidatingConfig
@Override
public boolean isClearState() {
- return false;
+ return isClearState;
}
@Override
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueStateSet.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueStateSet.java
index 9ebc851..4bdcb99 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueStateSet.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueStateSet.java
@@ -16,6 +16,9 @@
package com.ning.billing.catalog.overdue;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
import org.apache.commons.lang.NotImplementedException;
import org.joda.time.DateTime;
@@ -26,10 +29,10 @@ import com.ning.billing.catalog.api.overdue.BillingState;
import com.ning.billing.catalog.api.overdue.OverdueState;
import com.ning.billing.catalog.api.overdue.OverdueStateSet;
import com.ning.billing.catalog.api.overdue.Overdueable;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.util.config.ValidatingConfig;
import com.ning.billing.util.config.ValidationErrors;
+@XmlAccessorType(XmlAccessType.NONE)
public abstract class DefaultOverdueStateSet<T extends Overdueable> extends ValidatingConfig<StandaloneCatalog> implements OverdueStateSet<T> {
private DefaultOverdueState<T> clearState;
@@ -100,5 +103,4 @@ public abstract class DefaultOverdueStateSet<T extends Overdueable> extends Vali
return errors;
}
-
}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueRules.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueRules.java
index 74351cc..8e8b174 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueRules.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueRules.java
@@ -22,7 +22,6 @@ import javax.xml.bind.annotation.XmlElement;
import com.ning.billing.account.api.Account;
import com.ning.billing.catalog.StandaloneCatalog;
-import com.ning.billing.catalog.api.overdue.OverdueStateSet;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.util.config.ValidatingConfig;
import com.ning.billing.util.config.ValidationErrors;
@@ -30,12 +29,8 @@ import com.ning.billing.util.config.ValidationErrors;
@XmlAccessorType(XmlAccessType.NONE)
public class OverdueRules extends ValidatingConfig<StandaloneCatalog> {
- @XmlElement(required=false, name="bundleOverdueStates")
+ @XmlElement(required=true, name="bundleOverdueStates")
private OverdueStatesBundle bundleOverdueStates;
-
- @XmlElement(required=false, name="accountOverdueStates")
- private OverdueStatesAccount accountOverdueStates;
-
public DefaultOverdueStateSet<SubscriptionBundle> getBundleStateSet() {
return bundleOverdueStates;
@@ -47,9 +42,10 @@ public class OverdueRules extends ValidatingConfig<StandaloneCatalog> {
ValidationErrors errors) {
return bundleOverdueStates.validate(root, errors);
}
-
-
- public DefaultOverdueStateSet<Account> getAccountStateSet() {
- return accountOverdueStates;
+
+ public OverdueRules setOverdueStatesBundle(OverdueStatesBundle bundleODS) {
+ this.bundleOverdueStates = bundleODS;
+ return this;
}
+
}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStatesBundle.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStatesBundle.java
index d7736ac..e12050d 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStatesBundle.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStatesBundle.java
@@ -18,15 +18,11 @@ package com.ning.billing.catalog.overdue;
import javax.xml.bind.annotation.XmlElement;
-import com.ning.billing.ErrorCode;
-import com.ning.billing.catalog.StandaloneCatalog;
-import com.ning.billing.catalog.api.CatalogApiException;
-import com.ning.billing.catalog.api.overdue.OverdueState;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.util.config.ValidationErrors;
public class OverdueStatesBundle extends DefaultOverdueStateSet<SubscriptionBundle>{
- @XmlElement(required=false, name="bundleOverdueStages")
+
+ @XmlElement(required=true, name="state")
private DefaultOverdueState<SubscriptionBundle>[] bundleOverdueStates;
@Override
@@ -34,4 +30,8 @@ public class OverdueStatesBundle extends DefaultOverdueStateSet<SubscriptionBund
return bundleOverdueStates;
}
+ protected OverdueStatesBundle setBundleOverdueStates(DefaultOverdueState<SubscriptionBundle>[] bundleOverdueStates) {
+ this.bundleOverdueStates = bundleOverdueStates;
+ return this;
+ }
}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java b/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
index 7208884..fee8c37 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
@@ -27,7 +27,6 @@ import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import com.ning.billing.ErrorCode;
-import com.ning.billing.account.api.Account;
import com.ning.billing.catalog.api.ActionPolicy;
import com.ning.billing.catalog.api.BillingAlignment;
import com.ning.billing.catalog.api.BillingPeriod;
@@ -73,11 +72,11 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
@XmlElement(name="rules", required=true)
private PlanRules planRules;
- @XmlElement(name="overdueRules", required=false)
+ @XmlElement(name="overdueRules", required=true)
private OverdueRules overdueRules;
@XmlElementWrapper(name="plans", required=true)
- @XmlElement(name="plan", required=true)
+ @XmlElement(name="plan", required=true)
private DefaultPlan[] plans;
@XmlElement(name="priceLists", required=true)
@@ -306,10 +305,15 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
return this;
}
- protected StandaloneCatalog setPriceLists(DefaultPriceListSet priceLists) {
- this.priceLists = priceLists;
- return this;
- }
+ protected StandaloneCatalog setPriceLists(DefaultPriceListSet priceLists) {
+ this.priceLists = priceLists;
+ return this;
+ }
+
+ protected StandaloneCatalog setOverdueRules(OverdueRules overdueRules) {
+ this.overdueRules = overdueRules;
+ return this;
+ }
@Override
public boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException {
@@ -328,12 +332,5 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
return overdueRules.getBundleStateSet();
}
- @Override
- public OverdueStateSet<Account> currentAccountOverdueStateSet()
- throws CatalogApiException {
- return overdueRules.getAccountStateSet();
- }
-
-
}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
index c468755..567da32 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
@@ -454,12 +454,6 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
return versionForDate(clock.getUTCNow()).currentBundleOverdueStateSet();
}
- @Override
- public OverdueStateSet<Account> currentAccountOverdueStateSet()
- throws CatalogApiException {
- return versionForDate(clock.getUTCNow()).currentAccountOverdueStateSet();
- }
-
}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
index 244ca49..09fd0e5 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
@@ -18,6 +18,8 @@ package com.ning.billing.catalog;
import java.util.Date;
+import com.ning.billing.catalog.overdue.MockOverdueRules;
+import com.ning.billing.catalog.overdue.OverdueRules;
import com.ning.billing.catalog.rules.CaseCancelPolicy;
import com.ning.billing.catalog.rules.CaseChangePlanAlignment;
import com.ning.billing.catalog.rules.CaseChangePlanPolicy;
@@ -33,9 +35,15 @@ public class MockCatalog extends StandaloneCatalog {
setPlans((DefaultPlan[])MockPlan.createAll());
populateRules();
populatePriceLists();
+ setOverdueRules();
}
- public void populateRules(){
+ public void setOverdueRules() {
+ OverdueRules overdueRules = new MockOverdueRules();
+ setOverdueRules(overdueRules);
+ }
+
+ public void populateRules(){
setPlanRules(new PlanRules());
}
@@ -47,6 +55,8 @@ public class MockCatalog extends StandaloneCatalog {
){
}
+
+
public void populatePriceLists() {
DefaultPlan[] plans = getCurrentPlans();
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockCatalogModule.java b/catalog/src/test/java/com/ning/billing/catalog/MockCatalogModule.java
new file mode 100644
index 0000000..2aceb5b
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockCatalogModule.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.catalog;
+
+import com.google.inject.AbstractModule;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+
+public class MockCatalogModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ CatalogService catalogService = BrainDeadProxyFactory.createBrainDeadProxyFor(CatalogService.class);
+ ((ZombieControl) catalogService).addResult("getCurrentCatalog", new MockCatalog());
+ bind(CatalogService.class).toInstance(catalogService);
+ }
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/overdue/MockOverdueState.java b/catalog/src/test/java/com/ning/billing/catalog/overdue/MockOverdueState.java
new file mode 100644
index 0000000..f3d5a24
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/overdue/MockOverdueState.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.catalog.overdue;
+
+import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
+public class MockOverdueState<T extends Overdueable> extends DefaultOverdueState<T> {
+
+ public MockOverdueState() {
+ setName(MockOverdueAccessModule.CLEAR_STATE);
+ }
+
+ public MockOverdueState(String name, boolean blockChanges, boolean disableEntitlementAndBlockChanges) {
+ setName(name);
+ setBlockChanges(blockChanges);
+ setDisableEntitlement(disableEntitlementAndBlockChanges);
+ }
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/overdue/MockOverdueStatesBundle.java b/catalog/src/test/java/com/ning/billing/catalog/overdue/MockOverdueStatesBundle.java
new file mode 100644
index 0000000..c7532f1
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/overdue/MockOverdueStatesBundle.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.catalog.overdue;
+
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+
+public class MockOverdueStatesBundle extends OverdueStatesBundle {
+
+ public MockOverdueStatesBundle() {
+
+ }
+
+ public MockOverdueStatesBundle(DefaultOverdueState<SubscriptionBundle>[] states) {
+ setBundleOverdueStates(states);
+ }
+
+}
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
index c21aac1..5612fb6 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
@@ -67,6 +67,14 @@
</createAlignmentCase>
</createAlignment>
</rules>
+
+ <overdueRules>
+ <bundleOverdueStates>
+ <state name="ClearBundle">
+ <isClearState>true</isClearState>
+ </state>
+ </bundleOverdueStates>
+ </overdueRules>
<plans>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
index 0e650f1..77ea3bf 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
@@ -68,6 +68,14 @@
</createAlignment>
</rules>
+ <overdueRules>
+ <bundleOverdueStates>
+ <state name="ClearBundle">
+ <isClearState>true</isClearState>
+ </state>
+ </bundleOverdueStates>
+ </overdueRules>
+
<plans>
<plan name="pistol-monthly">
<effectiveDateForExistingSubscriptons>2011-02-14T00:00:00+00:00</effectiveDateForExistingSubscriptons>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
index f7ae066..9c98563 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
@@ -68,6 +68,14 @@
</createAlignment>
</rules>
+ <overdueRules>
+ <bundleOverdueStates>
+ <state name="ClearBundle">
+ <isClearState>true</isClearState>
+ </state>
+ </bundleOverdueStates>
+ </overdueRules>
+
<plans>
<plan name="pistol-monthly">
diff --git a/catalog/src/test/resources/WeaponsHire.xml b/catalog/src/test/resources/WeaponsHire.xml
index 3d36b9d..8fbb1f5 100644
--- a/catalog/src/test/resources/WeaponsHire.xml
+++ b/catalog/src/test/resources/WeaponsHire.xml
@@ -169,7 +169,15 @@ Use Cases to do:
<toPriceList>DEFAULT</toPriceList>
</priceListCase>
</priceList>
- </rules>
+ </rules>
+
+ <overdueRules>
+ <bundleOverdueStates>
+ <state name="ClearBundles">
+ <isClearState>true</isClearState>
+ </state>
+ </bundleOverdueStates>
+ </overdueRules>
<plans>
<plan name="pistol-monthly">
diff --git a/catalog/src/test/resources/WeaponsHireSmall.xml b/catalog/src/test/resources/WeaponsHireSmall.xml
index 21a9f08..2c363c0 100644
--- a/catalog/src/test/resources/WeaponsHireSmall.xml
+++ b/catalog/src/test/resources/WeaponsHireSmall.xml
@@ -70,6 +70,15 @@
</createAlignmentCase>
</createAlignment>
</rules>
+
+ <overdueRules>
+ <bundleOverdueStates>
+ <state name="ClearBundle">
+ <isClearState>true</isClearState>
+ </state>
+ </bundleOverdueStates>
+ </overdueRules>
+
<plans>
<plan name="pistol-monthly">
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java
index 6cbc05f..92b6654 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java
@@ -17,7 +17,6 @@
package com.ning.billing.entitlement.api.billing;
import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,6 +32,7 @@ import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.Product;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.api.user.SubscriptionTransition;
@@ -42,11 +42,13 @@ public class BillCycleDayCalculator {
private static final Logger log = LoggerFactory.getLogger(BillCycleDayCalculator.class);
private final CatalogService catalogService;
+ private final EntitlementUserApi entitlementApi;
@Inject
- public BillCycleDayCalculator(final CatalogService catalogService) {
+ public BillCycleDayCalculator(final CatalogService catalogService, final EntitlementUserApi entitlementApi) {
super();
this.catalogService = catalogService;
+ this.entitlementApi = entitlementApi;
}
protected int calculateBcd(SubscriptionBundle bundle, Subscription subscription, final SubscriptionTransition transition, final Account account) throws CatalogApiException, AccountApiException {
@@ -69,16 +71,16 @@ public class BillCycleDayCalculator {
switch (alignment) {
case ACCOUNT :
result = account.getBillCycleDay();
-
if(result == 0) {
result = calculateBcdFromSubscription(subscription, plan, account);
}
break;
case BUNDLE :
- result = bundle.getStartDate().toDateTime(account.getTimeZone()).getDayOfMonth();
+ Subscription baseSub = entitlementApi.getBaseSubscription(bundle.getId());
+ result = calculateBcdFromSubscription(baseSub, plan, account);
break;
case SUBSCRIPTION :
- result = subscription.getStartDate().toDateTime(account.getTimeZone()).getDayOfMonth();
+ result = calculateBcdFromSubscription(subscription, plan, account);
break;
}
if(result == -1) {
@@ -89,26 +91,8 @@ public class BillCycleDayCalculator {
}
private int calculateBcdFromSubscription(Subscription subscription, Plan plan, Account account) throws AccountApiException {
- int result = account.getBillCycleDay();
- if(result != 0) {
- return result;
- }
- result = new DateTime(account.getTimeZone()).getDayOfMonth();
-
- try {
- result = billCycleDay(subscription.getStartDate(),account.getTimeZone(), plan);
- } catch (CatalogApiException e) {
- log.error("Unexpected catalog error encountered when updating BCD",e);
- }
- return result;
- }
-
- private int billCycleDay(DateTime requestedDate, DateTimeZone timeZone,
- Plan plan) throws CatalogApiException {
-
- DateTime date = plan.dateOfFirstRecurringNonZeroCharge(requestedDate);
- return date.toDateTime(timeZone).getDayOfMonth();
-
+ DateTime date = plan.dateOfFirstRecurringNonZeroCharge(subscription.getStartDate());
+ return date.toDateTime(account.getTimeZone()).getDayOfMonth();
}
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
index 2a4d8ec..b3ada17 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
@@ -16,10 +16,13 @@
package com.ning.billing.entitlement.api.billing;
-import com.ning.billing.catalog.api.CatalogApiException;
+import java.math.BigDecimal;
+
import org.joda.time.DateTime;
+import com.ning.billing.account.api.Account;
import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
@@ -28,9 +31,8 @@ import com.ning.billing.entitlement.api.user.SubscriptionTransition;
import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
-import java.math.BigDecimal;
-
public class DefaultBillingEvent implements BillingEvent {
+ final private Account account;
final private int billCycleDay;
final private Subscription subscription;
final private DateTime effectiveDate;
@@ -45,7 +47,8 @@ public class DefaultBillingEvent implements BillingEvent {
final private SubscriptionTransitionType type;
final private Long totalOrdering;
- public DefaultBillingEvent(SubscriptionTransition transition, Subscription subscription, int billCycleDay, Currency currency) throws CatalogApiException {
+ public DefaultBillingEvent(Account account, SubscriptionTransition transition, Subscription subscription, int billCycleDay, Currency currency) throws CatalogApiException {
+ this.account = account;
this.billCycleDay = billCycleDay;
this.subscription = subscription;
effectiveDate = transition.getEffectiveTransitionTime();
@@ -68,11 +71,11 @@ public class DefaultBillingEvent implements BillingEvent {
totalOrdering = ((SubscriptionTransitionData) transition).getTotalOrdering();
}
- // Intended for test only
- public DefaultBillingEvent(Subscription subscription, DateTime effectiveDate, Plan plan, PlanPhase planPhase,
+ public DefaultBillingEvent(Account account, Subscription subscription, DateTime effectiveDate, Plan plan, PlanPhase planPhase,
BigDecimal fixedPrice, BigDecimal recurringPrice, Currency currency,
BillingPeriod billingPeriod, int billCycleDay, BillingModeType billingModeType,
String description, long totalOrdering, SubscriptionTransitionType type) {
+ this.account = account;
this.subscription = subscription;
this.effectiveDate = effectiveDate;
this.plan = plan;
@@ -103,6 +106,11 @@ public class DefaultBillingEvent implements BillingEvent {
}
@Override
+ public Account getAccount() {
+ return account;
+ }
+
+ @Override
public int getBillCycleDay() {
return billCycleDay;
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
index 32d01b9..1fd595c 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
@@ -71,7 +71,6 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
for (final SubscriptionBundle bundle: bundles) {
List<Subscription> subscriptions = entitlementDao.getSubscriptions(bundle.getId());
-
for (final Subscription subscription: subscriptions) {
for (final SubscriptionTransition transition : ((SubscriptionData) subscription).getBillingTransitions()) {
try {
@@ -82,10 +81,8 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
modifiedData.setBillCycleDay(bcd);
accountApi.updateAccount(account.getExternalKey(), modifiedData, context);
}
-
-
- BillingEvent event = new DefaultBillingEvent(transition, subscription, bcd, account.getCurrency());
+ BillingEvent event = new DefaultBillingEvent(account, transition, subscription, bcd, account.getCurrency());
result.add(event);
} catch (CatalogApiException e) {
log.error("Failing to identify catalog components while creating BillingEvent from transition: " +
@@ -96,6 +93,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
}
}
}
+
return result;
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/OverdueEventCalculator.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/OverdueEventCalculator.java
new file mode 100644
index 0000000..f68e2c9
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/OverdueEventCalculator.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.entitlement.api.billing;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.google.inject.Inject;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.overdue.OverdueState;
+import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.exceptions.EntitlementError;
+import com.ning.billing.util.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.OverdueEvent;
+
+public class OverdueEventCalculator {
+ private final OverdueAccessApi overdueApi;
+ private final CatalogService catalogService;
+
+ protected static class DisabledDuration {
+ private final DateTime start;
+ private final DateTime end;
+
+ public DisabledDuration(DateTime start,DateTime end) {
+ this.start = start;
+ this.end = end;
+ }
+ public DateTime getStart() {
+ return start;
+ }
+ public DateTime getEnd() {
+ return end;
+ }
+
+ }
+
+ protected static class MergeEvent extends OverdueEvent {
+
+ public MergeEvent(DateTime timestamp) {
+ super(null, null, null, timestamp);
+ }
+
+ }
+
+ @Inject
+ public OverdueEventCalculator(OverdueAccessApi overdueApi, CatalogService catalogService) {
+ this.overdueApi = overdueApi;
+ this.catalogService = catalogService;
+ }
+
+ public void insertOverdueEvents(SortedSet<BillingEvent> billingEvents) {
+ if(billingEvents.size() <= 0) { return; }
+
+ Account account = billingEvents.first().getAccount();
+
+ Hashtable<UUID,Set<Subscription>> bundleMap = createBundleSubscriptionMap(billingEvents);
+
+ SortedSet<BillingEvent> billingEventsToAdd = new TreeSet<BillingEvent>();
+ SortedSet<BillingEvent> billingEventsToRemove = new TreeSet<BillingEvent>();
+
+ for(UUID bundleId : bundleMap.keySet()) {
+ SortedSet<OverdueEvent> overdueBundleEvents = overdueApi.getOverdueHistory(bundleId, Overdueable.Type.SUBSCRIPTION_BUNDLE);
+ List<DisabledDuration> bundleDisablePairs = createDisablePairs(overdueBundleEvents);
+
+ for (Subscription subscription: bundleMap.get(bundleId)) {
+ billingEventsToAdd.addAll(createNewEvents( bundleDisablePairs, billingEvents, account, subscription));
+ billingEventsToRemove.addAll(eventsToRemove(bundleDisablePairs, billingEvents, subscription));
+ }
+ }
+
+ for(BillingEvent eventToAdd: billingEventsToAdd ) {
+ billingEvents.add(eventToAdd);
+ }
+
+ for(BillingEvent eventToRemove : billingEventsToRemove) {
+ billingEvents.remove(eventToRemove);
+ }
+
+ }
+
+ protected SortedSet<BillingEvent> eventsToRemove(List<DisabledDuration> disabledDuration,
+ SortedSet<BillingEvent> billingEvents, Subscription subscription) {
+ SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
+
+ SortedSet<BillingEvent> filteredBillingEvents = filter(billingEvents, subscription);
+ for(DisabledDuration duration : disabledDuration) {
+ for(BillingEvent event : filteredBillingEvents) {
+ if(duration.getEnd() == null || event.getEffectiveDate().isBefore(duration.getEnd())) {
+ if( event.getEffectiveDate().isAfter(duration.getStart()) ) { //between the pair
+ result.add(event);
+ }
+ } else { //after the last event of the pair no need to keep checking
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ protected SortedSet<BillingEvent> createNewEvents( List<DisabledDuration> disabledDuration, SortedSet<BillingEvent> billingEvents, Account account, Subscription subscription) {
+ SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
+ for(DisabledDuration duration : disabledDuration) {
+ BillingEvent precedingInitialEvent = precedingBillingEventForSubscription(duration.getStart(), billingEvents, subscription);
+ BillingEvent precedingFinalEvent = precedingBillingEventForSubscription(duration.getEnd(), billingEvents, subscription);
+
+ if(precedingInitialEvent != null) { // there is a preceding billing event
+ result.add(createNewDisableEvent(duration.getStart(), precedingInitialEvent));
+ if(duration.getEnd() != null) { // no second event in the pair means they are still disabled (no re-enable)
+ result.add(createNewReenableEvent(duration.getEnd(), precedingFinalEvent));
+ }
+
+ } else if(precedingFinalEvent != null) { // can happen - e.g. phase event
+ //
+ // TODO: check with Jeff that this is going to do something sensible
+ //
+ result.add(createNewReenableEvent(duration.getEnd(), precedingFinalEvent));
+
+ }
+
+ // N.B. if there's no precedingInitial and no precedingFinal then there's nothing to do
+ }
+ return result;
+ }
+
+ protected BillingEvent precedingBillingEventForSubscription(DateTime datetime, SortedSet<BillingEvent> billingEvents, Subscription subscription) {
+ if(datetime == null) { //second of a pair can be null if there's no re-enabling
+ return null;
+ }
+
+ SortedSet<BillingEvent> filteredBillingEvents = filter(billingEvents, subscription);
+ BillingEvent result = filteredBillingEvents.first();
+
+ if(datetime.isBefore(result.getEffectiveDate())) {
+ //This case can happen, for example, if we have an add on and the bundle goes into disabled before the add on is created
+ return null;
+ }
+
+ for(BillingEvent event : filteredBillingEvents) {
+ if(event.getEffectiveDate().isAfter(datetime)) { // found it its the previous event
+ return result;
+ } else { // still looking
+ result = event;
+ }
+ }
+ return result;
+ }
+
+ protected SortedSet<BillingEvent> filter(SortedSet<BillingEvent> billingEvents, Subscription subscription) {
+ SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
+ for(BillingEvent event : billingEvents) {
+ if(event.getSubscription() == subscription) {
+ result.add(event);
+ }
+ }
+ return result;
+ }
+
+ protected BillingEvent createNewDisableEvent(DateTime odEventTime, BillingEvent previousEvent) {
+ final Account account = previousEvent.getAccount();
+ final int billCycleDay = previousEvent.getBillCycleDay();
+ final Subscription subscription = previousEvent.getSubscription();
+ final DateTime effectiveDate = odEventTime;
+ final PlanPhase planPhase = previousEvent.getPlanPhase();
+ final Plan plan = previousEvent.getPlan();
+ final BigDecimal fixedPrice = BigDecimal.ZERO;
+ final BigDecimal recurringPrice = BigDecimal.ZERO;
+ final Currency currency = previousEvent.getCurrency();
+ final String description = "";
+ final BillingModeType billingModeType = previousEvent.getBillingMode();
+ final BillingPeriod billingPeriod = previousEvent.getBillingPeriod();
+ final SubscriptionTransitionType type = SubscriptionTransitionType.CANCEL;
+ final Long totalOrdering = 0L; //TODO
+
+ return new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
+ fixedPrice, recurringPrice, currency,
+ billingPeriod, billCycleDay, billingModeType,
+ description, totalOrdering, type);
+ }
+
+ protected BillingEvent createNewReenableEvent(DateTime odEventTime, BillingEvent previousEvent) {
+ final Account account = previousEvent.getAccount();
+ final int billCycleDay = previousEvent.getBillCycleDay();
+ final Subscription subscription = previousEvent.getSubscription();
+ final DateTime effectiveDate = odEventTime;
+ final PlanPhase planPhase = previousEvent.getPlanPhase();
+ final Plan plan = previousEvent.getPlan();
+ final BigDecimal fixedPrice = previousEvent.getFixedPrice();
+ final BigDecimal recurringPrice = previousEvent.getRecurringPrice();
+ final Currency currency = previousEvent.getCurrency();
+ final String description = "";
+ final BillingModeType billingModeType = previousEvent.getBillingMode();
+ final BillingPeriod billingPeriod = previousEvent.getBillingPeriod();
+ final SubscriptionTransitionType type = SubscriptionTransitionType.RE_CREATE;
+ final Long totalOrdering = 0L; //TODO
+
+ return new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
+ fixedPrice, recurringPrice, currency,
+ billingPeriod, billCycleDay, billingModeType,
+ description, totalOrdering, type);
+ }
+
+ protected Hashtable<UUID,Set<Subscription>> createBundleSubscriptionMap(SortedSet<BillingEvent> billingEvents) {
+ Hashtable<UUID,Set<Subscription>> result = new Hashtable<UUID,Set<Subscription>>();
+ for(BillingEvent event : billingEvents) {
+ UUID bundleId = event.getSubscription().getBundleId();
+ Set<Subscription> subs = result.get(bundleId);
+ if(subs == null) {
+ subs = new TreeSet<Subscription>();
+ result.put(bundleId,subs);
+ }
+ subs.add(event.getSubscription());
+ }
+ return result;
+ }
+
+
+
+ protected List<DisabledDuration> createDisablePairs(SortedSet<OverdueEvent> overdueBundleEvents) {
+ List<DisabledDuration> result = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ OverdueEvent first = null;
+
+ for(OverdueEvent e : overdueBundleEvents) {
+ if(isDisableEvent(e) && first == null) { // found a transition to disabled
+ first = e;
+ } else if(first != null && !isDisableEvent(e)) { // found a transition from disabled
+ result.add(new DisabledDuration(first.getTimestamp(), e.getTimestamp()));
+ first = null;
+ }
+ }
+
+ if(first != null) { // found a transition to disabled with no terminating event
+ result.add(new DisabledDuration(first.getTimestamp(), null));
+ }
+
+ return result;
+ }
+
+ protected boolean isDisableEvent(OverdueEvent e) {
+ OverdueState<?> state = null;
+ try {
+ if (e.getType() == Overdueable.Type.SUBSCRIPTION_BUNDLE) {
+ state = catalogService.getCurrentCatalog().currentBundleOverdueStateSet().findState(e.getStateName());
+ }
+ } catch (CatalogApiException exp) {
+ throw new EntitlementError(exp);
+ }
+ if (state == null) {
+ throw new EntitlementError("Unable to find an overdue state with name: " + e.getStateName());
+ }
+ return state.disableEntitlementAndChangesBlocked();
+ }
+
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/overdue/DefaultOverdueChecker.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/overdue/DefaultOverdueChecker.java
new file mode 100644
index 0000000..440173f
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/overdue/DefaultOverdueChecker.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.entitlement.api.overdue;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.overdue.OverdueState;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.engine.dao.EntitlementDao;
+import com.ning.billing.util.overdue.OverdueAccessApi;
+
+public class DefaultOverdueChecker implements OverdueChecker {
+
+ private final EntitlementDao dao;
+ private final CatalogService catalogService;
+ private final OverdueAccessApi overdueApi;
+
+ @Inject
+ public DefaultOverdueChecker(EntitlementDao dao, CatalogService catalogService, OverdueAccessApi overdueApi) {
+ this.catalogService = catalogService;
+ this.dao = dao;
+ this.overdueApi = overdueApi;
+ }
+
+ @Override
+ public void checkBlocked(Subscription subscription) throws EntitlementUserApiException {
+ if(subscription.getBundleId() != null) {
+ SubscriptionBundle bundle = dao.getSubscriptionBundleFromId(subscription.getBundleId());
+ checkBlocked(bundle);
+ }
+ }
+
+ @Override
+ public void checkBlocked(SubscriptionBundle bundle) throws EntitlementUserApiException {
+ OverdueState<SubscriptionBundle> bundleState = bundle.getOverdueState();
+ if(bundleState != null && bundleState.blockChanges()) {
+ throw new EntitlementUserApiException(ErrorCode.ENT_BUNDLE_IS_OVERDUE_BLOCKED, bundle.getId(), bundle.getKey());
+ }
+ }
+
+
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
index 20bad8d..a664327 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
@@ -31,7 +31,7 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.Product;
-import com.ning.billing.catalog.api.overdue.OverdueState;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
import com.ning.billing.entitlement.engine.addon.AddonUtils;
@@ -45,17 +45,19 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
private final EntitlementDao dao;
private final CatalogService catalogService;
private final SubscriptionApiService apiService;
+ private final OverdueChecker overdueChecker;
private final AddonUtils addonUtils;
@Inject
public DefaultEntitlementUserApi(Clock clock, EntitlementDao dao, CatalogService catalogService,
- SubscriptionApiService apiService, AddonUtils addonUtils) {
+ SubscriptionApiService apiService, AddonUtils addonUtils, OverdueChecker overdueChecker) {
super();
this.clock = clock;
this.apiService = apiService;
this.dao = dao;
this.catalogService = catalogService;
this.addonUtils = addonUtils;
+ this.overdueChecker = overdueChecker;
}
@Override
@@ -89,16 +91,15 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
}
@Override
+ public Subscription getBaseSubscription(UUID bundleId) {
+ return dao.getBaseSubscription(bundleId);
+ }
+
+ @Override
public SubscriptionBundle createBundleForAccount(UUID accountId, String bundleName)
throws EntitlementUserApiException {
- OverdueState<SubscriptionBundle> clearState;
- try {
- clearState = catalogService.getCurrentCatalog().currentBundleOverdueStateSet().findClearState();
- SubscriptionBundleData bundle = new SubscriptionBundleData(bundleName, accountId);
- return dao.createSubscriptionBundle(bundle);
- } catch (CatalogApiException e) {
- throw new EntitlementUserApiException(e);
- }
+ SubscriptionBundleData bundle = new SubscriptionBundleData(bundleName, accountId);
+ return dao.createSubscriptionBundle(bundle);
}
@Override
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
index 096914c..4a3dcfb 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
@@ -16,26 +16,46 @@
package com.ning.billing.entitlement.api.user;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.joda.time.DateTime;
+
import com.google.inject.Inject;
import com.ning.billing.ErrorCode;
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.ActionPolicy;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanChangeResult;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.Product;
import com.ning.billing.entitlement.alignment.PlanAligner;
import com.ning.billing.entitlement.alignment.TimedPhase;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
import com.ning.billing.entitlement.events.EntitlementEvent;
import com.ning.billing.entitlement.events.phase.PhaseEvent;
import com.ning.billing.entitlement.events.phase.PhaseEventData;
-import com.ning.billing.entitlement.events.user.*;
+import com.ning.billing.entitlement.events.user.ApiEvent;
+import com.ning.billing.entitlement.events.user.ApiEventBuilder;
+import com.ning.billing.entitlement.events.user.ApiEventCancel;
+import com.ning.billing.entitlement.events.user.ApiEventChange;
+import com.ning.billing.entitlement.events.user.ApiEventCreate;
+import com.ning.billing.entitlement.events.user.ApiEventReCreate;
+import com.ning.billing.entitlement.events.user.ApiEventUncancel;
import com.ning.billing.entitlement.exceptions.EntitlementError;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.DefaultClock;
-import org.joda.time.DateTime;
-
-import java.util.ArrayList;
-import java.util.List;
public class SubscriptionApiService {
@@ -43,26 +63,34 @@ public class SubscriptionApiService {
private final EntitlementDao dao;
private final CatalogService catalogService;
private final PlanAligner planAligner;
+ private final OverdueChecker overdueChecker;
@Inject
- public SubscriptionApiService(Clock clock, EntitlementDao dao, CatalogService catalogService, PlanAligner planAligner) {
+ public SubscriptionApiService(Clock clock, EntitlementDao dao, CatalogService catalogService, PlanAligner planAligner, OverdueChecker overdueChecker) {
this.clock = clock;
this.catalogService = catalogService;
this.planAligner = planAligner;
this.dao = dao;
+ this.overdueChecker = overdueChecker;
}
public SubscriptionData createPlan(SubscriptionBuilder builder, Plan plan, PhaseType initialPhase,
String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate)
throws EntitlementUserApiException {
-
+
SubscriptionData subscription = new SubscriptionData(builder, this, clock);
+
+ overdueChecker.checkBlocked(subscription);
+
+
createFromSubscription(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate, processedDate, false);
return subscription;
}
public void recreatePlan(SubscriptionData subscription, PlanPhaseSpecifier spec, DateTime requestedDate)
throws EntitlementUserApiException {
+
+ overdueChecker.checkBlocked(subscription);
SubscriptionState currentState = subscription.getState();
if (currentState != SubscriptionState.CANCELLED) {
@@ -95,6 +123,8 @@ public class SubscriptionApiService {
String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate, boolean reCreate)
throws EntitlementUserApiException {
+ overdueChecker.checkBlocked(subscription);
+
try {
TimedPhase [] curAndNextPhases = planAligner.getCurrentAndNextTimedPhaseOnCreate(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate);
@@ -207,6 +237,8 @@ public class SubscriptionApiService {
public void changePlan(SubscriptionData subscription, String productName, BillingPeriod term,
String priceList, DateTime requestedDate)
throws EntitlementUserApiException {
+
+ overdueChecker.checkBlocked(subscription);
try {
@@ -279,6 +311,7 @@ public class SubscriptionApiService {
}
}
+
public void commitCustomFields(SubscriptionData subscription, CallContext context) {
dao.saveCustomFields(subscription, context);
}
@@ -296,4 +329,6 @@ public class SubscriptionApiService {
requestedDate.toString(), previousTransition.getEffectiveTransitionTime());
}
}
+
+
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
index 8fc1eef..01c33f7 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
@@ -27,8 +27,8 @@ import com.ning.billing.entitlement.api.billing.DefaultEntitlementBillingApi;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
import com.ning.billing.entitlement.api.migration.DefaultEntitlementMigrationApi;
import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
-import com.ning.billing.entitlement.api.overdue.DefaultEntitlementOverdueApi;
-import com.ning.billing.entitlement.api.overdue.EntitlementOverdueApi;
+import com.ning.billing.entitlement.api.overdue.DefaultOverdueChecker;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
import com.ning.billing.entitlement.api.user.DefaultEntitlementUserApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.SubscriptionApiService;
@@ -46,6 +46,10 @@ public class EntitlementModule extends AbstractModule {
protected void installEntitlementDao() {
bind(EntitlementDao.class).to(EntitlementSqlDao.class).asEagerSingleton();
}
+
+ protected void installOverdueChecker() {
+ bind(OverdueChecker.class).to(DefaultOverdueChecker.class).asEagerSingleton();
+ }
protected void installEntitlementCore() {
bind(SubscriptionApiService.class).asEagerSingleton();
@@ -57,7 +61,6 @@ public class EntitlementModule extends AbstractModule {
bind(EntitlementUserApi.class).to(DefaultEntitlementUserApi.class).asEagerSingleton();
bind(EntitlementBillingApi.class).to(DefaultEntitlementBillingApi.class).asEagerSingleton();
bind(EntitlementMigrationApi.class).to(DefaultEntitlementMigrationApi.class).asEagerSingleton();
- bind(EntitlementOverdueApi.class).to(DefaultEntitlementOverdueApi.class).asEagerSingleton();
}
@Override
@@ -65,5 +68,6 @@ public class EntitlementModule extends AbstractModule {
installConfig();
installEntitlementDao();
installEntitlementCore();
+ installOverdueChecker();
}
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java
index 7209239..9a5af34 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java
@@ -133,7 +133,7 @@ public class TestDefaultBillingEvent {
Plan shotgun = new MockPlan();
PlanPhase shotgunMonthly = createMockMonthlyPlanPhase(null, BigDecimal.ZERO, PhaseType.TRIAL);
- return new DefaultBillingEvent(sub , effectiveDate,
+ return new DefaultBillingEvent(null, sub , effectiveDate,
shotgun, shotgunMonthly,
BigDecimal.ZERO, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, billCycleDay,
BillingModeType.IN_ADVANCE, "Test Event 1", totalOrdering, type);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
index c754b2c..c514164 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
@@ -47,6 +47,7 @@ import com.ning.billing.catalog.api.PriceList;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.glue.CatalogModule;
import com.ning.billing.entitlement.api.TestApiBase;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
@@ -80,7 +81,6 @@ public class TestDefaultEntitlementBillingApi {
private Clock clock;
private SubscriptionData subscription;
- private CallContextFactory factory;
private DateTime subscriptionStartDate;
@BeforeSuite(alwaysRun=true)
@@ -90,7 +90,6 @@ public class TestDefaultEntitlementBillingApi {
catalogService = g.getInstance(CatalogService.class);
clock = g.getInstance(Clock.class);
- factory = g.getInstance(CallContextFactory.class);
((DefaultCatalogService)catalogService).loadCatalog();
}
@@ -135,10 +134,12 @@ public class TestDefaultEntitlementBillingApi {
Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
((ZombieControl) account).addResult("getId", accountId).addResult("getCurrency", Currency.USD);
- AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+ AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
((ZombieControl) accountApi).addResult("getAccountById", account);
- BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService);
+ EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+ BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
CallContextFactory factory = new DefaultCallContextFactory(clock);
DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, dao, accountApi, bcdCalculator);
SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
@@ -163,7 +164,9 @@ public class TestDefaultEntitlementBillingApi {
((ZombieControl)account).addResult("getCurrency", Currency.USD);
((ZombieControl)accountApi).addResult("getAccountById", account);
- BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService);
+ EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+ BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
CallContextFactory factory = new DefaultCallContextFactory(clock);
DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, dao, accountApi, bcdCalculator);
SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
@@ -189,7 +192,10 @@ public class TestDefaultEntitlementBillingApi {
AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
((ZombieControl)accountApi).addResult("getAccountById", account);
- BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService);
+
+ EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+ BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
CallContextFactory factory = new DefaultCallContextFactory(clock);
DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, dao, accountApi, bcdCalculator);
SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
@@ -214,7 +220,9 @@ public class TestDefaultEntitlementBillingApi {
((ZombieControl)account).addResult("getCurrency", Currency.USD);
((ZombieControl)accountApi).addResult("getAccountById", account);
- BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService);
+ EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+ BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
CallContextFactory factory = new DefaultCallContextFactory(clock);
DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, dao, accountApi, bcdCalculator);
SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
@@ -237,14 +245,18 @@ public class TestDefaultEntitlementBillingApi {
((ZombieControl)account).addResult("getBillCycleDay", 1).addResult("getTimeZone", DateTimeZone.UTC);
((ZombieControl)account).addResult("getCurrency", Currency.USD);
- AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
- ((ZombieControl)accountApi).addResult("getAccountById", account);
- BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService);
+ AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+ ((ZombieControl)accountApi).addResult("getAccountById", account);
+
+ EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+ ((ZombieControl) entitlementApi).addResult("getBaseSubscription", subscription);
+
+ BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
CallContextFactory factory = new DefaultCallContextFactory(clock);
DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, dao, accountApi, bcdCalculator);
SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
- checkFirstEvent(events, nextPlan, bundles.get(0).getStartDate().getDayOfMonth(), oneId, now, nextPhase, ApiEventType.CREATE.toString());
+ checkFirstEvent(events, nextPlan, subscription.getStartDate().plusDays(30).getDayOfMonth(), oneId, now, nextPhase, ApiEventType.CREATE.toString());
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java
new file mode 100644
index 0000000..06d2ae1
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java
@@ -0,0 +1,771 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.entitlement.api.billing;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.catalog.MockCatalog;
+import com.ning.billing.catalog.MockPlan;
+import com.ning.billing.catalog.MockPlanPhase;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
+import com.ning.billing.catalog.overdue.DefaultOverdueState;
+import com.ning.billing.catalog.overdue.MockOverdueRules;
+import com.ning.billing.catalog.overdue.MockOverdueState;
+import com.ning.billing.catalog.overdue.MockOverdueStatesBundle;
+import com.ning.billing.catalog.overdue.OverdueRules;
+import com.ning.billing.catalog.overdue.OverdueStatesBundle;
+import com.ning.billing.entitlement.api.billing.OverdueEventCalculator.DisabledDuration;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.OverdueEvent;
+import com.ning.billing.util.overdue.dao.OverdueAccessDao;
+
+public class TestOverdueEventCalculator {
+
+ private static final String DISABLED_BUNDLE = "disabled-bundle";
+ private static final String CLEAR_BUNDLE = "clear-bundle";
+
+
+ private static final DefaultOverdueState<SubscriptionBundle> CLEAR_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(CLEAR_BUNDLE, false, false);
+ private static final DefaultOverdueState<SubscriptionBundle> DISABLED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(DISABLED_BUNDLE, false, true);
+
+ private OverdueAccessApi overdueAccessApi;
+ private Account account;
+ private Subscription subscription1;
+ private Subscription subscription2;
+ private Subscription subscription3;
+ private Subscription subscription4;
+ private UUID bundleId1 = UUID.randomUUID();
+ private UUID bundleId2 = UUID.randomUUID();
+ private Clock clock;
+ private OverdueEventCalculator odc;
+
+ @BeforeClass
+ public void setUpBeforeClass() throws Exception {
+
+ @SuppressWarnings("unchecked")
+ final OverdueStatesBundle bundleODS = new MockOverdueStatesBundle(new DefaultOverdueState[] {
+ CLEAR_BUNDLE_STATE, DISABLED_BUNDLE_STATE });
+
+ clock = new ClockMock();
+
+ Injector i = Guice.createInjector(new AbstractModule() {
+
+ @Override
+ protected void configure() {
+ overdueAccessApi = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessApi.class);
+ account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+ subscription1 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+ subscription2 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+ subscription3 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+ subscription4 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+ ((ZombieControl) subscription1).addResult("getBundleId", bundleId1);
+ ((ZombieControl) subscription2).addResult("getBundleId", bundleId1);
+ ((ZombieControl) subscription3).addResult("getBundleId", bundleId1);
+ ((ZombieControl) subscription4).addResult("getBundleId", bundleId2);
+ ((ZombieControl) subscription1).addResult("compareTo", 1);
+ ((ZombieControl) subscription2).addResult("compareTo", 1);
+ ((ZombieControl) subscription3).addResult("compareTo", 1);
+ ((ZombieControl) subscription4).addResult("compareTo", 1);
+ ((ZombieControl) subscription1).addResult("getId", UUID.randomUUID());
+ ((ZombieControl) subscription2).addResult("getId", UUID.randomUUID());
+ ((ZombieControl) subscription3).addResult("getId", UUID.randomUUID());
+ ((ZombieControl) subscription4).addResult("getId", UUID.randomUUID());
+
+ // bind(OverdueChecker.class).to(DefaultOverdueChecker.class).asEagerSingleton();
+ CatalogService catalogService = BrainDeadProxyFactory.createBrainDeadProxyFor(CatalogService.class);
+ ((ZombieControl) catalogService).addResult("getCurrentCatalog", new MockCatalog() {
+
+ @Override
+ public void setOverdueRules() {
+ OverdueRules overdueRules = new MockOverdueRules().setOverdueStatesBundle(bundleODS);
+ setOverdueRules(overdueRules);
+ }
+
+ });
+ bind(CatalogService.class).toInstance(catalogService);
+
+
+ bind(OverdueAccessDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessDao.class));
+ bind(OverdueAccessApi.class).toInstance(overdueAccessApi);
+
+ }
+
+ });
+ odc = i.getInstance(OverdueEventCalculator.class);
+
+ }
+
+ @Test
+ // S1-S2-S3 subscriptions in B1
+ // B1 -----[--------]
+ // S1 --A-------------------------------------
+ // S2 --B------C------------------------------
+ // S3 ------------------D---------------------
+
+
+ //Result
+ // S1 --A--[-------]--------------------------
+ // S2 --B--[-------]--------------------------
+ // S3 ------------------D---------------------
+
+ public void testInsertOverdueEvents() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, null));
+ BillingEvent A = createRealEvent(now.minusDays(1).minusHours(1), subscription1);
+ BillingEvent B = createRealEvent(now.minusDays(1), subscription2);
+ BillingEvent C = createRealEvent(now.plusDays(1), subscription2);
+ BillingEvent D = createRealEvent(now.plusDays(3), subscription3);
+ billingEvents.add(A);
+ billingEvents.add(B);
+ billingEvents.add(C);
+ billingEvents.add(D);
+
+ SortedSet<OverdueEvent> overdueBundleEvents = new TreeSet<OverdueEvent>();
+ overdueBundleEvents.add(new OverdueEvent(bundleId1,DISABLED_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now));
+ overdueBundleEvents.add(new OverdueEvent(bundleId1,CLEAR_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now.plusDays(2)));
+
+ ((ZombieControl)overdueAccessApi).addResult("getOverdueHistory", overdueBundleEvents);
+
+
+ odc.insertOverdueEvents(billingEvents);
+
+ assertEquals(billingEvents.size(), 7);
+
+ SortedSet<BillingEvent> s1Events = odc.filter(billingEvents, subscription1);
+ Iterator<BillingEvent> it1 = s1Events.iterator();
+ assertEquals(it1.next(), A);
+ assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.CANCEL);
+ assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+
+ SortedSet<BillingEvent> s2Events = odc.filter(billingEvents, subscription2);
+ Iterator<BillingEvent> it2 = s2Events.iterator();
+ assertEquals(it2.next(), B);
+ assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.CANCEL);
+ assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+
+ SortedSet<BillingEvent> s3Events = odc.filter(billingEvents, subscription3);
+ Iterator<BillingEvent> it3 = s3Events.iterator();
+ assertEquals(it3.next(),D);
+ }
+
+ // Open ended duration with a previous event
+ // --X--[----------------------------------
+ @Test
+ public void testEventsToRemoveOpenPrev() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, null));
+ billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+
+ SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+
+ assertEquals(results.size(), 0);
+ }
+
+ // Open with previous and following events
+ // --X--[----Y-----------------------------
+ @Test
+ public void testEventsToRemoveOpenPrevFollow() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, null));
+ BillingEvent e1 = createRealEvent(now.minusDays(1), subscription1);
+ BillingEvent e2 = createRealEvent(now.plusDays(1), subscription1);
+ billingEvents.add(e1);
+ billingEvents.add(e2);
+
+ SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+
+ assertEquals(results.size(), 1);
+ assertEquals(results.first(), e2);
+ }
+
+ // Open with no previous event (only following)
+ // -----[----X-----------------------------
+ @Test
+ public void testEventsToRemoveOpenFollow() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, null));
+ BillingEvent e1 = createRealEvent(now.plusDays(1), subscription1);
+ billingEvents.add(e1);
+
+ SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+
+ assertEquals(results.size(), 1);
+ assertEquals(results.first(), e1);
+ }
+
+ // Closed duration with a single previous event
+ // --X--[------------]---------------------
+ @Test
+ public void testEventsToRemoveClosedPrev() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+ BillingEvent e1 = createRealEvent(now.minusDays(1), subscription1);
+ billingEvents.add(e1);
+
+ SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+
+ assertEquals(results.size(), 0);
+ }
+
+ // Closed duration with a previous event and in-between event
+ // --X--[------Y-----]---------------------
+ @Test
+ public void testEventsToRemoveClosedPrevBetw() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+ billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+ billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+
+ SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+
+ assertEquals(results.size(), 2);
+ assertEquals(results.first().getEffectiveDate(), now);
+ assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+ assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+ assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+ assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+ assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+ }
+
+ // Closed duration with a previous event and in-between event and following
+ // --X--[------Y-----]-------Z-------------
+ @Test
+ public void testEventsToRemoveClosedPrevBetwNext() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+ BillingEvent e1 = createRealEvent(now.minusDays(1), subscription1);
+ BillingEvent e2 = createRealEvent(now.plusDays(1), subscription1);
+ BillingEvent e3 = createRealEvent(now.plusDays(3), subscription1);
+ billingEvents.add(e1);
+ billingEvents.add(e2);
+ billingEvents.add(e3);
+
+ SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+
+ assertEquals(results.size(), 1);
+ assertEquals(results.first(), e2);
+ }
+
+ // Closed with no previous event but in-between events
+ // -----[------Y-----]---------------------
+ @Test
+ public void testEventsToRemoveClosedBetwn() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+ BillingEvent e2 = createRealEvent(now.plusDays(1), subscription1);
+ billingEvents.add(e2);
+
+
+ SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+
+ assertEquals(results.size(), 1);
+ assertEquals(results.first(), e2);
+ }
+
+ // Closed with no previous event but in-between events and following
+ // -----[------Y-----]-------Z-------------
+ @Test
+ public void testEventsToRemoveClosedBetweenFollow() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+
+ BillingEvent e2 = createRealEvent(now.plusDays(1), subscription1);
+ BillingEvent e3 = createRealEvent(now.plusDays(3), subscription1);
+ billingEvents.add(e2);
+ billingEvents.add(e3);
+
+ SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+
+ assertEquals(results.size(), 1);
+ assertEquals(results.first(), e2);
+ }
+
+ // Closed duration with only following
+ // -----[------------]-------Z-------------
+ @Test
+ public void testEventsToRemoveClosedFollow() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+
+ BillingEvent e3 = createRealEvent(now.plusDays(3), subscription1);
+
+ billingEvents.add(e3);
+
+ SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+
+ assertEquals(results.size(), 0);
+ }
+
+ // Open ended duration with a previous event
+ // --X--[----------------------------------
+ @Test
+ public void testCreateNewEventsOpenPrev() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, null));
+ billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+
+ SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents, account, subscription1);
+
+ assertEquals(results.size(), 1);
+ assertEquals(results.first().getEffectiveDate(), now);
+ assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+ assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+ }
+
+ // Open with previous and following events
+ // --X--[----Y-----------------------------
+ @Test
+ public void testCreateNewEventsOpenPrevFollow() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, null));
+ billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+ billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+
+ SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents, account, subscription1);
+
+ assertEquals(results.size(), 1);
+ assertEquals(results.first().getEffectiveDate(), now);
+ assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+ assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+ }
+
+ // Open with no previous event (only following)
+ // -----[----X-----------------------------
+ @Test
+ public void testCreateNewEventsOpenFollow() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, null));
+ billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+
+ SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents, account, subscription1);
+
+ assertEquals(results.size(), 0);
+ }
+
+ // Closed duration with a single previous event
+ // --X--[------------]---------------------
+ @Test
+ public void testCreateNewEventsClosedPrev() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+ billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+
+ SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents, account, subscription1);
+
+ assertEquals(results.size(), 2);
+ assertEquals(results.first().getEffectiveDate(), now);
+ assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+ assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+ assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+ assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+ assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+ }
+
+ // Closed duration with a previous event and in-between event
+ // --X--[------Y-----]---------------------
+ @Test
+ public void testCreateNewEventsClosedPrevBetw() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+ billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+ billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+
+ SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents, account, subscription1);
+
+ assertEquals(results.size(), 2);
+ assertEquals(results.first().getEffectiveDate(), now);
+ assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+ assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+ assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+ assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+ assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+ }
+
+ // Closed duration with a previous event and in-between event and following
+ // --X--[------Y-----]-------Z-------------
+ @Test
+ public void testCreateNewEventsClosedPrevBetwNext() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+ billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+ billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+ billingEvents.add(createRealEvent(now.plusDays(3), subscription1));
+
+ SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents, account, subscription1);
+
+ assertEquals(results.size(), 2);
+ assertEquals(results.first().getEffectiveDate(), now);
+ assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+ assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+ assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+ assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+ assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+ }
+
+ // Closed with no previous event but in-between events
+ // -----[------Y-----]---------------------
+ @Test
+ public void testCreateNewEventsClosedBetwn() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+ billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+
+ SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents, account, subscription1);
+
+ assertEquals(results.size(), 1);
+ assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+ assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+ assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+ }
+
+ // Closed with no previous event but in-between events and following
+ // -----[------Y-----]-------Z-------------
+ @Test
+ public void testCreateNewEventsClosedBetweenFollow() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+ billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+
+ SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents, account, subscription1);
+
+ assertEquals(results.size(), 1);
+ assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+ assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+ assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+ }
+
+ // Closed duration with only following
+ // -----[------------]-------Z-------------
+ @Test
+ public void testCreateNewEventsClosedFollow() {
+ DateTime now = clock.getUTCNow();
+ List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+ SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+
+ disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+ billingEvents.add(createRealEvent(now.plusDays(3), subscription1));
+
+ SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents, account, subscription1);
+
+ assertEquals(results.size(), 0);
+ }
+
+ @Test
+ public void testPrecedingBillingEventForSubscription() {
+ DateTime now = new DateTime();
+
+ SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+
+ events.add(createRealEvent(now.minusDays(10), subscription1));
+ events.add(createRealEvent(now.minusDays(6), subscription1));
+ events.add(createRealEvent(now.minusDays(5), subscription1));
+ events.add(createRealEvent(now.minusDays(1), subscription1));
+
+ BillingEvent minus11 = odc.precedingBillingEventForSubscription(now.minusDays(11), events, subscription1);
+ assertNull(minus11);
+
+ BillingEvent minus5andAHalf= odc.precedingBillingEventForSubscription(now.minusDays(5).minusHours(12), events, subscription1);
+ assertNotNull(minus5andAHalf);
+ assertEquals(minus5andAHalf.getEffectiveDate(), now.minusDays(6));
+
+
+ }
+
+ protected BillingEvent createRealEvent(DateTime effectiveDate, Subscription subscription) {
+ final Account account = this.account;
+ final int billCycleDay = 1;
+ final PlanPhase planPhase = new MockPlanPhase();
+ final Plan plan = new MockPlan();
+ final BigDecimal fixedPrice = BigDecimal.TEN;
+ final BigDecimal recurringPrice = BigDecimal.TEN;
+ final Currency currency = Currency.USD;
+ final String description = "";
+ final BillingModeType billingModeType = BillingModeType.IN_ADVANCE;
+ final BillingPeriod billingPeriod = BillingPeriod.MONTHLY;
+ final SubscriptionTransitionType type = SubscriptionTransitionType.CHANGE;
+ final Long totalOrdering = 0L; //TODO
+
+ return new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
+ fixedPrice, recurringPrice, currency,
+ billingPeriod, billCycleDay, billingModeType,
+ description, totalOrdering, type);
+ }
+
+
+ @Test
+ public void testFilter() {
+ SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+
+ events.add(createBillingEvent(subscription1));
+ events.add(createBillingEvent(subscription1));
+ events.add(createBillingEvent(subscription1));
+ events.add(createBillingEvent(subscription2));
+
+ SortedSet<BillingEvent> result1 = odc.filter(events, subscription1);
+ SortedSet<BillingEvent> result2 = odc.filter(events, subscription2);
+ SortedSet<BillingEvent> result3 = odc.filter(events, subscription3);
+
+ assertEquals(result1.size(), 3);
+ assertEquals(result1.first().getSubscription(), subscription1);
+ assertEquals(result1.last().getSubscription(), subscription1);
+ assertEquals(result2.size(), 1);
+ assertEquals(result2.first().getSubscription(), subscription2);
+ assertEquals(result3.size(), 0);
+ }
+
+ @Test
+ public void testCreateNewDisableEvent() {
+ DateTime now = clock.getUTCNow();
+ BillingEvent event = new MockBillingEvent();
+
+ BillingEvent result = odc.createNewDisableEvent(now, event);
+ assertEquals(result.getBillCycleDay(),event.getBillCycleDay());
+ assertEquals(result.getEffectiveDate(), now);
+ assertEquals(result.getPlanPhase(), event.getPlanPhase());
+ assertEquals(result.getPlan(), event.getPlan());
+ assertEquals(result.getFixedPrice(),BigDecimal.ZERO);
+ assertEquals(result.getRecurringPrice(), BigDecimal.ZERO);
+ assertEquals(result.getCurrency(), event.getCurrency());
+ assertEquals(result.getDescription(), "");
+ assertEquals(result.getBillingMode(), event.getBillingMode());
+ assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
+ assertEquals(result.getTransitionType(), SubscriptionTransitionType.CANCEL);
+ assertEquals(result.getTotalOrdering(), new Long(0));
+ }
+
+ @Test
+ public void testCreateNewReenableEvent() {
+ DateTime now = clock.getUTCNow();
+ BillingEvent event = new MockBillingEvent();
+
+ BillingEvent result = odc.createNewReenableEvent(now, event);
+ assertEquals(result.getBillCycleDay(),event.getBillCycleDay());
+ assertEquals(result.getEffectiveDate(), now);
+ assertEquals(result.getPlanPhase(), event.getPlanPhase());
+ assertEquals(result.getPlan(), event.getPlan());
+ assertEquals(result.getFixedPrice(),event.getFixedPrice());
+ assertEquals(result.getRecurringPrice(), event.getRecurringPrice());
+ assertEquals(result.getCurrency(), event.getCurrency());
+ assertEquals(result.getDescription(), "");
+ assertEquals(result.getBillingMode(), event.getBillingMode());
+ assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
+ assertEquals(result.getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+ assertEquals(result.getTotalOrdering(), new Long(0));
+ }
+
+ private class MockBillingEvent extends DefaultBillingEvent {
+ public MockBillingEvent() {
+ super(account, subscription1, clock.getUTCNow(), null, null, BigDecimal.ZERO, BigDecimal.TEN, Currency.USD, BillingPeriod.ANNUAL,
+ 4, BillingModeType.IN_ADVANCE, "", 3L, SubscriptionTransitionType.CREATE);
+ }
+ }
+
+ @Test
+ public void testCreateBundleSubscriptionMap() {
+ SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+ events.add(createBillingEvent(subscription1));
+ events.add(createBillingEvent(subscription2));
+ events.add(createBillingEvent(subscription3));
+ events.add(createBillingEvent(subscription4));
+
+ Hashtable<UUID,Set<Subscription>> map = odc.createBundleSubscriptionMap(events);
+
+ assertNotNull(map);
+ assertEquals(map.keySet().size(),2);
+ assertEquals(map.get(bundleId1).size(), 3);
+ assertEquals(map.get(bundleId2).size(), 1);
+
+ }
+
+ private BillingEvent createBillingEvent(Subscription subscription) {
+ BillingEvent result = BrainDeadProxyFactory.createBrainDeadProxyFor(BillingEvent.class, Comparable.class);
+ ((ZombieControl)result).addResult("getSubscription", subscription);
+ ((ZombieControl)result).addResult("compareTo", 1);
+ return result;
+ }
+
+ @Test
+ public void testCreateDisablePairs() {
+ SortedSet<OverdueEvent> overdueBundleEvents;
+ UUID ovdId = UUID.randomUUID();
+ DateTime now = clock.getUTCNow();
+
+ //simple events open clear -> disabled
+ overdueBundleEvents = new TreeSet<OverdueEvent>();
+ overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+
+ List<DisabledDuration> pairs = odc.createDisablePairs(overdueBundleEvents);
+ assertEquals(pairs.size(), 1);
+ assertNotNull(pairs.get(0).getStart());
+ assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+ assertNull(pairs.get(0).getEnd());
+
+ //simple events closed clear -> disabled
+ overdueBundleEvents = new TreeSet<OverdueEvent>();
+ overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+
+ pairs = odc.createDisablePairs(overdueBundleEvents);
+ assertEquals(pairs.size(), 1);
+ assertNotNull(pairs.get(0).getStart());
+ assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+ assertNotNull(pairs.get(0).getEnd());
+ assertEquals(pairs.get(0).getEnd(),now.plusDays(2));
+
+ //simple BUNDLE events closed clear -> disabled
+ overdueBundleEvents = new TreeSet<OverdueEvent>();
+ overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+
+ pairs = odc.createDisablePairs(overdueBundleEvents);
+ assertEquals(pairs.size(), 1);
+ assertNotNull(pairs.get(0).getStart());
+ assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+ assertNotNull(pairs.get(0).getEnd());
+ assertEquals(pairs.get(0).getEnd(),now.plusDays(2));
+
+
+ //two or more disableds in a row
+ overdueBundleEvents = new TreeSet<OverdueEvent>();
+ overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(3)));
+
+ pairs = odc.createDisablePairs(overdueBundleEvents);
+ assertEquals(pairs.size(), 1);
+ assertNotNull(pairs.get(0).getStart());
+ assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+ assertNotNull(pairs.get(0).getEnd());
+ assertEquals(pairs.get(0).getEnd(),now.plusDays(3));
+
+
+ overdueBundleEvents = new TreeSet<OverdueEvent>();
+ overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(3)));
+ overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(4)));
+
+ pairs = odc.createDisablePairs(overdueBundleEvents);
+ assertEquals(pairs.size(), 1);
+ assertNotNull(pairs.get(0).getStart());
+ assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+ assertNotNull(pairs.get(0).getEnd());
+ assertEquals(pairs.get(0).getEnd(),now.plusDays(4));
+
+ }
+
+ @Test
+ public void testIsDisableEvent() {
+ DateTime now = clock.getUTCNow();
+ assertTrue(!odc.isDisableEvent(new OverdueEvent(new UUID(0L,0L), CLEAR_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now)));
+ assertTrue(odc.isDisableEvent(new OverdueEvent(new UUID(0L,0L), DISABLED_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now)));
+ }
+
+}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
index 6ea53bc..c7e155d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
@@ -22,6 +22,7 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
@Test(groups = "fast")
public class TestMigrationMemory extends TestMigration {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
index 587ca46..67b0371 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
@@ -22,6 +22,7 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
@Test(groups = "slow")
public class TestMigrationSql extends TestMigration {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java
new file mode 100644
index 0000000..e9fbc85
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.entitlement.api.overdue;
+
+import java.util.UUID;
+
+import junit.framework.Assert;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.ning.billing.catalog.MockCatalog;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.overdue.OverdueState;
+import com.ning.billing.catalog.overdue.DefaultOverdueState;
+import com.ning.billing.catalog.overdue.MockOverdueRules;
+import com.ning.billing.catalog.overdue.MockOverdueState;
+import com.ning.billing.catalog.overdue.MockOverdueStatesBundle;
+import com.ning.billing.catalog.overdue.OverdueRules;
+import com.ning.billing.catalog.overdue.OverdueStatesBundle;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.engine.dao.EntitlementDao;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.dao.OverdueAccessDao;
+
+public class TestOverdueChecker {
+
+
+ private static final String DISABLED_AND_BLOCKED_BUNDLE = "disabled-blocked-bundle";
+ private static final String DISABLED_BUNDLE = "disabled-bundle";
+ private static final String BLOCKED_BUNDLE = "blocked-bundle";
+ private static final String CLEAR_BUNDLE = "clear-bundle";
+
+
+ private static final DefaultOverdueState<SubscriptionBundle> CLEAR_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(CLEAR_BUNDLE, false, false);
+ private static final DefaultOverdueState<SubscriptionBundle> BLOCKED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(BLOCKED_BUNDLE, true, false);
+ private static final DefaultOverdueState<SubscriptionBundle> DISABLED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(DISABLED_BUNDLE, false, true);
+ private static final DefaultOverdueState<SubscriptionBundle> DISABLED_AND_BLOCKED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(DISABLED_AND_BLOCKED_BUNDLE, true, true) ;
+
+
+ private OverdueChecker checker;
+ private OverdueAccessApi overdueAccessApi;
+ private Subscription subscription;
+ private SubscriptionBundle bundle;
+
+ @BeforeClass(groups={"fast"})
+ public void setup() {
+ overdueAccessApi = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessApi.class);
+ subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
+ bundle = BrainDeadProxyFactory.createBrainDeadProxyFor(SubscriptionBundle.class);
+ ((ZombieControl) bundle).addResult("getAccountId", new UUID(0L,0L));
+ ((ZombieControl) bundle).addResult("getId", new UUID(0L,0L));
+ ((ZombieControl) bundle).addResult("getKey", "key");
+ ((ZombieControl) subscription).addResult("getBundleId", new UUID(0L,0L));
+
+ @SuppressWarnings("unchecked")
+ final OverdueStatesBundle bundleODS = new MockOverdueStatesBundle(new DefaultOverdueState[] {
+ CLEAR_BUNDLE_STATE,BLOCKED_BUNDLE_STATE, DISABLED_BUNDLE_STATE, DISABLED_AND_BLOCKED_BUNDLE_STATE
+ });
+
+ Injector i = Guice.createInjector(new AbstractModule() {
+
+ @Override
+ protected void configure() {
+ bind(OverdueChecker.class).to(DefaultOverdueChecker.class).asEagerSingleton();
+ CatalogService catalogService = BrainDeadProxyFactory.createBrainDeadProxyFor(CatalogService.class);
+ ((ZombieControl) catalogService).addResult("getCurrentCatalog", new MockCatalog() {
+
+ @Override
+ public void setOverdueRules() {
+ OverdueRules overdueRules = new MockOverdueRules().setOverdueStatesBundle(bundleODS);
+ setOverdueRules(overdueRules);
+ }
+
+ });
+ bind(CatalogService.class).toInstance(catalogService);
+
+
+ bind(OverdueAccessDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessDao.class));
+ bind(OverdueAccessApi.class).toInstance(overdueAccessApi);
+
+
+ EntitlementDao entitlementDao = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementDao.class);
+ //((ZombieControl) entitlementDao).addResult("", result)
+ bind(EntitlementDao.class).toInstance(entitlementDao);
+ ((ZombieControl) entitlementDao).addResult("getSubscriptionBundleFromId",bundle);
+
+ }
+
+ });
+ checker = i.getInstance(OverdueChecker.class);
+ }
+
+
+ private void setStateBundle(OverdueState<SubscriptionBundle> state) {
+ ((ZombieControl) bundle).addResult("getOverdueState", state);
+ }
+
+ @Test(groups={"fast"}, enabled = true)
+ public void testSubscriptionChecker() throws EntitlementUserApiException {
+ setStateBundle(CLEAR_BUNDLE_STATE);
+ checker.checkBlocked(bundle);
+
+ //BLOCKED BUNDLE
+ try {
+ setStateBundle(BLOCKED_BUNDLE_STATE);
+ checker.checkBlocked(subscription);
+ Assert.fail("The call should have been blocked!");
+ } catch (EntitlementUserApiException e) {
+ //Expected behavior
+ }
+
+ //DISABLED BUNDLE
+ try {
+ setStateBundle(DISABLED_BUNDLE_STATE);
+ checker.checkBlocked(subscription);
+ Assert.fail("The call should have been blocked!");
+ } catch (EntitlementUserApiException e) {
+ //Expected behavior
+ }
+
+ try {
+ setStateBundle(DISABLED_AND_BLOCKED_BUNDLE_STATE);
+ checker.checkBlocked(subscription);
+ Assert.fail("The call should have been blocked!");
+ } catch (EntitlementUserApiException e) {
+ //Expected behavior
+ }
+
+ setStateBundle(CLEAR_BUNDLE_STATE);
+ checker.checkBlocked(subscription);
+
+ }
+
+ @Test(groups={"fast"}, enabled = true)
+ public void testBundleChecker() throws EntitlementUserApiException {
+ setStateBundle(CLEAR_BUNDLE_STATE);
+ checker.checkBlocked(bundle);
+
+
+ //BLOCKED BUNDLE
+ try {
+ setStateBundle(BLOCKED_BUNDLE_STATE);
+ checker.checkBlocked(bundle);
+ Assert.fail("The call should have been blocked!");
+ } catch (EntitlementUserApiException e) {
+ //Expected behavior
+ }
+
+
+ //DISABLED BUNDLE
+ try {
+ setStateBundle(DISABLED_BUNDLE_STATE);
+ checker.checkBlocked(bundle);
+ Assert.fail("The call should have been blocked!");
+ } catch (EntitlementUserApiException e) {
+ //Expected behavior
+ }
+
+ //BLOCKED AND DISABLED BUNDLE
+ try {
+ setStateBundle(DISABLED_AND_BLOCKED_BUNDLE_STATE);
+ checker.checkBlocked(bundle);
+ Assert.fail("The call should have been blocked!");
+ } catch (EntitlementUserApiException e) {
+ //Expected behavior
+ }
+
+ setStateBundle(CLEAR_BUNDLE_STATE);
+ checker.checkBlocked(bundle);
+
+ }
+
+
+
+}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
index 59121c9..a770b4d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
@@ -72,6 +72,7 @@ import com.ning.billing.entitlement.events.user.ApiEvent;
import com.ning.billing.entitlement.events.user.ApiEventType;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.bus.Bus.EventBusException;
import com.ning.billing.util.bus.DefaultBusService;
import com.ning.billing.util.bus.BusService;
@@ -184,7 +185,7 @@ public abstract class TestApiBase {
}
@BeforeMethod(alwaysRun = true)
- public void setupTest() {
+ public void setupTest() throws Exception {
log.warn("RESET TEST FRAMEWORK\n\n");
@@ -192,13 +193,10 @@ public abstract class TestApiBase {
clock.resetDeltaFromReality();
((MockEntitlementDao) dao).reset();
- try {
- busService.getBus().register(testListener);
- UUID accountId = UUID.randomUUID();
- bundle = entitlementApi.createBundleForAccount(accountId, "myDefaultBundle");
- } catch (Exception e) {
- Assert.fail(e.getMessage());
- }
+
+ busService.getBus().register(testListener);
+ UUID accountId = UUID.randomUUID();
+ bundle = entitlementApi.createBundleForAccount(accountId, "myDefaultBundle");
assertNotNull(bundle);
((Engine)entitlementService).start();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
index 7db938e..4043254 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
@@ -43,6 +43,7 @@ import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
import com.ning.billing.util.clock.DefaultClock;
public class TestUserApiAddOn extends TestApiBase {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
index fec3550..b21b16d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
@@ -21,6 +21,8 @@ import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
import org.testng.annotations.Test;
public class TestUserApiCancelMemory extends TestUserApiCancel {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java
index 469d374..bdf02e7 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java
@@ -21,6 +21,8 @@ import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
import org.testng.annotations.Test;
public class TestUserApiCancelSql extends TestUserApiCancel {
@@ -34,7 +36,7 @@ public class TestUserApiCancelSql extends TestUserApiCancel {
}
@Test(enabled= false, groups={"stress"})
- public void stressTest() throws EntitlementBillingApiException {
+ public void stressTest() throws Exception {
for (int i = 0; i < MAX_STRESS_ITERATIONS; i++) {
cleanupTest();
setupTest();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
index ab76734..0359d8c 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
@@ -21,6 +21,8 @@ import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
import org.testng.annotations.Test;
public class TestUserApiChangePlanMemory extends TestUserApiChangePlan {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
index 735099c..0396f35 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
@@ -21,6 +21,8 @@ import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
import org.testng.annotations.Test;
public class TestUserApiChangePlanSql extends TestUserApiChangePlan {
@@ -33,7 +35,7 @@ public class TestUserApiChangePlanSql extends TestUserApiChangePlan {
}
@Test(enabled= true, groups={"stress"})
- public void stressTest() throws EntitlementBillingApiException {
+ public void stressTest() throws Exception {
for (int i = 0; i < MAX_STRESS_ITERATIONS; i++) {
cleanupTest();
setupTest();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
index 047ca67..b88ed86 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
@@ -20,6 +20,8 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
import org.testng.annotations.Test;
public class TestUserApiCreateMemory extends TestUserApiCreate {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java
index 6820fec..e5dcc11 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java
@@ -20,6 +20,8 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
import org.testng.annotations.Test;
public class TestUserApiCreateSql extends TestUserApiCreate {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
index 472e7c0..ab60304 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
@@ -190,7 +190,7 @@ public class TestUserApiDemos extends TestApiBase {
}
@Test(enabled= true, groups={"stress"})
- public void stressTest() throws EntitlementBillingApiException {
+ public void stressTest() throws Exception {
for (int i = 0; i < 100; i++) {
cleanupTest();
setupTest();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
index 7442298..e18b8cd 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
@@ -27,6 +27,7 @@ import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
import com.ning.billing.util.clock.DefaultClock;
import org.joda.time.DateTime;
import org.testng.Assert;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java
index b6f97c1..fc7de36 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java
@@ -22,6 +22,7 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
public class TestUserApiRecreateMemory extends TestUserApiRecreate {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java
index 2c1db68..0202753 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java
@@ -22,6 +22,7 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
public class TestUserApiRecreateSql extends TestUserApiRecreate {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
index f69b36a..81125db 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
@@ -28,6 +28,7 @@ import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
import com.ning.billing.util.clock.DefaultClock;
import org.joda.time.DateTime;
import org.testng.Assert;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
index f6881fd..c7ef8ad 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
@@ -21,6 +21,7 @@ import java.util.List;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallOrigin;
import com.ning.billing.util.callcontext.UserType;
@@ -51,7 +52,7 @@ public class TestUserCustomFieldsSql extends TestApiBase {
}
@Test(enabled=false, groups={"slow"})
- public void stress() {
+ public void stress() throws Exception {
cleanupTest();
for (int i = 0; i < 20; i++) {
setupTest();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
index acb1a2a..9b5a593 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
@@ -18,13 +18,21 @@ package com.ning.billing.entitlement.glue;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.catalog.glue.CatalogModule;
+import com.ning.billing.entitlement.api.overdue.MockOverdueChecker;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
import com.ning.billing.util.clock.MockClockModule;
import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.CallContextModule;
public class MockEngineModule extends EntitlementModule {
+
+ protected void installOverdueChecker() {
+ bind(OverdueChecker.class).to(MockOverdueChecker.class).asEagerSingleton();
+ }
+
@Override
protected void configure() {
super.configure();
@@ -33,5 +41,6 @@ public class MockEngineModule extends EntitlementModule {
bind(AccountUserApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class));
install(new MockClockModule());
install(new CallContextModule());
+ install(new MockOverdueAccessModule());
}
}
diff --git a/entitlement/src/test/resources/testInput.xml b/entitlement/src/test/resources/testInput.xml
index 8a97d57..6d761e0 100644
--- a/entitlement/src/test/resources/testInput.xml
+++ b/entitlement/src/test/resources/testInput.xml
@@ -171,6 +171,14 @@ Use Cases to do:
</priceList>
</rules>
+ <overdueRules>
+ <bundleOverdueStates>
+ <state name="Clear">
+ <isClearState>true</isClearState>
+ </state>
+ </bundleOverdueStates>
+ </overdueRules>
+
<plans>
<plan name="pistol-monthly">
<product>Pistol</product>
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index 60c36de..71be8c5 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -179,7 +179,7 @@ public class TestDefaultInvoiceMigrationApi {
DateTime effectiveDate = new DateTime().minusDays(1);
Currency currency = Currency.USD;
BigDecimal fixedPrice = null;
- events.add(new DefaultBillingEvent(subscription, effectiveDate,plan, planPhase,
+ events.add(new DefaultBillingEvent(account, subscription, effectiveDate,plan, planPhase,
fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1,
BillingModeType.IN_ADVANCE, "", 1L, SubscriptionTransitionType.CREATE));
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index 33a1c6a..2caa37f 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -410,7 +410,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
DateTime effectiveDate1 = new DateTime(2011, 2, 1, 0, 0, 0, 0);
- BillingEvent event1 = new DefaultBillingEvent(subscription, effectiveDate1, plan1, phase1, null,
+ BillingEvent event1 = new DefaultBillingEvent(null, subscription, effectiveDate1, plan1, phase1, null,
recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CREATE);
@@ -428,7 +428,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
MockPlan plan2 = new MockPlan(phase2);
DateTime effectiveDate2 = new DateTime(2011, 2, 15, 0, 0, 0, 0);
- BillingEvent event2 = new DefaultBillingEvent(subscription, effectiveDate2, plan2, phase2, null,
+ BillingEvent event2 = new DefaultBillingEvent(null, subscription, effectiveDate2, plan2, phase2, null,
recurringPrice2.getPrice(currency), currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
"testEvent2", 2L, SubscriptionTransitionType.CREATE);
events.add(event2);
@@ -461,7 +461,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
DateTime effectiveDate = buildDateTime(2011, 1, 1);
- BillingEvent event = new DefaultBillingEvent(subscription, effectiveDate, plan, phase, null,
+ BillingEvent event = new DefaultBillingEvent(null, subscription, effectiveDate, plan, phase, null,
recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 15, BillingModeType.IN_ADVANCE,
"testEvent", 1L, SubscriptionTransitionType.CREATE);
BillingEventSet events = new BillingEventSet();
@@ -494,7 +494,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
DateTime effectiveDate1 = buildDateTime(2011, 1, 1);
- BillingEvent event1 = new DefaultBillingEvent(subscription, effectiveDate1, plan, phase1, fixedPrice.getPrice(currency),
+ BillingEvent event1 = new DefaultBillingEvent(null, subscription, effectiveDate1, plan, phase1, fixedPrice.getPrice(currency),
null, currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CREATE);
BillingEventSet events = new BillingEventSet();
@@ -510,7 +510,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
invoiceList.add(invoice1);
DateTime effectiveDate2 = effectiveDate1.plusDays(30);
- BillingEvent event2 = new DefaultBillingEvent(subscription, effectiveDate2, plan, phase2, null,
+ BillingEvent event2 = new DefaultBillingEvent(null, subscription, effectiveDate2, plan, phase2, null,
recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
"testEvent2", 2L, SubscriptionTransitionType.CHANGE);
events.add(event2);
@@ -554,7 +554,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
DateTime effectiveDate1 = buildDateTime(2011, 1, 1);
- BillingEvent event1 = new DefaultBillingEvent(subscription, effectiveDate1, plan, phase1,
+ BillingEvent event1 = new DefaultBillingEvent(null, subscription, effectiveDate1, plan, phase1,
fixedPrice.getPrice(currency), null, currency,
BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CREATE);
@@ -562,7 +562,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
events.add(event1);
DateTime effectiveDate2 = effectiveDate1.plusDays(30);
- BillingEvent event2 = new DefaultBillingEvent(subscription, effectiveDate2, plan, phase2, null,
+ BillingEvent event2 = new DefaultBillingEvent(null, subscription, effectiveDate2, plan, phase2, null,
recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
"testEvent2", 2L, SubscriptionTransitionType.CHANGE);
events.add(event2);
@@ -601,7 +601,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
BillingEventSet events = new BillingEventSet();
List<Invoice> invoices = new ArrayList<Invoice>();
- BillingEvent event1 = new DefaultBillingEvent(subscription, targetDate1, plan, phase1, null,
+ BillingEvent event1 = new DefaultBillingEvent(null, subscription, targetDate1, plan, phase1, null,
TEN, currency,
BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CHANGE);
@@ -613,7 +613,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
invoice1 = invoiceDao.getById(invoice1.getId());
assertNotNull(invoice1.getInvoiceNumber());
- BillingEvent event2 = new DefaultBillingEvent(subscription, targetDate1, plan, phase2, null,
+ BillingEvent event2 = new DefaultBillingEvent(null, subscription, targetDate1, plan, phase2, null,
TWENTY, currency,
BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
"testEvent2", 2L, SubscriptionTransitionType.CHANGE);
@@ -639,7 +639,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
Currency currency = Currency.USD;
// create pseudo-random invoice
- BillingEvent event1 = new DefaultBillingEvent(subscription, targetDate1, plan, phase1, null,
+ BillingEvent event1 = new DefaultBillingEvent(null, subscription, targetDate1, plan, phase1, null,
TEN, currency,
BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CHANGE);
@@ -670,7 +670,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
Currency currency = Currency.USD;
// create pseudo-random invoice
- BillingEvent event1 = new DefaultBillingEvent(subscription, targetDate1, plan, phase1, null,
+ BillingEvent event1 = new DefaultBillingEvent(null, subscription, targetDate1, plan, phase1, null,
TEN, currency,
BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CHANGE);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/MockModule.java b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
index 99f12b4..f3d5aaf 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
@@ -16,10 +16,8 @@
package com.ning.billing.invoice;
-import com.ning.billing.util.callcontext.CallContextFactory;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.glue.FieldStoreModule;
-import com.ning.billing.util.glue.TagStoreModule;
+import java.util.UUID;
+
import org.skife.config.ConfigurationObjectFactory;
import org.skife.jdbi.v2.IDBI;
@@ -29,14 +27,22 @@ import com.ning.billing.catalog.glue.CatalogModule;
import com.ning.billing.dbi.DBIProvider;
import com.ning.billing.dbi.DbiConfig;
import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.glue.EntitlementModule;
import com.ning.billing.invoice.glue.InvoiceModule;
import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.FieldStoreModule;
import com.ning.billing.util.glue.GlobalLockerModule;
import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.TagStoreModule;
public class MockModule extends AbstractModule {
@@ -74,7 +80,27 @@ public class MockModule extends AbstractModule {
}
protected void installEntitlementModule() {
- install(new EntitlementModule());
+ install(new EntitlementModule() {
+
+ @Override
+ protected void installOverdueChecker() {
+ bind(OverdueChecker.class).toInstance(new OverdueChecker() {
+
+ @Override
+ public void checkBlocked(Subscription subscription)
+ throws EntitlementUserApiException {
+ }
+
+ @Override
+ public void checkBlocked(SubscriptionBundle bundle)
+ throws EntitlementUserApiException {
+ }
+
+
+ });
+ }
+
+ });
}
protected void installInvoiceModule() {
diff --git a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
index adc78b7..c75395f 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
@@ -24,23 +24,6 @@ import java.sql.SQLException;
import java.util.UUID;
import java.util.concurrent.Callable;
-import com.ning.billing.account.api.AccountUserApi;
-import com.ning.billing.account.api.MockAccountUserApi;
-import com.ning.billing.entitlement.api.billing.DefaultEntitlementBillingApi;
-import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
-import com.ning.billing.invoice.InvoiceDispatcher;
-import com.ning.billing.invoice.dao.DefaultInvoiceDao;
-import com.ning.billing.invoice.dao.InvoiceDao;
-import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
-import com.ning.billing.invoice.model.InvoiceGenerator;
-import com.ning.billing.util.callcontext.CallContextFactory;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.customfield.dao.AuditedCustomFieldDao;
-import com.ning.billing.util.customfield.dao.CustomFieldDao;
-import com.ning.billing.util.globallocker.GlobalLocker;
-import com.ning.billing.util.globallocker.MySqlGlobalLocker;
-import com.ning.billing.util.tag.dao.AuditedTagDao;
-import com.ning.billing.util.tag.dao.TagDao;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.skife.config.ConfigurationObjectFactory;
@@ -52,30 +35,51 @@ import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.account.api.MockAccountUserApi;
import com.ning.billing.catalog.DefaultCatalogService;
import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.config.CatalogConfig;
import com.ning.billing.config.InvoiceConfig;
import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.entitlement.api.billing.DefaultEntitlementBillingApi;
+import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
+import com.ning.billing.entitlement.api.user.DefaultEntitlementUserApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
import com.ning.billing.entitlement.engine.dao.EntitlementSqlDao;
+import com.ning.billing.invoice.InvoiceDispatcher;
import com.ning.billing.invoice.InvoiceListener;
+import com.ning.billing.invoice.dao.DefaultInvoiceDao;
+import com.ning.billing.invoice.dao.InvoiceDao;
+import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
+import com.ning.billing.invoice.model.InvoiceGenerator;
import com.ning.billing.lifecycle.KillbillService.ServiceException;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.bus.InMemoryBus;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.customfield.dao.AuditedCustomFieldDao;
+import com.ning.billing.util.customfield.dao.CustomFieldDao;
+import com.ning.billing.util.globallocker.GlobalLocker;
+import com.ning.billing.util.globallocker.MySqlGlobalLocker;
import com.ning.billing.util.notificationq.DefaultNotificationQueueService;
import com.ning.billing.util.notificationq.DummySqlTest;
import com.ning.billing.util.notificationq.NotificationQueueService;
import com.ning.billing.util.notificationq.dao.NotificationSqlDao;
+import com.ning.billing.util.tag.dao.AuditedTagDao;
+import com.ning.billing.util.tag.dao.TagDao;
public class TestNextBillingDateNotifier {
private Clock clock;
@@ -115,9 +119,10 @@ public class TestNextBillingDateNotifier {
@BeforeClass(groups={"slow"})
public void setup() throws ServiceException, IOException, ClassNotFoundException, SQLException {
//TestApiBase.loadSystemPropertiesFromClasspath("/entitlement.properties");
- final Injector g = Guice.createInjector(Stage.PRODUCTION, new AbstractModule() {
- @Override
+ final Injector g = Guice.createInjector(Stage.PRODUCTION, new MockOverdueAccessModule() {
+
protected void configure() {
+ super.configure();
bind(Clock.class).to(ClockMock.class).asEagerSingleton();
bind(CallContextFactory.class).to(DefaultCallContextFactory.class).asEagerSingleton();
bind(Bus.class).to(InMemoryBus.class).asEagerSingleton();
@@ -140,6 +145,16 @@ public class TestNextBillingDateNotifier {
bind(NextBillingDatePoster.class).to(DefaultNextBillingDatePoster.class).asEagerSingleton();
bind(AccountUserApi.class).to(MockAccountUserApi.class).asEagerSingleton();
bind(EntitlementBillingApi.class).to(DefaultEntitlementBillingApi.class).asEagerSingleton();
+ bind(EntitlementUserApi.class).to(DefaultEntitlementUserApi.class).asEagerSingleton();
+ bind(OverdueChecker.class).toInstance(new OverdueChecker() {
+
+ @Override
+ public void checkBlocked(Subscription subscription){}
+
+ @Override
+ public void checkBlocked(SubscriptionBundle bundle){}
+
+ });
}
});
diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
index 4f5f991..2e57eea 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
@@ -23,11 +23,6 @@ import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.clock.Clock;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
@@ -56,25 +51,27 @@ import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceApiException;
-import com.ning.billing.invoice.api.InvoiceUserApi;
import com.ning.billing.invoice.dao.InvoiceDao;
import com.ning.billing.invoice.model.InvoiceGenerator;
import com.ning.billing.invoice.notification.NextBillingDateNotifier;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
import com.ning.billing.util.bus.BusService;
import com.ning.billing.util.bus.DefaultBusService;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.globallocker.GlobalLocker;
@Test(groups = "slow")
-@Guice(modules = {MockModule.class})
+@Guice(modules = {MockModule.class, MockOverdueAccessModule.class})
public class TestInvoiceDispatcher {
private Logger log = LoggerFactory.getLogger(TestInvoiceDispatcher.class);
@Inject
- private InvoiceUserApi invoiceUserApi;
-
- @Inject
private InvoiceGenerator generator;
@Inject
@@ -149,7 +146,7 @@ public class TestInvoiceDispatcher {
DateTime effectiveDate = new DateTime().minusDays(1);
Currency currency = Currency.USD;
BigDecimal fixedPrice = null;
- events.add(new DefaultBillingEvent(subscription, effectiveDate,plan, planPhase,
+ events.add(new DefaultBillingEvent(account, subscription, effectiveDate,plan, planPhase,
fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1,
BillingModeType.IN_ADVANCE, "", 1L, SubscriptionTransitionType.CREATE));
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
index 6e6b9b3..f09a520 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
@@ -481,6 +481,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
UUID accountId = UUID.randomUUID();
Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+ ((ZombieControl) subscription).addResult("getBundleId", UUID.randomUUID());
Plan plan = new MockPlan("plan 1");
MockInternationalPrice zeroPrice = new MockInternationalPrice(new DefaultPrice(ZERO, Currency.USD));
@@ -493,13 +494,13 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
BillingEventSet events = new BillingEventSet();
- BillingEvent event1 = new DefaultBillingEvent(subscription, new DateTime("2012-01-1T00:00:00.000-08:00"),
+ BillingEvent event1 = new DefaultBillingEvent(null, subscription, new DateTime("2012-01-1T00:00:00.000-08:00"),
plan, phase1,
ZERO, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
BillingModeType.IN_ADVANCE, "Test Event 1", 1L,
SubscriptionTransitionType.CREATE);
- BillingEvent event2 = new DefaultBillingEvent(subscription, changeDate,
+ BillingEvent event2 = new DefaultBillingEvent(null, subscription, changeDate,
plan, phase2,
ZERO, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
BillingModeType.IN_ADVANCE, "Test Event 2", 2L,
@@ -691,7 +692,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
Subscription sub = new SubscriptionData(new SubscriptionBuilder().setId(subscriptionId));
Currency currency = Currency.USD;
- return new DefaultBillingEvent(sub, startDate, plan, planPhase,
+ return new DefaultBillingEvent(null, sub, startDate, plan, planPhase,
planPhase.getFixedPrice() == null ? null : planPhase.getFixedPrice().getPrice(currency),
planPhase.getRecurringPrice() == null ? null : planPhase.getRecurringPrice().getPrice(currency),
currency, planPhase.getBillingPeriod(),
overdue/pom.xml 7(+6 -1)
diff --git a/overdue/pom.xml b/overdue/pom.xml
index 0f5a57d..44f3149 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -44,7 +44,6 @@
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
@@ -88,6 +87,12 @@
<artifactId>mysql-connector-mxj-db-files</artifactId>
<scope>test</scope>
</dependency>
+ <!-- Strangely this is needed in order to run the tests in local db mode -->
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
index 1323e55..e9d3f77 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
@@ -20,6 +20,8 @@ import org.apache.commons.lang.NotImplementedException;
import org.joda.time.DateTime;
import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.overdue.OverdueError;
import com.ning.billing.catalog.api.overdue.OverdueState;
import com.ning.billing.catalog.api.overdue.Overdueable;
import com.ning.billing.overdue.dao.OverdueDao;
@@ -38,7 +40,7 @@ public class OverdueStateApplicator<T extends Overdueable>{
this.clock = clock;
}
- public void apply(T overdueable, OverdueState<T> previousOverdueState, OverdueState<T> nextOverdueState, DateTime timeOfNextCheck) {
+ public void apply(T overdueable, OverdueState<T> previousOverdueState, OverdueState<T> nextOverdueState, DateTime timeOfNextCheck) throws OverdueError {
if(previousOverdueState.getName().equals(nextOverdueState.getName())) {
return; // nothing to do
}
@@ -57,11 +59,15 @@ public class OverdueStateApplicator<T extends Overdueable>{
throw new NotImplementedException();
}
-
- protected void storeNewState(T overdueable, OverdueState<T> nextOverdueState) {
- overdueDao.setOverdueState(overdueable, nextOverdueState, clock);
+
+ protected void storeNewState(T overdueable, OverdueState<T> nextOverdueState) throws OverdueError {
+ try {
+ overdueDao.setOverdueState(overdueable, nextOverdueState, Overdueable.Type.get(overdueable), clock);
+ } catch (Exception e) {
+ throw new OverdueError(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, overdueable.getId(), overdueable.getClass().getName());
+ }
}
-
+
protected void createFutureNotification(T overdueable,
DateTime timeOfNextCheck) {
// TODO Auto-generated method stub
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
index cbd9219..6705c30 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
@@ -30,7 +30,7 @@ import com.ning.billing.catalog.api.PriceList;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.overdue.BillingStateBundle;
import com.ning.billing.catalog.api.overdue.PaymentResponse;
-import com.ning.billing.entitlement.api.overdue.EntitlementOverdueApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.invoice.api.Invoice;
@@ -41,10 +41,10 @@ import com.ning.billing.util.tag.Tag;
public class BillingStateCalculatorBundle extends BillingStateCalculator<SubscriptionBundle>{
- private EntitlementOverdueApi entitlementApi;
+ private EntitlementUserApi entitlementApi;
@Inject
- public BillingStateCalculatorBundle(EntitlementOverdueApi entitlementApi, InvoiceUserApi invoiceApi, Clock clock) {
+ public BillingStateCalculatorBundle(EntitlementUserApi entitlementApi, InvoiceUserApi invoiceApi, Clock clock) {
super(invoiceApi, clock);
this.entitlementApi = entitlementApi;
}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueDao.java b/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueDao.java
index fe69e34..278fe59 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueDao.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueDao.java
@@ -22,6 +22,6 @@ import com.ning.billing.util.clock.Clock;
public interface OverdueDao {
- <T extends Overdueable> void setOverdueState(T overdueable, OverdueState<T> newOverdueState, Clock clock);
+ <T extends Overdueable> void setOverdueState(T overdueable, OverdueState<T> newOverdueState, Overdueable.Type type, Clock clock);
}
\ No newline at end of file
diff --git a/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueSqlDao.java b/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueSqlDao.java
index bd77283..18a2814 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueSqlDao.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueSqlDao.java
@@ -20,21 +20,25 @@ import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.sqlobject.Bind;
import org.skife.jdbi.v2.sqlobject.Binder;
import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
import com.ning.billing.catalog.api.overdue.OverdueState;
import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.entity.BinderBase;
@ExternalizedSqlViaStringTemplate3()
-public interface OverdueSqlDao extends OverdueDao {
+public interface OverdueSqlDao extends OverdueDao, CloseMe, Transmogrifier {
@Override
@SqlUpdate
public abstract <T extends Overdueable> void setOverdueState(
@Bind(binder = OverdueableBinder.class) T overdueable,
@Bind(binder = OverdueStateBinder.class) OverdueState<T> overdueState,
+ @Bind(binder = OverdueableTypeBinder.class) Overdueable.Type type,
@Bind(binder = CurrentTimeBinder.class) Clock clock) ;
public static class OverdueableBinder extends BinderBase implements Binder<Bind, Overdueable> {
@@ -43,6 +47,7 @@ public interface OverdueSqlDao extends OverdueDao {
stmt.bind("id", overdueable.getId().toString());
}
}
+
public static class OverdueStateBinder<T extends Overdueable> extends BinderBase implements Binder<Bind, OverdueState<T>> {
@Override
public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, OverdueState<T> overdueState) {
@@ -50,10 +55,19 @@ public interface OverdueSqlDao extends OverdueDao {
}
}
+ public class OverdueableTypeBinder extends BinderBase implements Binder<Bind, Overdueable.Type>{
+
+ @Override
+ public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, Type type) {
+ stmt.bind("type", type.name());
+ }
+
+ }
+
public static class CurrentTimeBinder extends BinderBase implements Binder<Bind, Clock> {
@Override
public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, Clock clock) {
- stmt.bind("created_date", clock.getUTCNow());
+ stmt.bind("created_date", clock.getUTCNow().toDate());
}
}
diff --git a/overdue/src/main/resources/com/ning/billing/overdue/dao/OverdueSqlDao.sql.stg b/overdue/src/main/resources/com/ning/billing/overdue/dao/OverdueSqlDao.sql.stg
index 229a6a7..a081e92 100644
--- a/overdue/src/main/resources/com/ning/billing/overdue/dao/OverdueSqlDao.sql.stg
+++ b/overdue/src/main/resources/com/ning/billing/overdue/dao/OverdueSqlDao.sql.stg
@@ -1,13 +1,15 @@
group OverdueSqlDao;
-setOverdueStateForBundle() ::= <<
+setOverdueState() ::= <<
insert into overdue_states (
id
, state
+ , type
, created_date
) values (
:id
, :state
- , NOW()
+ , :type
+ , :created_date
);
>>
\ No newline at end of file
diff --git a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
index f04575c..6374ce1 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
@@ -32,7 +32,7 @@ import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PriceList;
import com.ning.billing.catalog.api.overdue.BillingStateBundle;
import com.ning.billing.catalog.api.overdue.PaymentResponse;
-import com.ning.billing.entitlement.api.overdue.EntitlementOverdueApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.invoice.api.Invoice;
@@ -72,7 +72,7 @@ public class TestBillingStateCalculatorBundle extends TestBillingStateCalculator
Clock clock = new ClockMock();
InvoiceUserApi invoiceApi = BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceUserApi.class);
- EntitlementOverdueApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementOverdueApi.class);
+ EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
((ZombieControl)invoiceApi).addResult("getUnpaidInvoicesByAccountId", invoices);
@@ -107,7 +107,7 @@ public class TestBillingStateCalculatorBundle extends TestBillingStateCalculator
((ZombieControl)bundle).addResult("getId", thisBundleId);
((ZombieControl)bundle).addResult("getAccountId", UUID.randomUUID());
- EntitlementOverdueApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementOverdueApi.class);
+ EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
((ZombieControl)entitlementApi).addResult("getBaseSubscription",subscription);
@@ -131,9 +131,6 @@ public class TestBillingStateCalculatorBundle extends TestBillingStateCalculator
Assert.assertEquals(state.getBasePlanPriceList(), pricelist);
Assert.assertEquals(state.getBasePlanProduct(), plan.getProduct());
-
-
-
}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java b/overdue/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java
index c0efba2..41a8ab0 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java
@@ -17,10 +17,10 @@
package com.ning.billing.overdue.dao;
import java.io.IOException;
+import java.util.SortedSet;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
-import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
@@ -29,9 +29,9 @@ import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import com.google.inject.Inject;
-import com.ning.billing.catalog.api.Duration;
-import com.ning.billing.catalog.api.TimeUnit;
+import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.overdue.OverdueState;
+import com.ning.billing.catalog.api.overdue.Overdueable;
import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.mock.BrainDeadProxyFactory;
@@ -39,6 +39,7 @@ import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
import com.ning.billing.overdue.glue.OverdueModule;
import com.ning.billing.util.clock.ClockMock;
import com.ning.billing.util.glue.OverdueAccessModule;
+import com.ning.billing.util.overdue.OverdueEvent;
import com.ning.billing.util.overdue.dao.OverdueAccessDao;
@Guice(modules = {MockModule.class, OverdueModule.class, OverdueAccessModule.class})
@@ -78,15 +79,48 @@ public class TestOverdueDao {
OverdueState<SubscriptionBundle> state = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueState.class);
((ZombieControl)state).addResult("getName", overdueStateName);
- dao.setOverdueState(bundle, state, clock);
+ dao.setOverdueState(bundle, state, Overdueable.Type.SUBSCRIPTION_BUNDLE, clock);
clock.setDeltaFromReality(1000 * 3600 * 24);
String overdueStateName2 = "NoReallyThisCantGoOn";
((ZombieControl)state).addResult("getName", overdueStateName2);
- dao.setOverdueState(bundle, state, clock);
+ dao.setOverdueState(bundle, state, Overdueable.Type.SUBSCRIPTION_BUNDLE, clock);
- Assert.assertEquals(accessDao.getOverdueStateNameFor(bundle), overdueStateName2);
+ Assert.assertEquals(accessDao.getOverdueStateFor(bundle), overdueStateName2);
+ Assert.assertEquals(accessDao.getOverdueStateForIdAndType(bundle.getId(), Overdueable.Type.SUBSCRIPTION_BUNDLE), overdueStateName2);
}
+ @Test(groups={"slow"}, enabled=true)
+ public void testDaoHistory() throws CatalogApiException {
+ ClockMock clock = new ClockMock();
+ SubscriptionBundle bundle = BrainDeadProxyFactory.createBrainDeadProxyFor(SubscriptionBundle.class);
+ UUID bundleId = UUID.randomUUID();
+ ((ZombieControl)bundle).addResult("getId", bundleId);
+
+ String overdueStateName = "WayPassedItMan";
+ @SuppressWarnings("unchecked")
+ OverdueState<SubscriptionBundle> state = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueState.class);
+ ((ZombieControl)state).addResult("getName", overdueStateName);
+
+ dao.setOverdueState(bundle, state, Overdueable.Type.SUBSCRIPTION_BUNDLE, clock);
+ clock.setDeltaFromReality(1000 * 3600 * 24);
+
+ String overdueStateName2 = "NoReallyThisCantGoOn";
+ ((ZombieControl)state).addResult("getName", overdueStateName2);
+ dao.setOverdueState(bundle, state, Overdueable.Type.SUBSCRIPTION_BUNDLE, clock);
+
+ SortedSet<OverdueEvent> history1 = accessDao.getOverdueHistoryFor(bundle);
+ SortedSet<OverdueEvent> history2 = accessDao.getOverdueHistoryForIdAndType(bundle.getId(), Overdueable.Type.get(bundle));
+
+ Assert.assertEquals(history1.size(), 2);
+ Assert.assertEquals(history1.first().getStateName(), overdueStateName);
+ Assert.assertEquals(history1.last().getStateName(), overdueStateName2);
+
+ Assert.assertEquals(history2.size(), 2);
+ Assert.assertEquals(history2.first().getStateName(), overdueStateName);
+ Assert.assertEquals(history2.last().getStateName(), overdueStateName2);
+
+ }
+
}
diff --git a/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessDao.java b/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessDao.java
index 6327dc5..ac61a4d 100644
--- a/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessDao.java
+++ b/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessDao.java
@@ -16,10 +16,22 @@
package com.ning.billing.util.overdue.dao;
+import java.util.SortedSet;
+import java.util.UUID;
+
import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
+import com.ning.billing.util.overdue.OverdueEvent;
public interface OverdueAccessDao {
- public String getOverdueStateNameFor(Overdueable overdueable);
+ public String getOverdueStateFor(Overdueable overdueable);
+
+ public String getOverdueStateForIdAndType(UUID overdueableId, Type type);
+
+ public SortedSet<OverdueEvent> getOverdueHistoryFor(Overdueable overdueable);
+
+ public SortedSet<OverdueEvent> getOverdueHistoryForIdAndType(UUID overdueableId, Type type);
+
}
diff --git a/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.java b/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.java
index b6e0426..8dfd32b 100644
--- a/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.java
@@ -18,7 +18,10 @@ package com.ning.billing.util.overdue.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.SortedSet;
+import java.util.UUID;
+import org.joda.time.DateTime;
import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.sqlobject.Bind;
@@ -31,10 +34,13 @@ import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
import org.skife.jdbi.v2.tweak.ResultSetMapper;
+import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
import com.ning.billing.util.entity.BinderBase;
import com.ning.billing.util.entity.MapperBase;
import com.ning.billing.util.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.OverdueEvent;
@ExternalizedSqlViaStringTemplate3()
public interface OverdueAccessSqlDao extends Transactional<OverdueAccessSqlDao>, CloseMe, Transmogrifier, OverdueAccessDao {
@@ -42,7 +48,45 @@ public interface OverdueAccessSqlDao extends Transactional<OverdueAccessSqlDao>,
@Override
@SqlQuery
@Mapper(OverdueStateSqlMapper.class)
- public abstract String getOverdueStateNameFor(@Bind(binder = OverdueableBinder.class)Overdueable overdueable) ;
+ public abstract String getOverdueStateFor(@Bind(binder = OverdueableBinder.class)Overdueable overdueable) ;
+
+ @Override
+ @SqlQuery
+ @Mapper(OverdueStateSqlMapper.class)
+ public abstract String getOverdueStateForIdAndType(@Bind(binder = UUIDBinder.class) UUID overdueableId, @Bind(binder = OverdueableTypeBinder.class) Type type);
+
+ @Override
+ @SqlQuery
+ @Mapper(OverdueHistorySqlMapper.class)
+ public abstract SortedSet<OverdueEvent> getOverdueHistoryFor(@Bind(binder = OverdueableBinder.class)Overdueable overdueable) ;
+
+ @Override
+ @SqlQuery
+ @Mapper(OverdueHistorySqlMapper.class)
+ public abstract SortedSet<OverdueEvent> getOverdueHistoryForIdAndType(@Bind(binder = UUIDBinder.class) UUID overdueableId, @Bind(binder = OverdueableTypeBinder.class) Type type);
+
+
+ public class OverdueHistorySqlMapper extends MapperBase implements ResultSetMapper<OverdueEvent> {
+
+ @Override
+ public OverdueEvent map(int index, ResultSet r, StatementContext ctx)
+ throws SQLException {
+
+ DateTime timestamp;
+ UUID overdueableId;
+ String stateName;
+ Type type;
+ try {
+ timestamp = new DateTime(r.getDate("created_date"));
+ overdueableId = UUID.fromString(r.getString("id"));
+ stateName = r.getString("state") == null ? OverdueAccessApi.CLEAR_STATE_NAME : r.getString("state");
+ type = Type.get(r.getString("type"));
+ } catch (CatalogApiException e) {
+ throw new SQLException(e);
+ }
+ return new OverdueEvent(overdueableId, stateName, type, timestamp);
+ }
+ }
public static class OverdueStateSqlMapper extends MapperBase implements ResultSetMapper<String> {
@@ -53,6 +97,15 @@ public interface OverdueAccessSqlDao extends Transactional<OverdueAccessSqlDao>,
}
}
+ public static class UUIDBinder extends BinderBase implements Binder<Bind, UUID> {
+ @Override
+ public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, UUID id) {
+ stmt.bind("id", id.toString());
+ }
+ }
+
+
+
public static class OverdueableBinder extends BinderBase implements Binder<Bind, Overdueable> {
@Override
public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, Overdueable overdueable) {
@@ -60,4 +113,14 @@ public interface OverdueAccessSqlDao extends Transactional<OverdueAccessSqlDao>,
}
}
+ public class OverdueableTypeBinder extends BinderBase implements Binder<Bind, Overdueable.Type>{
+
+ @Override
+ public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, Type type) {
+ stmt.bind("type", type.name());
+ }
+
+ }
+
+
}
diff --git a/util/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java b/util/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java
index 67d6948..d104a44 100644
--- a/util/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java
+++ b/util/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java
@@ -16,15 +16,12 @@
package com.ning.billing.util.overdue;
+import java.util.SortedSet;
+import java.util.UUID;
+
import com.google.inject.Inject;
-import com.ning.billing.ErrorCode;
-import com.ning.billing.catalog.api.CatalogApiException;
-import com.ning.billing.catalog.api.StaticCatalog;
-import com.ning.billing.catalog.api.overdue.OverdueError;
-import com.ning.billing.catalog.api.overdue.OverdueState;
-import com.ning.billing.catalog.api.overdue.OverdueStateSet;
import com.ning.billing.catalog.api.overdue.Overdueable;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
import com.ning.billing.util.overdue.dao.OverdueAccessDao;
public class DefaultOverdueAcessApi implements OverdueAccessApi {
@@ -37,7 +34,23 @@ public class DefaultOverdueAcessApi implements OverdueAccessApi {
@Override
public String getOverdueStateNameFor(Overdueable overdueable) {
- return dao.getOverdueStateNameFor(overdueable);
+ return dao.getOverdueStateFor(overdueable);
+ }
+
+ @Override
+ public String getOverdueStateNameFor(UUID overdueableId, Type type) {
+ return dao.getOverdueStateForIdAndType(overdueableId, type);
+ }
+
+ @Override
+ public SortedSet<OverdueEvent> getOverdueHistory(Overdueable overdueable) {
+ return dao.getOverdueHistoryFor(overdueable);
+ }
+
+ @Override
+ public SortedSet<OverdueEvent> getOverdueHistory(UUID overdueableId,
+ Type type) {
+ return dao.getOverdueHistoryForIdAndType(overdueableId, type);
}
}
diff --git a/util/src/main/java/com/ning/billing/util/overdue/OverdueAccessApi.java b/util/src/main/java/com/ning/billing/util/overdue/OverdueAccessApi.java
index 5fd9c0d..3978c7e 100644
--- a/util/src/main/java/com/ning/billing/util/overdue/OverdueAccessApi.java
+++ b/util/src/main/java/com/ning/billing/util/overdue/OverdueAccessApi.java
@@ -16,9 +16,9 @@
package com.ning.billing.util.overdue;
-import com.ning.billing.catalog.api.StaticCatalog;
-import com.ning.billing.catalog.api.overdue.OverdueError;
-import com.ning.billing.catalog.api.overdue.OverdueState;
+import java.util.SortedSet;
+import java.util.UUID;
+
import com.ning.billing.catalog.api.overdue.Overdueable;
public interface OverdueAccessApi {
@@ -26,5 +26,10 @@ public interface OverdueAccessApi {
public String getOverdueStateNameFor(Overdueable overdueable);
+ public String getOverdueStateNameFor(UUID overdueableId, Overdueable.Type type);
+
+ public SortedSet<OverdueEvent> getOverdueHistory(Overdueable overdueable);
+
+ public SortedSet<OverdueEvent> getOverdueHistory(UUID overdueableId, Overdueable.Type type);
}
diff --git a/util/src/main/java/com/ning/billing/util/overdue/OverdueEvent.java b/util/src/main/java/com/ning/billing/util/overdue/OverdueEvent.java
new file mode 100644
index 0000000..645fad0
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/overdue/OverdueEvent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.overdue;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
+
+public class OverdueEvent implements Comparable<OverdueEvent>{
+ private final UUID overdueableId;
+ private final String stateName;
+ private final Overdueable.Type type;
+ private final DateTime timestamp;
+
+ public OverdueEvent(UUID overdueableId, String stateName, Type type,
+ DateTime timestamp) {
+ super();
+ this.overdueableId = overdueableId;
+ this.stateName = stateName;
+ this.type = type;
+ this.timestamp = timestamp;
+ }
+
+ public UUID getOverdueableId() {
+ return overdueableId;
+ }
+ public String getStateName() {
+ return stateName;
+ }
+ public Overdueable.Type getType() {
+ return type;
+ }
+ public DateTime getTimestamp() {
+ return timestamp;
+ }
+
+ @Override
+ public int compareTo(OverdueEvent arg0) {
+ return timestamp.compareTo(arg0.getTimestamp());
+ }
+}
diff --git a/util/src/main/resources/com/ning/billing/util/ddl.sql b/util/src/main/resources/com/ning/billing/util/ddl.sql
index 2bce344..b40e5a4 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -122,6 +122,7 @@ DROP TABLE IF EXISTS overdue_states;
CREATE TABLE overdue_states (
id char(36) NOT NULL,
state varchar(50) NOT NULL,
+ type varchar(20) NOT NULL,
created_date datetime NOT NULL
) ENGINE=innodb;
CREATE INDEX overdue_states_by_id ON overdue_states (id);
diff --git a/util/src/main/resources/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.sql.stg
index 606a4d0..81a38aa 100644
--- a/util/src/main/resources/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.sql.stg
@@ -1,13 +1,54 @@
group OverdueAccessSqlDao;
-getOverdueStateNameFor() ::= <<
+getOverdueStateFor() ::= <<
select
id
, state
+ , type
, created_date
from overdue_states
- where id = :id
+ where id = :id
order by created_date desc
limit 1
;
+>>
+
+getOverdueStateForIdAndType() ::= <<
+ select
+ id
+ , state
+ , type
+ , created_date
+ from overdue_states
+ where id = :id
+ and type = :type
+ order by created_date desc
+ limit 1
+ ;
+>>
+
+
+getOverdueHistoryFor() ::= <<
+ select
+ id
+ , state
+ , type
+ , created_date
+ from overdue_states
+ where id = :id
+ order by created_date asc
+ ;
+>>
+
+getOverdueHistoryForIdAndType() ::= <<
+ select
+ id
+ , state
+ , type
+ , created_date
+ from overdue_states
+ where id = :id
+ and type = :type
+ order by created_date asc
+ ;
>>
\ No newline at end of file
diff --git a/util/src/test/java/com/ning/billing/mock/BrainDeadProxyFactory.java b/util/src/test/java/com/ning/billing/mock/BrainDeadProxyFactory.java
index 9cfbe9f..7a3d28f 100644
--- a/util/src/test/java/com/ning/billing/mock/BrainDeadProxyFactory.java
+++ b/util/src/test/java/com/ning/billing/mock/BrainDeadProxyFactory.java
@@ -19,12 +19,15 @@ package com.ning.billing.mock;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import bsh.This;
+
public class BrainDeadProxyFactory {
private static final Logger log = LoggerFactory.getLogger(BrainDeadProxyFactory.class);
@@ -39,9 +42,12 @@ public class BrainDeadProxyFactory {
}
@SuppressWarnings("unchecked")
- public static <T> T createBrainDeadProxyFor(final Class<T> clazz) {
+ public static <T> T createBrainDeadProxyFor(final Class<T> clazz, final Class<?> ... others) {
+ Class<?>[] clazzes = Arrays.copyOf(others, others.length + 2);
+ clazzes[others.length] = ZombieControl.class;
+ clazzes[others.length + 1] = clazz;
return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
- new Class[] { clazz , ZombieControl.class},
+ clazzes,
new InvocationHandler() {
private final Map<String,Object> results = new HashMap<String,Object>();
@@ -68,7 +74,9 @@ public class BrainDeadProxyFactory {
throw ((Throwable) result);
}
return result;
- } else {
+ } else if (method.getName().equals("equals")){
+ return proxy == args[0];
+ } else {
log.error(String.format("No result for Method: '%s' on Class '%s'",method.getName(), method.getDeclaringClass().getName()));
throw new UnsupportedOperationException();
}
diff --git a/util/src/test/java/com/ning/billing/mock/overdue/MockOverdueAccessModule.java b/util/src/test/java/com/ning/billing/mock/overdue/MockOverdueAccessModule.java
new file mode 100644
index 0000000..a5add78
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/mock/overdue/MockOverdueAccessModule.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.mock.overdue;
+
+import com.google.inject.AbstractModule;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.dao.OverdueAccessDao;
+
+public class MockOverdueAccessModule extends AbstractModule {
+ public static final String CLEAR_STATE="Clear";
+
+ @Override
+ protected void configure() {
+ OverdueAccessApi overdueAccessApi = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessApi.class);
+ ((ZombieControl) overdueAccessApi).addResult("getOverdueStateNameFor", MockOverdueAccessModule.CLEAR_STATE);
+ bind(OverdueAccessDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessDao.class));
+ bind(OverdueAccessApi.class).toInstance(overdueAccessApi);
+ }
+}