Details
diff --git a/api/src/main/java/com/ning/billing/account/api/ControlTagType.java b/api/src/main/java/com/ning/billing/account/api/ControlTagType.java
index 23c23ae..926c32f 100644
--- a/api/src/main/java/com/ning/billing/account/api/ControlTagType.java
+++ b/api/src/main/java/com/ning/billing/account/api/ControlTagType.java
@@ -18,7 +18,8 @@ package com.ning.billing.account.api;
public enum ControlTagType {
AUTO_BILLING_OFF("Suspends billing until removed.", true, false),
- AUTO_INVOICING_OFF("Suspends invoicing until removed.", false, true);
+ AUTO_INVOICING_OFF("Suspends invoicing until removed.", false, true),
+ OVERDUE_ENFORCEMENT_OFF("Suspends invoicing until removed.", false, false);
private final String description;
private final boolean autoPaymentOff;
diff --git a/api/src/main/java/com/ning/billing/catalog/api/overdue/BillingState.java b/api/src/main/java/com/ning/billing/catalog/api/overdue/BillingState.java
new file mode 100644
index 0000000..d1c30a1
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/catalog/api/overdue/BillingState.java
@@ -0,0 +1,71 @@
+/*
+ * 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.api.overdue;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.tag.Tag;
+
+public class BillingState {
+ private final UUID objectId;
+ private final int numberOfUnpaidInvoices;
+ private final BigDecimal balanceOfUnpaidInvoices;
+ private final DateTime dateOfEarliestUnpaidInvoice;
+ private final PaymentResponse responseForLastFailedPayment;
+ private final Tag[] tags;
+
+ public BillingState(UUID id, int numberOfUnpaidInvoices, BigDecimal balanceOfUnpaidInvoices,
+ DateTime dateOfEarliestUnpaidInvoice,
+ PaymentResponse responseForLastFailedPayment,
+ Tag[] tags) {
+ super();
+ this.objectId = id;
+ this.numberOfUnpaidInvoices = numberOfUnpaidInvoices;
+ this.balanceOfUnpaidInvoices = balanceOfUnpaidInvoices;
+ this.dateOfEarliestUnpaidInvoice = dateOfEarliestUnpaidInvoice;
+ this.responseForLastFailedPayment = responseForLastFailedPayment;
+ this.tags = tags;
+ }
+
+ public UUID getObjectId() {
+ return objectId;
+ }
+
+ public int getNumberOfUnpaidInvoices() {
+ return numberOfUnpaidInvoices;
+ }
+
+ public BigDecimal getBalanceOfUnpaidInvoices() {
+ return balanceOfUnpaidInvoices;
+ }
+
+ public DateTime getDateOfEarliestUnpaidInvoice() {
+ return dateOfEarliestUnpaidInvoice;
+ }
+
+ public PaymentResponse getResponseForLastFailedPayment() {
+ return responseForLastFailedPayment;
+ }
+
+ public Tag[] getTags() {
+ return tags;
+ }
+
+}
diff --git a/api/src/main/java/com/ning/billing/catalog/api/overdue/BillingStateBundle.java b/api/src/main/java/com/ning/billing/catalog/api/overdue/BillingStateBundle.java
new file mode 100644
index 0000000..e640f61
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/catalog/api/overdue/BillingStateBundle.java
@@ -0,0 +1,65 @@
+/*
+ * 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.api.overdue;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.util.tag.Tag;
+
+public class BillingStateBundle extends BillingState {
+ private final BillingState accountState;
+ private final Product basePlanProduct;
+ private final BillingPeriod basePlanBillingPeriod;
+ private final PriceList basePlanPriceList;
+
+ public BillingStateBundle(UUID id, BillingState accountState, int numberOfUnpaidInvoices, BigDecimal unpaidInvoiceBalance,
+ DateTime dateOfEarliestUnpaidInvoice,
+ PaymentResponse responseForLastFailedPayment,
+ Tag[] tags,
+ Product basePlanProduct,
+ BillingPeriod basePlanBillingPeriod,
+ PriceList basePlanPriceList) {
+ super(id, numberOfUnpaidInvoices, unpaidInvoiceBalance,
+ dateOfEarliestUnpaidInvoice, responseForLastFailedPayment, tags);
+ this.accountState = accountState;
+ this.basePlanProduct = basePlanProduct;
+ this.basePlanBillingPeriod = basePlanBillingPeriod;
+ this.basePlanPriceList = basePlanPriceList;
+ }
+
+ public BillingState getAccountState() {
+ return accountState;
+ }
+
+ public Product getBasePlanProduct() {
+ return basePlanProduct;
+ }
+
+ public BillingPeriod getBasePlanBillingPeriod() {
+ return basePlanBillingPeriod;
+ }
+
+ public PriceList getBasePlanPriceList() {
+ return basePlanPriceList;
+ }
+}
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
new file mode 100644
index 0000000..48c044a
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/catalog/api/overdue/OverdueState.java
@@ -0,0 +1,49 @@
+/*
+ * 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.api.overdue;
+
+import java.util.UUID;
+
+public class OverdueState {
+ private final UUID id;
+ private final String stageName;
+ private final String externalMessage;
+ private final boolean cancel;
+
+ public OverdueState(UUID id, String stageName, String externalMessage, boolean cancel) {
+ this.id = id;
+ this.stageName = stageName;
+ this.externalMessage = externalMessage;
+ this.cancel = cancel;
+ }
+
+ public UUID getId() {
+ return id;
+ }
+
+ public boolean cancel() {
+ return cancel;
+ }
+
+ public String getStageName() {
+ return stageName;
+ }
+ public String getExternalMessage() {
+ return externalMessage;
+ }
+
+}
diff --git a/api/src/main/java/com/ning/billing/catalog/api/overdue/PaymentResponse.java b/api/src/main/java/com/ning/billing/catalog/api/overdue/PaymentResponse.java
new file mode 100644
index 0000000..6227e2e
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/catalog/api/overdue/PaymentResponse.java
@@ -0,0 +1,25 @@
+/*
+ * 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.api.overdue;
+
+public enum PaymentResponse {
+ INSUFFICIENT_FUNDS,
+ TEMPORARY_ACCOUNT_ISSUE,
+ LOST_OR_STOLEN,
+ PERMANENT_ACCOUNT_ISSUE,
+ OTHER
+}
diff --git a/api/src/main/java/com/ning/billing/catalog/api/OverdueActions.java b/api/src/main/java/com/ning/billing/catalog/api/OverdueActions.java
new file mode 100644
index 0000000..8525d91
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/catalog/api/OverdueActions.java
@@ -0,0 +1,22 @@
+/*
+ * 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.api;
+
+public enum OverdueActions {
+ CANCEL,
+ PAYMENT_RETRY
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceList.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceList.java
index aba447d..c597dc0 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceList.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceList.java
@@ -107,10 +107,20 @@ public class DefaultPriceList extends ValidatingConfig<StandaloneCatalog> implem
return count;
}
- public DefaultPriceList setRetired(boolean retired) {
+ protected DefaultPriceList setRetired(boolean retired) {
this.retired = retired;
return this;
}
+ public DefaultPriceList setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public DefaultPriceList setPlans(DefaultPlan[] plans) {
+ this.plans = plans;
+ return this;
+ }
+
}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultProduct.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultProduct.java
index ff3868c..6687c75 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultProduct.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultProduct.java
@@ -55,7 +55,6 @@ public class DefaultProduct extends ValidatingConfig<StandaloneCatalog> implemen
//Not included in XML
private String catalogName;
-
@Override
public String getCatalogName() {
return catalogName;
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/BundleCondition.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/BundleCondition.java
new file mode 100644
index 0000000..fb8e985
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/BundleCondition.java
@@ -0,0 +1,77 @@
+/*
+ * 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 javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlIDREF;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.DefaultPriceList;
+import com.ning.billing.catalog.DefaultProduct;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.overdue.BillingState;
+import com.ning.billing.catalog.api.overdue.BillingStateBundle;
+
+@XmlAccessorType(XmlAccessType.NONE)
+public class BundleCondition extends Condition {
+ @XmlElement(required=false, name="accountConditions")
+ private Condition accountCondition;
+
+ @XmlElement(required=false, name="basePlanProduct")
+ @XmlIDREF
+ private DefaultProduct basePlanProduct;
+
+ @XmlElement(required=false, name="basePlanBillingPeriod")
+ private BillingPeriod basePlanBillingPeriod;
+
+ @XmlElement(required=false, name="basePlanPriceList")
+ @XmlIDREF
+ private DefaultPriceList basePlanPriceList;
+
+ public boolean evaluate(BillingStateBundle state, DateTime now) {
+ return super.evaluate((BillingState)state, now) &&
+ (accountCondition == null || accountCondition.evaluate(state.getAccountState(), now)) &&
+ (basePlanProduct == null || basePlanProduct.equals(state.getBasePlanProduct())) &&
+ (basePlanBillingPeriod == null || basePlanBillingPeriod.equals(state.getBasePlanBillingPeriod())) &&
+ (basePlanPriceList == null || basePlanPriceList.equals(state.getBasePlanPriceList()));
+ }
+
+ protected BundleCondition setAccountCondition(Condition accountCondition) {
+ this.accountCondition = accountCondition;
+ return this;
+ }
+
+ protected BundleCondition setBasePlanProduct(DefaultProduct basePlanProduct) {
+ this.basePlanProduct = basePlanProduct;
+ return this;
+ }
+
+ protected BundleCondition setBasePlanBillingPeriod(BillingPeriod basePlanBillingPeriod) {
+ this.basePlanBillingPeriod = basePlanBillingPeriod;
+ return this;
+ }
+
+ protected BundleCondition setBasePlanPriceList(DefaultPriceList basePlanPriceList) {
+ this.basePlanPriceList = basePlanPriceList;
+ return this;
+ }
+
+
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/Condition.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/Condition.java
new file mode 100644
index 0000000..c87f548
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/Condition.java
@@ -0,0 +1,89 @@
+/*
+ * 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 java.math.BigDecimal;
+import java.net.URI;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.account.api.ControlTagType;
+import com.ning.billing.catalog.DefaultDuration;
+import com.ning.billing.catalog.StandaloneCatalog;
+import com.ning.billing.catalog.api.overdue.BillingState;
+import com.ning.billing.catalog.api.overdue.PaymentResponse;
+import com.ning.billing.util.config.ValidatingConfig;
+import com.ning.billing.util.config.ValidationErrors;
+import com.ning.billing.util.tag.Tag;
+
+@XmlAccessorType(XmlAccessType.NONE)
+public class Condition extends ValidatingConfig<StandaloneCatalog> {
+ @XmlElement(required=false, name="numberOfUnpaidInvoicesEqualsOrExceeds")
+ private Integer numberOfUnpaidInvoicesEqualsOrExceeds;
+
+ @XmlElement(required=false, name="totalUnpaidInvoiceBalanceEqualsOrExceeds")
+ private BigDecimal totalUnpaidInvoiceBalanceEqualsOrExceeds;
+
+ @XmlElement(required=false, name="timeSinceEarliestUnpaidInvoiceEqualsOrExceeds")
+ private DefaultDuration timeSinceEarliestUnpaidInvoiceEqualsOrExceeds;
+
+ @XmlElementWrapper(required=false, name="responseForLastFailedPaymentIn")
+ @XmlElement(required=false, name="response")
+ private PaymentResponse[] responseForLastFailedPayment;
+
+ @XmlElement(required=false, name="controlTag")
+ private ControlTagType controlTag;
+
+ public boolean evaluate(BillingState state, DateTime now) {
+ return
+ (numberOfUnpaidInvoicesEqualsOrExceeds == null || state.getNumberOfUnpaidInvoices() >= numberOfUnpaidInvoicesEqualsOrExceeds.intValue() ) &&
+ (totalUnpaidInvoiceBalanceEqualsOrExceeds == null || totalUnpaidInvoiceBalanceEqualsOrExceeds.compareTo(state.getBalanceOfUnpaidInvoices()) <= 0) &&
+ (timeSinceEarliestUnpaidInvoiceEqualsOrExceeds == null || !timeSinceEarliestUnpaidInvoiceEqualsOrExceeds.addToDateTime(state.getDateOfEarliestUnpaidInvoice()).isAfter(now)) &&
+ (responseForLastFailedPayment == null || responseIsIn(state.getResponseForLastFailedPayment(), responseForLastFailedPayment)) &&
+ (controlTag == null || isTagIn(controlTag, state.getTags()));
+ }
+
+ private boolean responseIsIn(PaymentResponse actualResponse,
+ PaymentResponse[] responseForLastFailedPayment) {
+ for(PaymentResponse response: responseForLastFailedPayment) {
+ if(response.equals(actualResponse)) return true;
+ }
+ return false;
+ }
+
+ private boolean isTagIn(ControlTagType tag, Tag[] tags) {
+ for(Tag t : tags) {
+ if (t.getTagDefinitionName().equals(tag.toString())) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public ValidationErrors validate(StandaloneCatalog root,
+ ValidationErrors errors) {
+ return errors;
+ }
+
+ @Override
+ public void initialize(StandaloneCatalog root, URI uri) {
+ }
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/Overdue.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/Overdue.java
new file mode 100644
index 0000000..6d89a19
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/Overdue.java
@@ -0,0 +1,54 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.overdue.BillingStateBundle;
+import com.ning.billing.catalog.api.overdue.OverdueState;
+
+@XmlAccessorType(XmlAccessType.NONE)
+public class Overdue {
+
+ @XmlElement(required=false, name="bundleOverdueStages")
+ private OverdueStage<BundleCondition>[] bundleOverdueStages;
+
+
+ public List<OverdueState> calculateBundleOverdueState(BillingStateBundle[] states, DateTime now){
+ List<OverdueState> result = new ArrayList<OverdueState>();
+ for(BillingStateBundle state : states) {
+ for(OverdueStage<BundleCondition> stage : bundleOverdueStages) {
+ if(stage.getCondition().evaluate(state, now)) {
+ OverdueState ods = new OverdueState(state.getObjectId(),stage.getStageName(),
+ stage.getExternalMessage(), stage.isCancelled());
+ result.add(ods);
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStage.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStage.java
new file mode 100644
index 0000000..3af6b26
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStage.java
@@ -0,0 +1,73 @@
+/*
+ * 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 javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+
+@XmlAccessorType(XmlAccessType.NONE)
+public class OverdueStage<T extends Condition> {
+ @XmlElement(required=false, name="condition")
+ private T condition;
+
+ @XmlAttribute(required=false, name="stageName")
+ private String stageName;
+
+ @XmlElement(required=false, name="externalMessage")
+ private String externalMessage;
+
+ @XmlElement(required=false, name="cancel")
+ private boolean cancel;
+
+ public String getStageName() {
+ return stageName;
+ }
+
+ public String getExternalMessage() {
+ return externalMessage;
+ }
+ public boolean isCancelled() {
+ return cancel;
+ }
+
+ public T getCondition() {
+ return condition;
+ }
+
+ public OverdueStage<T> setStageName(String stageName) {
+ this.stageName = stageName;
+ return this;
+ }
+
+ public OverdueStage<T> setExternalMessage(String externalMessage) {
+ this.externalMessage = externalMessage;
+ return this;
+ }
+
+ public OverdueStage<T> setCancel(boolean cancel) {
+ this.cancel = cancel;
+ return this;
+ }
+
+ public OverdueStage<T> setCondition(T condition) {
+ this.condition = condition;
+ return this;
+ }
+
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockPriceList.java b/catalog/src/test/java/com/ning/billing/catalog/MockPriceList.java
new file mode 100644
index 0000000..9b672ba
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockPriceList.java
@@ -0,0 +1,28 @@
+/*
+ * 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.ning.billing.catalog.api.PriceListSet;
+
+public class MockPriceList extends DefaultPriceList {
+
+ public MockPriceList() {
+ setName(PriceListSet.DEFAULT_PRICELIST_NAME);
+ setRetired(false);
+ setPlans(MockPlan.createAll());
+ }
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/overdue/TestBundleCondition.java b/catalog/src/test/java/com/ning/billing/catalog/overdue/TestBundleCondition.java
new file mode 100644
index 0000000..69507cd
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/overdue/TestBundleCondition.java
@@ -0,0 +1,134 @@
+/*
+ * 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 java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.ControlTagType;
+import com.ning.billing.catalog.DefaultPriceList;
+import com.ning.billing.catalog.DefaultProduct;
+import com.ning.billing.catalog.MockPriceList;
+import com.ning.billing.catalog.MockProduct;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.overdue.BillingState;
+import com.ning.billing.catalog.api.overdue.BillingStateBundle;
+import com.ning.billing.catalog.api.overdue.PaymentResponse;
+import com.ning.billing.util.config.XMLLoader;
+import com.ning.billing.util.tag.DefaultControlTag;
+import com.ning.billing.util.tag.DescriptiveTag;
+import com.ning.billing.util.tag.Tag;
+
+public class TestBundleCondition {
+
+ @XmlRootElement(name="conditions")
+ private static class MockBundleCondition extends BundleCondition {}
+
+ @Test(groups={"fast"}, enabled=true)
+ public void testAccountState() throws Exception {
+ String xml =
+ "<conditions>" +
+ " <accountConditions>" +
+ " <controlTag>OVERDUE_ENFORCEMENT_OFF</controlTag>" +
+ " </accountConditions>" +
+ "</conditions>";
+ InputStream is = new ByteArrayInputStream(xml.getBytes());
+ BundleCondition c = XMLLoader.getObjectFromStreamNoValidation(is, MockBundleCondition.class);
+
+ DateTime now = new DateTime();
+
+ BillingState accountState0 = new BillingState(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.LOST_OR_STOLEN, new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.AUTO_BILLING_OFF),new DescriptiveTag(null, "Tag", "Martin", now)});
+ BillingState accountState1 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.OVERDUE_ENFORCEMENT_OFF)});
+ BillingState accountState2 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("200.00"), now.minusDays(20),
+ PaymentResponse.TEMPORARY_ACCOUNT_ISSUE,
+ new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.OVERDUE_ENFORCEMENT_OFF),
+ new DefaultControlTag("Martin", now, ControlTagType.AUTO_BILLING_OFF),
+ new DescriptiveTag(null, "Tag", "Martin", now)});
+
+ BillingStateBundle state0 = new BillingStateBundle(new UUID(0L,1L), accountState0, 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}, MockProduct.createBicycle(), BillingPeriod.MONTHLY, new MockPriceList() );
+ BillingStateBundle state1 = new BillingStateBundle(new UUID(0L,1L), accountState1, 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}, MockProduct.createBicycle(), BillingPeriod.MONTHLY, new MockPriceList() );
+ BillingStateBundle state2 = new BillingStateBundle(new UUID(0L,1L), accountState2, 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}, MockProduct.createBicycle(), BillingPeriod.MONTHLY, new MockPriceList() );
+
+ Assert.assertTrue(!c.evaluate(state0, new DateTime()));
+ Assert.assertTrue(c.evaluate(state1, new DateTime()));
+ Assert.assertTrue(c.evaluate(state2, new DateTime()));
+ }
+
+ @Test(groups={"fast"}, enabled=true)
+ public void testProduct() throws Exception {
+ DefaultProduct prod = MockProduct.createBicycle();
+ BundleCondition c = new BundleCondition().setBasePlanProduct(prod);
+
+ DateTime now = new DateTime();
+
+ BillingState accountState0 = new BillingState(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.LOST_OR_STOLEN, new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.AUTO_BILLING_OFF),new DescriptiveTag(null, "Tag", "Martin", now)});
+ BillingState accountState1 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.OVERDUE_ENFORCEMENT_OFF)});
+
+ BillingStateBundle state0 = new BillingStateBundle(new UUID(0L,1L), accountState0, 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}, MockProduct.createJet(), BillingPeriod.MONTHLY, new MockPriceList() );
+ BillingStateBundle state1 = new BillingStateBundle(new UUID(0L,1L), accountState1, 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}, prod, BillingPeriod.MONTHLY, new MockPriceList() );
+
+ Assert.assertTrue(!c.evaluate(state0, new DateTime()));
+ Assert.assertTrue(c.evaluate(state1, new DateTime()));
+ }
+
+
+ @Test(groups={"fast"}, enabled=true)
+ public void testBillingPeriod() throws Exception {
+ BundleCondition c = new BundleCondition().setBasePlanBillingPeriod(BillingPeriod.ANNUAL);
+
+ DateTime now = new DateTime();
+
+ BillingState accountState0 = new BillingState(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.LOST_OR_STOLEN, new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.AUTO_BILLING_OFF),new DescriptiveTag(null, "Tag", "Martin", now)});
+ BillingState accountState1 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.OVERDUE_ENFORCEMENT_OFF)});
+
+ BillingStateBundle state0 = new BillingStateBundle(new UUID(0L,1L), accountState0, 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}, MockProduct.createJet(), BillingPeriod.MONTHLY, new MockPriceList() );
+ BillingStateBundle state1 = new BillingStateBundle(new UUID(0L,1L), accountState1, 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}, MockProduct.createJet(), BillingPeriod.ANNUAL, new MockPriceList() );
+
+ Assert.assertTrue(!c.evaluate(state0, new DateTime()));
+ Assert.assertTrue(c.evaluate(state1, new DateTime()));
+ }
+
+ @Test(groups={"fast"}, enabled=true)
+ public void testPriceList() throws Exception {
+ DefaultPriceList pl = new MockPriceList().setName("test");
+ BundleCondition c = new BundleCondition().setBasePlanPriceList(pl);
+
+ DateTime now = new DateTime();
+
+ BillingState accountState0 = new BillingState(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.LOST_OR_STOLEN, new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.AUTO_BILLING_OFF),new DescriptiveTag(null, "Tag", "Martin", now)});
+ BillingState accountState1 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.OVERDUE_ENFORCEMENT_OFF)});
+
+ BillingStateBundle state0 = new BillingStateBundle(new UUID(0L,1L), accountState0, 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}, MockProduct.createJet(), BillingPeriod.MONTHLY, new MockPriceList() );
+ BillingStateBundle state1 = new BillingStateBundle(new UUID(0L,1L), accountState1, 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}, MockProduct.createJet(), BillingPeriod.MONTHLY, pl );
+
+ Assert.assertTrue(!c.evaluate(state0, new DateTime()));
+ Assert.assertTrue(c.evaluate(state1, new DateTime()));
+ }
+
+ //MDW TODO: test Pricelist and billing period
+
+
+
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/overdue/TestCondition.java b/catalog/src/test/java/com/ning/billing/catalog/overdue/TestCondition.java
new file mode 100644
index 0000000..3993a8b
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/overdue/TestCondition.java
@@ -0,0 +1,149 @@
+/*
+ * 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 java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import javax.swing.DefaultDesktopManager;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.ControlTagType;
+import com.ning.billing.catalog.api.overdue.BillingState;
+import com.ning.billing.catalog.api.overdue.PaymentResponse;
+import com.ning.billing.util.config.XMLLoader;
+import com.ning.billing.util.tag.ControlTag;
+import com.ning.billing.util.tag.DefaultControlTag;
+import com.ning.billing.util.tag.DefaultTagDefinition;
+import com.ning.billing.util.tag.DescriptiveTag;
+import com.ning.billing.util.tag.Tag;
+
+public class TestCondition {
+
+ @XmlRootElement(name="condition")
+ private static class MockCondition extends Condition {}
+
+ @Test(groups={"fast"}, enabled=true)
+ public void testNumberOfUnpaidInvoicesEqualsOrExceeds() throws Exception {
+ String xml =
+ "<condition>" +
+ " <numberOfUnpaidInvoicesEqualsOrExceeds>1</numberOfUnpaidInvoicesEqualsOrExceeds>" +
+ "</condition>";
+ InputStream is = new ByteArrayInputStream(xml.getBytes());
+ MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is, MockCondition.class);
+
+ BillingState state0 = new BillingState(new UUID(0L,1L), 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+ BillingState state1 = new BillingState(new UUID(0L,1L), 1, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+ BillingState state2 = new BillingState(new UUID(0L,1L), 2, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+
+ Assert.assertTrue(!c.evaluate(state0, new DateTime()));
+ Assert.assertTrue(c.evaluate(state1, new DateTime()));
+ Assert.assertTrue(c.evaluate(state2, new DateTime()));
+ }
+
+ @Test(groups={"fast"}, enabled=true)
+ public void testTotalUnpaidInvoiceBalanceEqualsOrExceeds() throws Exception {
+ String xml =
+ "<condition>" +
+ " <totalUnpaidInvoiceBalanceEqualsOrExceeds>100.00</totalUnpaidInvoiceBalanceEqualsOrExceeds>" +
+ "</condition>";
+ InputStream is = new ByteArrayInputStream(xml.getBytes());
+ MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is, MockCondition.class);
+
+ BillingState state0 = new BillingState(new UUID(0L,1L), 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+ BillingState state1 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("100.00"), new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+ BillingState state2 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("200.00"), new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+
+ Assert.assertTrue(!c.evaluate(state0, new DateTime()));
+ Assert.assertTrue(c.evaluate(state1, new DateTime()));
+ Assert.assertTrue(c.evaluate(state2, new DateTime()));
+ }
+
+
+ @Test(groups={"fast"}, enabled=true)
+ public void testTimeSinceEarliestUnpaidInvoiceEqualsOrExceeds() throws Exception {
+ String xml =
+ "<condition>" +
+ " <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds><unit>DAYS</unit><number>10</number></timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ "</condition>";
+ InputStream is = new ByteArrayInputStream(xml.getBytes());
+ MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is, MockCondition.class);
+
+ DateTime now = new DateTime();
+
+ BillingState state0 = new BillingState(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+ BillingState state1 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+ BillingState state2 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("200.00"), now.minusDays(20), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+
+ Assert.assertTrue(!c.evaluate(state0, now));
+ Assert.assertTrue(c.evaluate(state1, now));
+ Assert.assertTrue(c.evaluate(state2, now));
+ }
+
+ @Test(groups={"fast"}, enabled=true)
+ public void testResponseForLastFailedPaymentIn() throws Exception {
+ String xml =
+ "<condition>" +
+ " <responseForLastFailedPaymentIn><response>INSUFFICIENT_FUNDS</response><response>TEMPORARY_ACCOUNT_ISSUE</response></responseForLastFailedPaymentIn>" +
+ "</condition>";
+ InputStream is = new ByteArrayInputStream(xml.getBytes());
+ MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is, MockCondition.class);
+
+ DateTime now = new DateTime();
+
+ BillingState state0 = new BillingState(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.LOST_OR_STOLEN, new Tag[]{});
+ BillingState state1 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+ BillingState state2 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("200.00"), now.minusDays(20), PaymentResponse.TEMPORARY_ACCOUNT_ISSUE, new Tag[]{});
+
+ Assert.assertTrue(!c.evaluate(state0, now));
+ Assert.assertTrue(c.evaluate(state1, now));
+ Assert.assertTrue(c.evaluate(state2, now));
+ }
+
+ @Test(groups={"fast"}, enabled=true)
+ public void testHasControlTag() throws Exception {
+ String xml =
+ "<condition>" +
+ " <controlTag>OVERDUE_ENFORCEMENT_OFF</controlTag>" +
+ "</condition>";
+ InputStream is = new ByteArrayInputStream(xml.getBytes());
+ MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is, MockCondition.class);
+
+ DateTime now = new DateTime();
+
+ BillingState state0 = new BillingState(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.LOST_OR_STOLEN, new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.AUTO_BILLING_OFF),new DescriptiveTag(null, "Tag", "Martin", now)});
+ BillingState state1 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.OVERDUE_ENFORCEMENT_OFF)});
+ BillingState state2 = new BillingState(new UUID(0L,1L), 1, new BigDecimal("200.00"), now.minusDays(20),
+ PaymentResponse.TEMPORARY_ACCOUNT_ISSUE,
+ new Tag[]{new DefaultControlTag("Martin", now, ControlTagType.OVERDUE_ENFORCEMENT_OFF),
+ new DefaultControlTag("Martin", now, ControlTagType.AUTO_BILLING_OFF),
+ new DescriptiveTag(null, "Tag", "Martin", now)});
+
+ Assert.assertTrue(!c.evaluate(state0, now));
+ Assert.assertTrue(c.evaluate(state1, now));
+ Assert.assertTrue(c.evaluate(state2, now));
+ }
+
+
+
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/overdue/TestOverdue.java b/catalog/src/test/java/com/ning/billing/catalog/overdue/TestOverdue.java
new file mode 100644
index 0000000..16f2118
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/overdue/TestOverdue.java
@@ -0,0 +1,21 @@
+/*
+ * 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;
+
+public class TestOverdue {
+
+}
diff --git a/util/src/main/java/com/ning/billing/util/config/XMLLoader.java b/util/src/main/java/com/ning/billing/util/config/XMLLoader.java
index d0487b8..9d35352 100644
--- a/util/src/main/java/com/ning/billing/util/config/XMLLoader.java
+++ b/util/src/main/java/com/ning/billing/util/config/XMLLoader.java
@@ -71,6 +71,18 @@ public class XMLLoader {
return null;
}
}
+
+ public static <T> T getObjectFromStreamNoValidation(InputStream stream, Class<T> clazz) throws SAXException, InvalidConfigException, JAXBException, IOException, TransformerException {
+ Object o = unmarshaller(clazz).unmarshal(stream);
+ if (clazz.isInstance(o)) {
+ @SuppressWarnings("unchecked")
+ T castObject = (T)o;
+ return castObject;
+ } else {
+ return null;
+ }
+ }
+
public static <T extends ValidatingConfig<T>> void validate(URI uri, T c) throws ValidationException {
c.initialize(c, uri);