killbill-memoizeit

beatrix: Add test case to verify we can invoice PENDING subscription

4/20/2017 1:06:09 AM

Details

diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index f32d4bf..27b7116 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -18,18 +18,15 @@
 
 package org.killbill.billing.beatrix.integration;
 
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.Callable;
-
-import javax.annotation.Nullable;
-import javax.inject.Inject;
-import javax.inject.Named;
-
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Stage;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
@@ -129,15 +126,16 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Stage;
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.Callable;
 
 import static com.jayway.awaitility.Awaitility.await;
 import static java.util.concurrent.TimeUnit.SECONDS;
@@ -427,19 +425,22 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
         return new TestPaymentMethodPlugin();
     }
 
-    protected AccountData getAccountData(final int billingDay) {
-        return new MockAccountBuilder().name(UUID.randomUUID().toString().substring(1, 8))
-                                       .firstNameLength(6)
-                                       .email(UUID.randomUUID().toString().substring(1, 8))
-                                       .phone(UUID.randomUUID().toString().substring(1, 8))
-                                       .migrated(false)
-                                       .isNotifiedForInvoices(false)
-                                       .externalKey(UUID.randomUUID().toString().substring(1, 8))
-                                       .billingCycleDayLocal(billingDay)
-                                       .currency(Currency.USD)
-                                       .paymentMethodId(UUID.randomUUID())
-                                       .timeZone(DateTimeZone.UTC)
-                                       .build();
+    protected AccountData getAccountData(@Nullable final Integer billingDay) {
+        final MockAccountBuilder builder = new MockAccountBuilder()
+                .name(UUID.randomUUID().toString().substring(1, 8))
+                .firstNameLength(6)
+                .email(UUID.randomUUID().toString().substring(1, 8))
+                .phone(UUID.randomUUID().toString().substring(1, 8))
+                .migrated(false)
+                .isNotifiedForInvoices(false)
+                .externalKey(UUID.randomUUID().toString().substring(1, 8))
+                .currency(Currency.USD)
+                .paymentMethodId(UUID.randomUUID())
+                .timeZone(DateTimeZone.UTC);
+        if (billingDay != null) {
+            builder.billingCycleDayLocal(billingDay);
+        }
+        return builder.build();
     }
 
     protected AccountData getChildAccountData(final int billingDay, final UUID parentAccountId, final boolean isPaymentDelegatedToParent) {
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
index 2402ed2..a697d6c 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
@@ -25,30 +25,39 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
+import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.api.TestApiListener.NextEvent;
 import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
+import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PriceListSet;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.DefaultEntitlement;
 import org.killbill.billing.entitlement.api.Entitlement;
+import org.killbill.billing.entitlement.api.EntitlementApiException;
+import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.invoice.api.DryRunArguments;
 import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
+import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.api.InvoiceItemType;
 import org.killbill.billing.invoice.model.ExternalChargeInvoiceItem;
 import org.killbill.billing.payment.api.Payment;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
+import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
 
+import static com.tc.util.Assert.fail;
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
 public class TestIntegrationInvoice extends TestIntegrationBase {
@@ -361,5 +370,78 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
         assertListenerStatus();
     }
 
+    @Test(groups = "slow")
+    public void testDryRunWithPendingSubscription() throws Exception {
+
+        final LocalDate initialDate = new LocalDate(2017, 4, 1);
+        clock.setDay(initialDate);
+
+        // Create account with non BCD to force junction BCD logic to activate
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(null));
+
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+
+        final LocalDate futureDate = new LocalDate(2017, 5, 1);
+
+        // No CREATE event as this is set in the future
+        final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, futureDate, false, ImmutableList.<PluginProperty>of(), callContext);
+        assertEquals(createdEntitlement.getState(), Entitlement.EntitlementState.PENDING);
+        assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(futureDate), 0);
+        assertEquals(createdEntitlement.getEffectiveEndDate(), null);
+        assertListenerStatus();
+
+        // Generate a dryRun invoice on the billing startDate
+        final DryRunArguments dryRunArguments1 = new TestDryRunArguments(DryRunType.TARGET_DATE);
+        final Invoice dryRunInvoice1 = invoiceUserApi.triggerInvoiceGeneration(createdEntitlement.getAccountId(), futureDate, dryRunArguments1, callContext);
+        assertEquals(dryRunInvoice1.getInvoiceItems().size(), 1);
+        assertEquals(dryRunInvoice1.getInvoiceItems().get(0).getInvoiceItemType(),  InvoiceItemType.FIXED);
+        assertEquals(dryRunInvoice1.getInvoiceItems().get(0).getAmount().compareTo(BigDecimal.ZERO), 0);
+        assertEquals(dryRunInvoice1.getInvoiceItems().get(0).getStartDate(),  futureDate);
+        assertEquals(dryRunInvoice1.getInvoiceItems().get(0).getPlanName(),  "shotgun-annual");
+
+
+        // Generate a dryRun invoice with a plan change
+        final DryRunArguments dryRunArguments = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null,
+                SubscriptionEventType.CHANGE,  createdEntitlement.getId(), createdEntitlement.getBundleId(), futureDate, BillingActionPolicy.IMMEDIATE);
+
+        // First one day prior subscription starts
+        try {
+            invoiceUserApi.triggerInvoiceGeneration(createdEntitlement.getAccountId(), futureDate.minusDays(1), dryRunArguments, callContext);
+            fail("Should fail to trigger dryRun invoice prior subscription starts");
+        } catch (final InvoiceApiException e) {
+            assertEquals(e.getCode(),ErrorCode.INVOICE_NOTHING_TO_DO.getCode());
+        }
+
+        // Second, on the startDate
+        final Invoice dryRunInvoice2 = invoiceUserApi.triggerInvoiceGeneration(createdEntitlement.getAccountId(), futureDate, dryRunArguments, callContext);
+        assertEquals(dryRunInvoice2.getInvoiceItems().size(), 1);
+        assertEquals(dryRunInvoice2.getInvoiceItems().get(0).getInvoiceItemType(),  InvoiceItemType.FIXED);
+        assertEquals(dryRunInvoice2.getInvoiceItems().get(0).getAmount().compareTo(BigDecimal.ZERO), 0);
+        assertEquals(dryRunInvoice2.getInvoiceItems().get(0).getStartDate(),  futureDate);
+        assertEquals(dryRunInvoice2.getInvoiceItems().get(0).getPlanName(),  "pistol-monthly");
+
+
+        // Check BCD is not yet set
+        final Account refreshedAccount1 = accountUserApi.getAccountById(account.getId(), callContext);
+        assertEquals(refreshedAccount1.getBillCycleDayLocal(), new Integer(0));
+
+
+        busHandler.pushExpectedEvents(NextEvent.INVOICE);
+        final Invoice realInvoice = invoiceUserApi.triggerInvoiceGeneration(createdEntitlement.getAccountId(), futureDate, null, callContext);
+        assertListenerStatus();
+
+        assertEquals(realInvoice.getInvoiceItems().size(), 1);
+        assertEquals(realInvoice.getInvoiceItems().get(0).getInvoiceItemType(),  InvoiceItemType.FIXED);
+        assertEquals(realInvoice.getInvoiceItems().get(0).getAmount().compareTo(BigDecimal.ZERO), 0);
+        assertEquals(realInvoice.getInvoiceItems().get(0).getStartDate(),  futureDate);
+        assertEquals(realInvoice.getInvoiceItems().get(0).getPlanName(),  "shotgun-annual");
+
+        // Check BCD is now set
+        final Account refreshedAccount2 = accountUserApi.getAccountById(account.getId(), callContext);
+        assertEquals(refreshedAccount2.getBillCycleDayLocal(), new Integer(31));
+
+    }
+
+
 
 }