killbill-memoizeit
Changes
pom.xml 2(+1 -1)
Details
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueCondition.java b/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueCondition.java
index ee30861..743012e 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueCondition.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/config/DefaultOverdueCondition.java
@@ -60,6 +60,9 @@ public class DefaultOverdueCondition extends ValidatingConfig<DefaultOverdueConf
@XmlElement(required = false, name = "controlTag")
private ControlTagType controlTag;
+ @XmlElement(required = false, name = "controlTagExclusion")
+ private ControlTagType controlTagExclusion;
+
@Override
public boolean evaluate(final BillingState state, final LocalDate date) {
LocalDate unpaidInvoiceTriggerDate = null;
@@ -73,7 +76,8 @@ public class DefaultOverdueCondition extends ValidatingConfig<DefaultOverdueConf
(timeSinceEarliestUnpaidInvoiceEqualsOrExceeds == null ||
(unpaidInvoiceTriggerDate != null && !unpaidInvoiceTriggerDate.isAfter(date))) &&
(responseForLastFailedPayment == null || responseIsIn(state.getResponseForLastFailedPayment(), responseForLastFailedPayment)) &&
- (controlTag == null || isTagIn(controlTag, state.getTags()));
+ (controlTag == null || isTagIn(controlTag, state.getTags())) &&
+ (controlTagExclusion == null || isTagNotIn(controlTagExclusion, state.getTags()));
}
private boolean responseIsIn(final PaymentResponse actualResponse,
@@ -95,6 +99,15 @@ public class DefaultOverdueCondition extends ValidatingConfig<DefaultOverdueConf
return false;
}
+ private boolean isTagNotIn(final ControlTagType tagType, final Tag[] tags) {
+ for (final Tag t : tags) {
+ if (t.getTagDefinitionId().equals(tagType.getId())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@Override
public ValidationErrors validate(final DefaultOverdueConfig root,
final ValidationErrors errors) {
@@ -140,6 +153,11 @@ public class DefaultOverdueCondition extends ValidatingConfig<DefaultOverdueConf
}
@Override
+ public ControlTagType getExclusionControlTagType() {
+ return controlTagExclusion;
+ }
+
+ @Override
public String toString() {
final StringBuilder sb = new StringBuilder("DefaultOverdueCondition{");
sb.append("numberOfUnpaidInvoicesEqualsOrExceeds=").append(numberOfUnpaidInvoicesEqualsOrExceeds);
@@ -147,6 +165,7 @@ public class DefaultOverdueCondition extends ValidatingConfig<DefaultOverdueConf
sb.append(", timeSinceEarliestUnpaidInvoiceEqualsOrExceeds=").append(timeSinceEarliestUnpaidInvoiceEqualsOrExceeds);
sb.append(", responseForLastFailedPayment=").append(Arrays.toString(responseForLastFailedPayment));
sb.append(", controlTag=").append(controlTag);
+ sb.append(", controlTagExclusion=").append(controlTagExclusion);
sb.append('}');
return sb.toString();
}
diff --git a/overdue/src/test/resources/OverdueConfigSchema.xsd b/overdue/src/test/resources/OverdueConfigSchema.xsd
index d8f014b..dfb0e47 100644
--- a/overdue/src/test/resources/OverdueConfigSchema.xsd
+++ b/overdue/src/test/resources/OverdueConfigSchema.xsd
@@ -72,6 +72,7 @@
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" name="controlTag" type="controlTagType"/>
+<xs:element minOccurs="0" name="controlTagExclusion" type="controlTagType"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index ee51037..801d529 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
<parent>
<artifactId>killbill-oss-parent</artifactId>
<groupId>org.kill-bill.billing</groupId>
- <version>0.122</version>
+ <version>0.123-SNAPSHOT</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.17.3-SNAPSHOT</version>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
index d504896..1380883 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
@@ -147,6 +147,19 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
return accountJson;
}
+ protected Account createAccountNoPMBundleAndSubscription() throws Exception {
+ // Create an account with no payment method
+ final Account accountJson = createAccount();
+ assertNotNull(accountJson);
+
+ // Add a bundle, subscription and move the clock to get the first invoice
+ final Subscription subscriptionJson = createEntitlement(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
+ ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+ assertNotNull(subscriptionJson);
+
+ return accountJson;
+ }
+
protected Account createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice() throws Exception {
// Create an account with no payment method
final Account accountJson = createAccount();
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java
index 6685955..f2f8f2c 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java
@@ -27,6 +27,8 @@ import org.killbill.billing.client.model.Invoice;
import org.killbill.billing.client.model.InvoicePayment;
import org.killbill.billing.client.model.Invoices;
import org.killbill.billing.client.model.Payment;
+import org.killbill.billing.client.model.Tags;
+import org.killbill.billing.util.tag.ControlTagType;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -46,7 +48,6 @@ public class TestOverdue extends TestJaxrsBase {
Assert.assertNotNull(overdueConfig);
}
-
@Test(groups = "slow", description = "Can retrieve the account overdue status")
public void testOverdueStatus() throws Exception {
// Create an account without a payment method
@@ -99,4 +100,83 @@ public class TestOverdue extends TestJaxrsBase {
// Verify we're in clear state
Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJson.getAccountId()).getIsClearState());
}
+
+ @Test(groups = "slow", description = "Allow overdue condition by control tag defined in overdue config xml file")
+ public void testControlTagOverdueConfig() throws Exception {
+ final String overdueConfigPath = Resources.getResource("overdueWithControlTag.xml").getPath();
+ killBillClient.uploadXMLOverdueConfig(overdueConfigPath, requestOptions);
+
+ // Create an account without a payment method and assign a TEST tag
+ final Account accountJson = createAccountNoPMBundleAndSubscription();
+ final Tags accountTag = killBillClient.createAccountTag(accountJson.getAccountId(), ControlTagType.TEST.getId(), requestOptions);
+ assertEquals(accountTag.get(0).getTagDefinitionId(), ControlTagType.TEST.getId());
+
+ // Create an account without a TEST tag
+ final Account accountJsonNoTag = createAccountNoPMBundleAndSubscription();
+
+ // No payment will be triggered as the account doesn't have a payment method
+ clock.addMonths(1);
+ crappyWaitForLackOfProperSynchonization();
+
+ // Get the invoices
+ final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+ // 2 invoices but look for the non zero dollar one
+ assertEquals(invoices.size(), 2);
+
+ final List<Invoice> invoicesNoTag = killBillClient.getInvoicesForAccount(accountJsonNoTag.getAccountId(), requestOptions);
+ // 2 invoices but look for the non zero dollar one
+ assertEquals(invoicesNoTag.size(), 2);
+
+ // We're still clear - see the configuration
+ Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getIsClearState());
+ Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJsonNoTag.getAccountId(), requestOptions).getIsClearState());
+
+ clock.addDays(30);
+ crappyWaitForLackOfProperSynchonization();
+
+ // This account is expected to move to OD1 state because it matches with controlTag defined
+ Assert.assertEquals(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getName(), "OD1");
+ // This account is not expected to move to OD1 state because it does not match with controlTag defined
+ Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJsonNoTag.getAccountId(), requestOptions).getIsClearState());
+ }
+
+ @Test(groups = "slow", description = "Allow overdue condition by exclusion control tag defined in overdue config xml file")
+ public void testExclusionControlTagOverdueConfig() throws Exception {
+ final String overdueConfigPath = Resources.getResource("overdueWithExclusionControlTag.xml").getPath();
+ killBillClient.uploadXMLOverdueConfig(overdueConfigPath, requestOptions);
+
+ // Create an account without a payment method and assign a TEST tag
+ final Account accountJson = createAccountNoPMBundleAndSubscription();
+ final Tags accountTag = killBillClient.createAccountTag(accountJson.getAccountId(), ControlTagType.TEST.getId(), requestOptions);
+ assertEquals(accountTag.get(0).getTagDefinitionId(), ControlTagType.TEST.getId());
+
+ // Create an account without a TEST tag
+ final Account accountJsonNoTag = createAccountNoPMBundleAndSubscription();
+
+ // move a month a wait for invoicing
+ // No payment will be triggered as the account doesn't have a payment method
+ clock.addMonths(1);
+ crappyWaitForLackOfProperSynchonization();
+
+ // Get the invoices
+ final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+ // 2 invoices but look for the non zero dollar one
+ assertEquals(invoices.size(), 2);
+
+ final List<Invoice> invoicesNoTag = killBillClient.getInvoicesForAccount(accountJsonNoTag.getAccountId(), requestOptions);
+ // 2 invoices but look for the non zero dollar one
+ assertEquals(invoicesNoTag.size(), 2);
+
+ // We're still clear - see the configuration
+ Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getIsClearState());
+ Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJsonNoTag.getAccountId(), requestOptions).getIsClearState());
+
+ clock.addDays(30);
+ crappyWaitForLackOfProperSynchonization();
+
+ // This account is not expected to move to OD1 state because it does not match with exclusion controlTag defined
+ Assert.assertTrue(killBillClient.getOverdueStateForAccount(accountJson.getAccountId(), requestOptions).getIsClearState());
+ // This account is expected to move to OD1 state because it matches with exclusion controlTag defined
+ Assert.assertEquals(killBillClient.getOverdueStateForAccount(accountJsonNoTag.getAccountId(), requestOptions).getName(), "OD1");
+ }
}
diff --git a/profiles/killbill/src/test/resources/overdueWithControlTag.xml b/profiles/killbill/src/test/resources/overdueWithControlTag.xml
new file mode 100644
index 0000000..dcb06f9
--- /dev/null
+++ b/profiles/killbill/src/test/resources/overdueWithControlTag.xml
@@ -0,0 +1,63 @@
+<!--
+ ~ Copyright 2014-2016 Groupon, Inc
+ ~ Copyright 2014-2016 The Billing Project, LLC
+ ~
+ ~ The Billing Project licenses this file to you under the Apache License, version 2.0
+ ~ (the "License"); you may not use this file except in compliance with the
+ ~ License. You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ ~ License for the specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<overdueConfig>
+ <accountOverdueStates>
+ <state name="OD3">
+ <condition>
+ <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <unit>DAYS</unit><number>50</number>
+ </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <controlTag>TEST</controlTag>
+ </condition>
+ <externalMessage>Reached OD3</externalMessage>
+ <blockChanges>true</blockChanges>
+ <disableEntitlementAndChangesBlocked>true</disableEntitlementAndChangesBlocked>
+ <autoReevaluationInterval>
+ <unit>DAYS</unit><number>5</number>
+ </autoReevaluationInterval>
+ </state>
+ <state name="OD2">
+ <condition>
+ <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <unit>DAYS</unit><number>40</number>
+ </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <controlTag>TEST</controlTag>
+ </condition>
+ <externalMessage>Reached OD2</externalMessage>
+ <blockChanges>true</blockChanges>
+ <disableEntitlementAndChangesBlocked>true</disableEntitlementAndChangesBlocked>
+ <autoReevaluationInterval>
+ <unit>DAYS</unit><number>5</number>
+ </autoReevaluationInterval>
+ </state>
+ <state name="OD1">
+ <condition>
+ <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <unit>DAYS</unit><number>30</number>
+ </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <controlTag>TEST</controlTag>
+ </condition>
+ <externalMessage>Reached OD1</externalMessage>
+ <blockChanges>true</blockChanges>
+ <disableEntitlementAndChangesBlocked>false</disableEntitlementAndChangesBlocked>
+ <autoReevaluationInterval>
+ <unit>DAYS</unit><number>5</number>
+ </autoReevaluationInterval>
+ </state>
+ </accountOverdueStates>
+</overdueConfig>
diff --git a/profiles/killbill/src/test/resources/overdueWithExclusionControlTag.xml b/profiles/killbill/src/test/resources/overdueWithExclusionControlTag.xml
new file mode 100644
index 0000000..1da2113
--- /dev/null
+++ b/profiles/killbill/src/test/resources/overdueWithExclusionControlTag.xml
@@ -0,0 +1,63 @@
+<!--
+ ~ Copyright 2014-2016 Groupon, Inc
+ ~ Copyright 2014-2016 The Billing Project, LLC
+ ~
+ ~ The Billing Project licenses this file to you under the Apache License, version 2.0
+ ~ (the "License"); you may not use this file except in compliance with the
+ ~ License. You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ ~ License for the specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<overdueConfig>
+ <accountOverdueStates>
+ <state name="OD3">
+ <condition>
+ <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <unit>DAYS</unit><number>50</number>
+ </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <controlTagExclusion>TEST</controlTagExclusion>
+ </condition>
+ <externalMessage>Reached OD3</externalMessage>
+ <blockChanges>true</blockChanges>
+ <disableEntitlementAndChangesBlocked>true</disableEntitlementAndChangesBlocked>
+ <autoReevaluationInterval>
+ <unit>DAYS</unit><number>5</number>
+ </autoReevaluationInterval>
+ </state>
+ <state name="OD2">
+ <condition>
+ <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <unit>DAYS</unit><number>40</number>
+ </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <controlTagExclusion>TEST</controlTagExclusion>
+ </condition>
+ <externalMessage>Reached OD2</externalMessage>
+ <blockChanges>true</blockChanges>
+ <disableEntitlementAndChangesBlocked>true</disableEntitlementAndChangesBlocked>
+ <autoReevaluationInterval>
+ <unit>DAYS</unit><number>5</number>
+ </autoReevaluationInterval>
+ </state>
+ <state name="OD1">
+ <condition>
+ <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <unit>DAYS</unit><number>30</number>
+ </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>
+ <controlTagExclusion>TEST</controlTagExclusion>
+ </condition>
+ <externalMessage>Reached OD1</externalMessage>
+ <blockChanges>true</blockChanges>
+ <disableEntitlementAndChangesBlocked>false</disableEntitlementAndChangesBlocked>
+ <autoReevaluationInterval>
+ <unit>DAYS</unit><number>5</number>
+ </autoReevaluationInterval>
+ </state>
+ </accountOverdueStates>
+</overdueConfig>