From ce4007ef1f830ecb82f7781ea01b34dbc6948b0b Mon Sep 17 00:00:00 2001 From: maciej-nedza <76946708+maciej-nedza@users.noreply.github.com> Date: Tue, 5 Mar 2024 09:21:52 +0100 Subject: [PATCH] [DE-676] Proforma invoices tests 2 (#121) --- ...cesControllerCreateSignupProformaTest.java | 79 ++++ .../ProformaInvoicesControllerCreateTest.java | 18 +- ...esControllerPreviewSignupProformaTest.java | 93 +++++ ...ProformaInvoicesControllerPreviewTest.java | 31 +- .../ProformaInvoicesControllerReadTest.java | 12 +- ...oicesControllerSubscriptionGroupsTest.java | 209 ++++++++++ .../ProformaInvoicesControllerVoidTest.java | 24 +- .../ProformaInvoicesCreator.java | 319 --------------- .../ProformaInvoicesTestBase.java | 380 ++++++++++++++++++ .../advancedbilling/utils/TestSetup.java | 3 + 10 files changed, 797 insertions(+), 371 deletions(-) create mode 100644 tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerCreateSignupProformaTest.java create mode 100644 tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerPreviewSignupProformaTest.java create mode 100644 tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerSubscriptionGroupsTest.java delete mode 100644 tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesCreator.java create mode 100644 tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesTestBase.java diff --git a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerCreateSignupProformaTest.java b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerCreateSignupProformaTest.java new file mode 100644 index 00000000..43572fd0 --- /dev/null +++ b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerCreateSignupProformaTest.java @@ -0,0 +1,79 @@ +package com.maxio.advancedbilling.controllers.proformainvoices; + +import com.maxio.advancedbilling.TestClient; +import com.maxio.advancedbilling.exceptions.ApiException; +import com.maxio.advancedbilling.models.Component; +import com.maxio.advancedbilling.models.CreateSubscription; +import com.maxio.advancedbilling.models.CreateSubscriptionRequest; +import com.maxio.advancedbilling.models.Customer; +import com.maxio.advancedbilling.models.ProformaInvoice; +import com.maxio.advancedbilling.utils.TestTeardown; +import com.maxio.advancedbilling.utils.assertions.CommonAssertions; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class ProformaInvoicesControllerCreateSignupProformaTest extends ProformaInvoicesTestBase { + + private static Customer customer; + + @BeforeAll + static void setUp() throws IOException, ApiException { + customer = TEST_SETUP.createCustomer(); + } + + @AfterAll + static void teardown() throws IOException, ApiException { + new TestTeardown().deleteCustomer(customer); + } + + @Test + void shouldCreateSignupProforma() throws IOException, ApiException { + // given - when + ProformaInvoiceWithComponents invoiceWithData = createSignupProformaInvoice(customer); + + // then + assertProformaInvoice(customer, invoiceWithData, true, true); + } + + @Test + void shouldReturn422WhenCreatingProformaInvoiceWithInvalidData() { + // when - then + CommonAssertions + .assertThatErrorArrayMapResponse(() -> PROFORMA_INVOICES_CONTROLLER.createSignupProformaInvoice( + new CreateSubscriptionRequest(new CreateSubscription.Builder() + .productId(11) + .build() + ) + ) + ) + .isUnprocessableEntity() + .hasErrorMap(Map.of("base", List.of("Couldn't find Product by 11"))); + } + + @Test + void shouldReturn401WhenProvidingInvalidCredentials() { + // when - then + CommonAssertions.assertUnauthorized(() -> TestClient.createInvalidCredentialsClient().getProformaInvoicesController() + .createSignupProformaInvoice(null) + ); + } + + private ProformaInvoiceWithComponents createSignupProformaInvoice(Customer customer) throws IOException, ApiException { + Component meteredComponent = TEST_SETUP.createMeteredComponent(productFamily, 11.5); + Component quantityBasedComponent = TEST_SETUP.createQuantityBasedComponent(productFamily.getId()); + + ProformaInvoice proformaInvoice = CLIENT.getProformaInvoicesController().createSignupProformaInvoice( + new CreateSubscriptionRequest( + getCreateSubscription(customer, meteredComponent, quantityBasedComponent) + ) + ); + + return new ProformaInvoiceWithComponents(proformaInvoice, quantityBasedComponent, meteredComponent); + } + +} diff --git a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerCreateTest.java b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerCreateTest.java index cd255da4..2bb90fec 100644 --- a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerCreateTest.java +++ b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerCreateTest.java @@ -1,11 +1,8 @@ package com.maxio.advancedbilling.controllers.proformainvoices; -import com.maxio.advancedbilling.AdvancedBillingClient; import com.maxio.advancedbilling.TestClient; -import com.maxio.advancedbilling.controllers.ProformaInvoicesController; import com.maxio.advancedbilling.exceptions.ApiException; import com.maxio.advancedbilling.models.Customer; -import com.maxio.advancedbilling.utils.TestSetup; import com.maxio.advancedbilling.utils.TestTeardown; import com.maxio.advancedbilling.utils.assertions.CommonAssertions; import org.junit.jupiter.api.AfterAll; @@ -14,12 +11,7 @@ import java.io.IOException; -public class ProformaInvoicesControllerCreateTest { - - private static final TestSetup TEST_SETUP = new TestSetup(); - private static final AdvancedBillingClient CLIENT = TestClient.createClient(); - private static final ProformaInvoicesController PROFORMA_INVOICES_CONTROLLER = CLIENT - .getProformaInvoicesController(); +public class ProformaInvoicesControllerCreateTest extends ProformaInvoicesTestBase { private static Customer customer; @@ -35,13 +27,11 @@ static void teardown() throws IOException, ApiException { @Test void shouldCreateProformaInvoice() throws IOException, ApiException { - // given-when - ProformaInvoicesCreator proformaInvoicesCreator = new ProformaInvoicesCreator(); - ProformaInvoicesCreator.ProformaInvoiceWithComponents invoiceWithData = - proformaInvoicesCreator.createProformaInvoiceWithComponents(customer); + // given - when + ProformaInvoiceWithComponents invoiceWithData = createProformaInvoiceWithComponents(customer); // then - proformaInvoicesCreator.assertProformaInvoice(customer, invoiceWithData, true); + assertProformaInvoice(customer, invoiceWithData, true, false); } @Test diff --git a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerPreviewSignupProformaTest.java b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerPreviewSignupProformaTest.java new file mode 100644 index 00000000..419e668b --- /dev/null +++ b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerPreviewSignupProformaTest.java @@ -0,0 +1,93 @@ +package com.maxio.advancedbilling.controllers.proformainvoices; + +import com.maxio.advancedbilling.TestClient; +import com.maxio.advancedbilling.exceptions.ApiException; +import com.maxio.advancedbilling.models.Component; +import com.maxio.advancedbilling.models.CreateSignupProformaPreviewInclude; +import com.maxio.advancedbilling.models.CreateSubscription; +import com.maxio.advancedbilling.models.CreateSubscriptionRequest; +import com.maxio.advancedbilling.models.Customer; +import com.maxio.advancedbilling.models.SignupProformaPreview; +import com.maxio.advancedbilling.utils.TestTeardown; +import com.maxio.advancedbilling.utils.assertions.CommonAssertions; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ProformaInvoicesControllerPreviewSignupProformaTest extends ProformaInvoicesTestBase { + + private static Customer customer; + + @BeforeAll + static void setUp() throws IOException, ApiException { + customer = TEST_SETUP.createCustomer(); + } + + @AfterAll + static void teardown() throws IOException, ApiException { + new TestTeardown().deleteCustomer(customer); + } + + @Test + void shouldPreviewSignupProformaWithNextProforma() throws IOException, ApiException { + // given - when + SignupProformaPreviewWithComponents previewWithData = previewSignupProformaInvoice(customer); + + // then + ProformaInvoiceWithComponents proformaInvoiceWithComponents = new ProformaInvoiceWithComponents( + previewWithData.preview().getCurrentProformaInvoice(), + previewWithData.quantityBasedComponent(), previewWithData.meteredComponent() + ); + assertProformaInvoice(customer, proformaInvoiceWithComponents, false, true); + + assertThat(previewWithData.preview().getNextProformaInvoice()).usingRecursiveComparison() + .ignoringFields("createdAt", "subtotalAmount", "totalAmount", "uid", "lineItems", + "deliveryDate", "dueAmount") + .isEqualTo(previewWithData.preview().getCurrentProformaInvoice()); + } + + @Test + void shouldReturn422WhenCreatingProformaInvoiceWithInvalidData() { + // when - then + CommonAssertions + .assertThatErrorArrayMapResponse(() -> PROFORMA_INVOICES_CONTROLLER.previewSignupProformaInvoice( + null, + new CreateSubscriptionRequest(new CreateSubscription.Builder() + .productId(11) + .build() + ) + ) + ) + .isUnprocessableEntity() + .hasErrorMap(Map.of("base", List.of("Couldn't find Product by 11"))); + } + + @Test + void shouldReturn401WhenProvidingInvalidCredentials() { + // when - then + CommonAssertions.assertUnauthorized(() -> TestClient.createInvalidCredentialsClient().getProformaInvoicesController() + .previewSignupProformaInvoice(null, null) + ); + } + + private SignupProformaPreviewWithComponents previewSignupProformaInvoice(Customer customer) throws IOException, ApiException { + Component meteredComponent = TEST_SETUP.createMeteredComponent(productFamily, 11.5); + Component quantityBasedComponent = TEST_SETUP.createQuantityBasedComponent(productFamily.getId()); + + SignupProformaPreview signupProformaPreview = CLIENT.getProformaInvoicesController().previewSignupProformaInvoice( + CreateSignupProformaPreviewInclude.NEXT_PROFORMA_INVOICE, + new CreateSubscriptionRequest( + getCreateSubscription(customer, meteredComponent, quantityBasedComponent) + ) + ).getProformaInvoicePreview(); + + return new SignupProformaPreviewWithComponents(signupProformaPreview, quantityBasedComponent, meteredComponent); + } + +} diff --git a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerPreviewTest.java b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerPreviewTest.java index b8b1db3e..6fa577fa 100644 --- a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerPreviewTest.java +++ b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerPreviewTest.java @@ -1,11 +1,10 @@ package com.maxio.advancedbilling.controllers.proformainvoices; -import com.maxio.advancedbilling.AdvancedBillingClient; import com.maxio.advancedbilling.TestClient; -import com.maxio.advancedbilling.controllers.ProformaInvoicesController; import com.maxio.advancedbilling.exceptions.ApiException; +import com.maxio.advancedbilling.models.Component; import com.maxio.advancedbilling.models.Customer; -import com.maxio.advancedbilling.utils.TestSetup; +import com.maxio.advancedbilling.models.Subscription; import com.maxio.advancedbilling.utils.TestTeardown; import com.maxio.advancedbilling.utils.assertions.CommonAssertions; import org.junit.jupiter.api.AfterAll; @@ -14,12 +13,7 @@ import java.io.IOException; -public class ProformaInvoicesControllerPreviewTest { - - private static final TestSetup TEST_SETUP = new TestSetup(); - private static final AdvancedBillingClient CLIENT = TestClient.createClient(); - private static final ProformaInvoicesController PROFORMA_INVOICES_CONTROLLER = CLIENT - .getProformaInvoicesController(); +public class ProformaInvoicesControllerPreviewTest extends ProformaInvoicesTestBase { private static Customer customer; @@ -35,13 +29,11 @@ static void teardown() throws IOException, ApiException { @Test void shouldPreviewProformaInvoice() throws IOException, ApiException { - // given-when - ProformaInvoicesCreator proformaInvoicesCreator = new ProformaInvoicesCreator(); - ProformaInvoicesCreator.ProformaInvoiceWithComponents invoiceWithData = - proformaInvoicesCreator.previewProformaInvoiceWithComponents(customer); + // given - when + ProformaInvoiceWithComponents invoiceWithData = previewProformaInvoiceWithComponents(customer); // then - proformaInvoicesCreator.assertProformaInvoice(customer, invoiceWithData, false); + assertProformaInvoice(customer, invoiceWithData, false, false); } @Test @@ -60,4 +52,15 @@ void shouldReturn401WhenProvidingInvalidCredentials() { ); } + private ProformaInvoiceWithComponents previewProformaInvoiceWithComponents(Customer customer) throws IOException, ApiException { + Component meteredComponent = TEST_SETUP.createMeteredComponent(productFamily, 11.5); + Component quantityBasedComponent = TEST_SETUP.createQuantityBasedComponent(productFamily.getId()); + Subscription subscription = setupSubscription(customer, quantityBasedComponent, meteredComponent); + + return new ProformaInvoiceWithComponents( + CLIENT.getProformaInvoicesController().previewProformaInvoice(subscription.getId()), + quantityBasedComponent, meteredComponent + ); + } + } diff --git a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerReadTest.java b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerReadTest.java index 9ec87827..3d2805fa 100644 --- a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerReadTest.java +++ b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerReadTest.java @@ -1,12 +1,10 @@ package com.maxio.advancedbilling.controllers.proformainvoices; -import com.maxio.advancedbilling.AdvancedBillingClient; import com.maxio.advancedbilling.TestClient; import com.maxio.advancedbilling.controllers.ProformaInvoicesController; import com.maxio.advancedbilling.exceptions.ApiException; import com.maxio.advancedbilling.models.Customer; import com.maxio.advancedbilling.models.ProformaInvoice; -import com.maxio.advancedbilling.utils.TestSetup; import com.maxio.advancedbilling.utils.TestTeardown; import com.maxio.advancedbilling.utils.assertions.CommonAssertions; import org.junit.jupiter.api.AfterAll; @@ -17,12 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat; -public class ProformaInvoicesControllerReadTest { - - private static final TestSetup TEST_SETUP = new TestSetup(); - private static final AdvancedBillingClient CLIENT = TestClient.createClient(); - private static final ProformaInvoicesController PROFORMA_INVOICES_CONTROLLER = CLIENT - .getProformaInvoicesController(); +public class ProformaInvoicesControllerReadTest extends ProformaInvoicesTestBase { private static Customer customer; @@ -39,8 +32,7 @@ static void teardown() throws IOException, ApiException { @Test void shouldReadProformaInvoice() throws IOException, ApiException { // given - ProformaInvoice createdProformaInvoice = new ProformaInvoicesCreator() - .createProformaInvoiceWithComponents(customer).invoice(); + ProformaInvoice createdProformaInvoice = createProformaInvoiceWithComponents(customer).invoice(); // when ProformaInvoice proformaInvoice = PROFORMA_INVOICES_CONTROLLER.readProformaInvoice(createdProformaInvoice.getUid()); diff --git a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerSubscriptionGroupsTest.java b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerSubscriptionGroupsTest.java new file mode 100644 index 00000000..8f0106df --- /dev/null +++ b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerSubscriptionGroupsTest.java @@ -0,0 +1,209 @@ +package com.maxio.advancedbilling.controllers.proformainvoices; + +import com.maxio.advancedbilling.AdvancedBillingClient; +import com.maxio.advancedbilling.TestClient; +import com.maxio.advancedbilling.controllers.ProformaInvoicesController; +import com.maxio.advancedbilling.exceptions.ApiException; +import com.maxio.advancedbilling.models.CollectionMethod; +import com.maxio.advancedbilling.models.Component; +import com.maxio.advancedbilling.models.InvoiceAddress; +import com.maxio.advancedbilling.models.InvoiceConsolidationLevel; +import com.maxio.advancedbilling.models.InvoiceCustomer; +import com.maxio.advancedbilling.models.InvoiceLineItem; +import com.maxio.advancedbilling.models.InvoiceSeller; +import com.maxio.advancedbilling.models.ListProformaInvoicesResponse; +import com.maxio.advancedbilling.models.ListSubscriptionGroupProformaInvoicesInput; +import com.maxio.advancedbilling.models.Product; +import com.maxio.advancedbilling.models.ProductFamily; +import com.maxio.advancedbilling.models.ProformaInvoice; +import com.maxio.advancedbilling.models.ProformaInvoiceRole; +import com.maxio.advancedbilling.models.SubscriptionGroupSignupResponse; +import com.maxio.advancedbilling.utils.TestSetup; +import com.maxio.advancedbilling.utils.TestTeardown; +import com.maxio.advancedbilling.utils.assertions.CommonAssertions; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.time.LocalDate; + +import static com.maxio.advancedbilling.controllers.proformainvoices.ProformaInvoicesTestBase.formatDescriptionDate; +import static com.maxio.advancedbilling.models.ProformaInvoiceStatus.DRAFT; +import static com.maxio.advancedbilling.utils.TestFixtures.INVOICE_SELLER; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +/** + * This class tests both `Create Consolidated Proforma Invoices` and `List Subscription Group Proforma Invoices` + * operations, as the Creation response is asynchronous and has no specific response, but it's needed to execute listing. + */ +public class ProformaInvoicesControllerSubscriptionGroupsTest { + + private static final TestSetup TEST_SETUP = new TestSetup(); + private static final AdvancedBillingClient CLIENT = TestClient.createClient(); + private static final ProformaInvoicesController PROFORMA_INVOICES_CONTROLLER = CLIENT + .getProformaInvoicesController(); + + private static SubscriptionGroupSignupResponse groupSignup; + private static ProductFamily productFamily; + private static Product product; + + @BeforeAll + static void setUp() throws IOException, ApiException, InterruptedException { + productFamily = TEST_SETUP.createProductFamily(); + product = TEST_SETUP.createProduct(productFamily, b -> b.priceInCents(1250)); + Component meteredComponent = TEST_SETUP.createMeteredComponent(productFamily, 11.5); + + groupSignup = TEST_SETUP.signupWithSubscriptionGroup(product, meteredComponent); + PROFORMA_INVOICES_CONTROLLER.createConsolidatedProformaInvoice(groupSignup.getUid()); + + Thread.sleep(5000); + } + + @AfterAll + static void teardown() throws IOException, ApiException { + new TestTeardown().deleteSubscriptionGroup(groupSignup); + } + + @Test + void shouldListSubscriptionGroupProformaInvoices() throws IOException, ApiException { + // given - when + ListProformaInvoicesResponse listProformaInvoicesResponse = PROFORMA_INVOICES_CONTROLLER + .listSubscriptionGroupProformaInvoices(new ListSubscriptionGroupProformaInvoicesInput.Builder() + .uid(groupSignup.getUid()) + .lineItems(true) + .build() + ); + + // then + assertThat(listProformaInvoicesResponse.getMeta()).isNotNull(); + assertThat(listProformaInvoicesResponse.getMeta().getCurrentPage()).isEqualTo(1); + assertThat(listProformaInvoicesResponse.getMeta().getStatusCode()).isEqualTo(200); + assertThat(listProformaInvoicesResponse.getMeta().getTotalCount()).isEqualTo(1); + assertThat(listProformaInvoicesResponse.getMeta().getTotalPages()).isEqualTo(1); + + assertThat(listProformaInvoicesResponse.getProformaInvoices().size()).isEqualTo(1); + + ProformaInvoice proformaInvoice = listProformaInvoicesResponse.getProformaInvoices().get(0); + + InvoiceAddress invoiceBillingAddress = proformaInvoice.getBillingAddress(); + assertThat(invoiceBillingAddress.getAdditionalProperties()).isEmpty(); + assertAll( + () -> assertThat(invoiceBillingAddress).isNotNull(), + () -> assertThat(invoiceBillingAddress.getStreet()).isEqualTo("1703 Edsel Road"), + () -> assertThat(invoiceBillingAddress.getLine2()).isNull(), + () -> assertThat(invoiceBillingAddress.getCity()).isEqualTo("Los Angeles"), + () -> assertThat(invoiceBillingAddress.getState()).isEqualTo("CA"), + () -> assertThat(invoiceBillingAddress.getZip()).isNull(), + () -> assertThat(invoiceBillingAddress.getCountry()).isNull() + ); + + InvoiceAddress invoiceShippingAddress = proformaInvoice.getShippingAddress(); + assertThat(invoiceShippingAddress.getAdditionalProperties()).isEmpty(); + assertAll( + () -> assertThat(invoiceShippingAddress).isNotNull(), + () -> assertThat(invoiceShippingAddress.getStreet()).isEqualTo("Broadway"), + () -> assertThat(invoiceShippingAddress.getLine2()).isNull(), + () -> assertThat(invoiceShippingAddress.getCity()).isEqualTo("NY"), + () -> assertThat(invoiceShippingAddress.getState()).isNull(), + () -> assertThat(invoiceShippingAddress.getZip()).isNull(), + () -> assertThat(invoiceShippingAddress.getCountry()).isNull() + ); + + assertThat(proformaInvoice.getCollectionMethod()).isEqualTo(CollectionMethod.AUTOMATIC); + assertThat(proformaInvoice.getConsolidationLevel()).isEqualTo(InvoiceConsolidationLevel.PARENT); + assertThat(proformaInvoice.getConsolidationLevel()).isEqualTo(InvoiceConsolidationLevel.PARENT); + assertThat(proformaInvoice.getCreatedAt()).isNotNull(); + assertThat(proformaInvoice.getCredits()).isNull(); + assertThat(proformaInvoice.getCurrency()).isEqualTo("USD"); + assertThat(proformaInvoice.getCustomFields()).isNull(); + + InvoiceCustomer invoiceCustomer = proformaInvoice.getCustomer(); + assertThat(invoiceCustomer.getAdditionalProperties()).isEmpty(); + assertAll( + () -> assertThat(invoiceCustomer).isNotNull(), + () -> assertThat(invoiceCustomer.getChargifyId()).isNotNull(), + () -> assertThat(invoiceCustomer.getFirstName()).isEqualTo("Payer"), + () -> assertThat(invoiceCustomer.getLastName()).isEqualTo("Doe"), + () -> assertThat(invoiceCustomer.getOrganization()).isNull(), + () -> assertThat(invoiceCustomer.getEmail()).isEqualTo("payerdoe@chargify.com"), + () -> assertThat(invoiceCustomer.getVatNumber()).isNull(), + () -> assertThat(invoiceCustomer.getReference()).isNull() + ); + assertThat(proformaInvoice.getCustomerId()).isEqualTo(groupSignup.getCustomerId()); + + assertThat(proformaInvoice.getDeliveryDate()).isEqualTo(LocalDate.now().plusMonths(1)); + assertThat(proformaInvoice.getMemo()).isEqualTo("Thanks for your business! If you have any questions, please contact your account manager."); + assertThat(proformaInvoice.getNumber()).isNotNull(); + assertThat(proformaInvoice.getPaymentInstructions()).isEqualTo("Please make checks payable to \"Acme, Inc.\""); + assertThat(proformaInvoice.getProductFamilyName()).isEqualTo(productFamily.getName()); + assertThat(proformaInvoice.getProductName()).isEqualTo(product.getName()); + assertThat(proformaInvoice.getPublicUrl()).isNotNull().isNotBlank(); + assertThat(proformaInvoice.getRole()).isEqualTo(ProformaInvoiceRole.PROFORMA_ADHOC); + InvoiceSeller invoiceSeller = proformaInvoice.getSeller(); + assertThat(invoiceSeller.getAdditionalProperties()).isEmpty(); + assertThat(invoiceSeller) + .usingRecursiveComparison() + .isEqualTo(INVOICE_SELLER); + assertThat(proformaInvoice.getSequenceNumber()).isNotNull(); + assertThat(proformaInvoice.getSiteId()).isNotNull(); + assertThat(proformaInvoice.getStatus()).isEqualTo(DRAFT); + assertThat(proformaInvoice.getSubscriptionId()).isEqualTo(groupSignup.getPrimarySubscriptionId()); + assertThat(proformaInvoice.getUid()).isNotNull(); + + assertThat(proformaInvoice.getCreditAmount()).isEqualTo("0.0"); + assertThat(proformaInvoice.getDiscountAmount()).isEqualTo("0.0"); + assertThat(proformaInvoice.getDueAmount()).isEqualTo("25.0"); + assertThat(proformaInvoice.getPaidAmount()).isEqualTo("0.0"); + assertThat(proformaInvoice.getRefundAmount()).isEqualTo("0.0"); + assertThat(proformaInvoice.getTaxAmount()).isEqualTo("0.0"); + assertThat(proformaInvoice.getSubtotalAmount()).isEqualTo("25.0"); + assertThat(proformaInvoice.getTotalAmount()).isEqualTo("25.0"); + + assertThat(proformaInvoice.getLineItems()) + .hasSize(2) + .usingRecursiveFieldByFieldElementComparatorIgnoringFields("uid", "additionalProperties") + .containsOnly( + new InvoiceLineItem.Builder() + .title(product.getName()) + .description("%s - %s".formatted(formatDescriptionDate(LocalDate.now().plusMonths(1)), + formatDescriptionDate(LocalDate.now().plusMonths(1).plusMonths(1)))) + .quantity("1.0") + .unitPrice("12.5") + .subtotalAmount("12.5") + .discountAmount("0.0") + .taxAmount("0.0") + .totalAmount("12.5") + .kind("baseline") + .tieredUnitPrice(false) + .periodRangeStart(LocalDate.now().plusMonths(1)) + .periodRangeEnd(LocalDate.now().plusMonths(1).plusMonths(1)) + .productId(product.getId()) + .productVersion(null) + .componentId(null) + .pricePointId(null) + .productPricePointId(product.getDefaultProductPricePointId()) + .customItem(false) + .build() + ); + } + + @Test + void shouldReturn404WhenCreatingConsolidatedProformaInvoiceForNonExistentGroup() { + // when - then + CommonAssertions.assertNotFound( + () -> PROFORMA_INVOICES_CONTROLLER.createConsolidatedProformaInvoice("123") + ); + } + + @Test + void shouldReturn401WhenProvidingInvalidCredentials() { + // when - then + CommonAssertions.assertUnauthorized(() -> TestClient.createInvalidCredentialsClient() + .getProformaInvoicesController() + .createConsolidatedProformaInvoice("123") + ); + } + +} diff --git a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerVoidTest.java b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerVoidTest.java index 45a0552b..6936eb98 100644 --- a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerVoidTest.java +++ b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesControllerVoidTest.java @@ -1,15 +1,13 @@ package com.maxio.advancedbilling.controllers.proformainvoices; -import com.maxio.advancedbilling.AdvancedBillingClient; import com.maxio.advancedbilling.TestClient; -import com.maxio.advancedbilling.controllers.ProformaInvoicesController; import com.maxio.advancedbilling.exceptions.ApiException; import com.maxio.advancedbilling.models.Customer; import com.maxio.advancedbilling.models.ProformaInvoice; import com.maxio.advancedbilling.models.ProformaInvoiceStatus; +import com.maxio.advancedbilling.models.Subscription; import com.maxio.advancedbilling.models.VoidInvoice; import com.maxio.advancedbilling.models.VoidInvoiceRequest; -import com.maxio.advancedbilling.utils.TestSetup; import com.maxio.advancedbilling.utils.TestTeardown; import com.maxio.advancedbilling.utils.assertions.CommonAssertions; import org.junit.jupiter.api.AfterAll; @@ -20,20 +18,13 @@ import static org.assertj.core.api.Assertions.assertThat; -public class ProformaInvoicesControllerVoidTest { - - private static final TestSetup TEST_SETUP = new TestSetup(); - private static final AdvancedBillingClient CLIENT = TestClient.createClient(); - private static final ProformaInvoicesController PROFORMA_INVOICES_CONTROLLER = CLIENT - .getProformaInvoicesController(); - private static ProformaInvoicesCreator proformaInvoicesCreator; +public class ProformaInvoicesControllerVoidTest extends ProformaInvoicesTestBase { private static Customer customer; @BeforeAll static void setUp() throws IOException, ApiException { customer = TEST_SETUP.createCustomer(); - proformaInvoicesCreator = new ProformaInvoicesCreator(); } @AfterAll @@ -44,7 +35,7 @@ static void teardown() throws IOException, ApiException { @Test public void shouldVoidProformaInvoice() throws IOException, ApiException { // given - ProformaInvoice proformaInvoice = proformaInvoicesCreator.createBasicProformaInvoice(customer); + ProformaInvoice proformaInvoice = createBasicProformaInvoice(customer); // when ProformaInvoice voidedInvoice = PROFORMA_INVOICES_CONTROLLER @@ -61,7 +52,7 @@ public void shouldVoidProformaInvoice() throws IOException, ApiException { @Test void shouldReturn422WhenVoidingVoidedInvoice() throws IOException, ApiException { // given - ProformaInvoice proformaInvoice = proformaInvoicesCreator.createBasicProformaInvoice(customer); + ProformaInvoice proformaInvoice = createBasicProformaInvoice(customer); PROFORMA_INVOICES_CONTROLLER .voidProformaInvoice(proformaInvoice.getUid(), new VoidInvoiceRequest( new VoidInvoice("Duplicate invoice") @@ -78,7 +69,7 @@ void shouldReturn422WhenVoidingVoidedInvoice() throws IOException, ApiException @Test void shouldReturn422WhenVoidingInvoiceWithoutReason() throws IOException, ApiException { // given - ProformaInvoice proformaInvoice = proformaInvoicesCreator.createBasicProformaInvoice(customer); + ProformaInvoice proformaInvoice = createBasicProformaInvoice(customer); // when - then CommonAssertions @@ -105,4 +96,9 @@ void shouldReturn401WhenProvidingInvalidCredentials() { ); } + private ProformaInvoice createBasicProformaInvoice(Customer customer) throws IOException, ApiException { + Subscription subscription = TEST_SETUP.createSubscription(customer, product); + return CLIENT.getProformaInvoicesController().createProformaInvoice(subscription.getId()); + } + } diff --git a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesCreator.java b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesCreator.java deleted file mode 100644 index a9e6c33c..00000000 --- a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesCreator.java +++ /dev/null @@ -1,319 +0,0 @@ -package com.maxio.advancedbilling.controllers.proformainvoices; - -import com.maxio.advancedbilling.AdvancedBillingClient; -import com.maxio.advancedbilling.TestClient; -import com.maxio.advancedbilling.exceptions.ApiException; -import com.maxio.advancedbilling.models.AllocateComponents; -import com.maxio.advancedbilling.models.CollectionMethod; -import com.maxio.advancedbilling.models.Component; -import com.maxio.advancedbilling.models.CreateAllocation; -import com.maxio.advancedbilling.models.CreateUsage; -import com.maxio.advancedbilling.models.CreateUsageRequest; -import com.maxio.advancedbilling.models.Customer; -import com.maxio.advancedbilling.models.InvoiceAddress; -import com.maxio.advancedbilling.models.InvoiceConsolidationLevel; -import com.maxio.advancedbilling.models.InvoiceCustomer; -import com.maxio.advancedbilling.models.InvoiceLineItem; -import com.maxio.advancedbilling.models.InvoiceSeller; -import com.maxio.advancedbilling.models.IssueServiceCredit; -import com.maxio.advancedbilling.models.IssueServiceCreditRequest; -import com.maxio.advancedbilling.models.Product; -import com.maxio.advancedbilling.models.ProductFamily; -import com.maxio.advancedbilling.models.ProformaInvoice; -import com.maxio.advancedbilling.models.ProformaInvoiceCredit; -import com.maxio.advancedbilling.models.ProformaInvoiceRole; -import com.maxio.advancedbilling.models.ProformaInvoiceStatus; -import com.maxio.advancedbilling.models.Subscription; -import com.maxio.advancedbilling.models.containers.CreateUsageComponentId; -import com.maxio.advancedbilling.models.containers.IssueServiceCreditAmount; -import com.maxio.advancedbilling.utils.TestSetup; -import io.apimatic.core.types.BaseModel; - -import java.io.IOException; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.Collections; -import java.util.List; - -import static com.maxio.advancedbilling.utils.TestFixtures.INVOICE_SELLER; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; - -class ProformaInvoicesCreator { - - private static final TestSetup TEST_SETUP = new TestSetup(); - private static final AdvancedBillingClient CLIENT = TestClient.createClient(); - - private final Product product; - private final ProductFamily productFamily; - - ProformaInvoicesCreator() throws IOException, ApiException { - productFamily = TEST_SETUP.createProductFamily(); - product = TEST_SETUP.createProduct(productFamily, b -> b.priceInCents(1250)); - } - - ProformaInvoice createBasicProformaInvoice(Customer customer) throws IOException, ApiException { - Subscription subscription = TEST_SETUP.createSubscription(customer, product); - return CLIENT.getProformaInvoicesController().createProformaInvoice(subscription.getId()); - } - - ProformaInvoiceWithComponents createProformaInvoiceWithComponents(Customer customer) throws IOException, ApiException { - Component meteredComponent = TEST_SETUP.createMeteredComponent(productFamily, 11.5); - Component quantityBasedComponent = TEST_SETUP.createQuantityBasedComponent(productFamily.getId()); - Subscription subscription = setupSubscription(customer, quantityBasedComponent, meteredComponent); - - return new ProformaInvoiceWithComponents( - CLIENT.getProformaInvoicesController().createProformaInvoice(subscription.getId()), - quantityBasedComponent, meteredComponent - ); - } - - ProformaInvoiceWithComponents previewProformaInvoiceWithComponents(Customer customer) throws IOException, ApiException { - Component meteredComponent = TEST_SETUP.createMeteredComponent(productFamily, 11.5); - Component quantityBasedComponent = TEST_SETUP.createQuantityBasedComponent(productFamily.getId()); - Subscription subscription = setupSubscription(customer, quantityBasedComponent, meteredComponent); - - return new ProformaInvoiceWithComponents( - CLIENT.getProformaInvoicesController().previewProformaInvoice(subscription.getId()), - quantityBasedComponent, meteredComponent - ); - } - - private Subscription setupSubscription(Customer customer, Component quantityBasedComponent, - Component meteredComponent) throws IOException, ApiException { - Subscription subscription = TEST_SETUP.createSubscription(customer, product); - CLIENT.getSubscriptionInvoiceAccountController().issueServiceCredit(subscription.getId(), - new IssueServiceCreditRequest( - new IssueServiceCredit(IssueServiceCreditAmount.fromString("5"), "credit") - )); - CLIENT.getSubscriptionComponentsController().allocateComponents(subscription.getId(), - new AllocateComponents.Builder() - .allocations( - List.of( - new CreateAllocation.Builder() - .componentId(quantityBasedComponent.getId()) - .quantity(20) - .build() - ) - ) - .build()); - CLIENT.getSubscriptionComponentsController().createUsage(subscription.getId(), - CreateUsageComponentId.fromNumber(meteredComponent.getId()), - new CreateUsageRequest(new CreateUsage.Builder() - .quantity(20.0) - .build())); - return subscription; - } - - void assertProformaInvoice(Customer customer, - ProformaInvoiceWithComponents invoiceWithData, - boolean assertPreservationDataNonEmpty) { - ProformaInvoice proformaInvoice = invoiceWithData.invoice(); - assertThat(proformaInvoice.getAdditionalProperties()).isEmpty(); - - Component quantityBasedComponent = invoiceWithData.quantityBasedComponent(); - assertThat(quantityBasedComponent.getAdditionalProperties()).isEmpty(); - - Component meteredComponent = invoiceWithData.meteredComponent(); - assertThat(meteredComponent.getAdditionalProperties()).isEmpty(); - - if (assertPreservationDataNonEmpty) { - assertThat(proformaInvoice.getNumber()).isNotNull(); - assertThat(proformaInvoice.getSequenceNumber()).isNotNull(); - assertThat(proformaInvoice.getPublicUrl()).isNotNull().isNotBlank(); - } else { - assertThat(proformaInvoice.getNumber()).isNull(); - assertThat(proformaInvoice.getSequenceNumber()).isNull(); - assertThat(proformaInvoice.getPublicUrl()).isNull(); - } - assertThat(proformaInvoice.getUid()).isNotNull().isNotBlank(); - - InvoiceAddress invoiceBillingAddress = proformaInvoice.getBillingAddress(); - assertThat(invoiceBillingAddress.getAdditionalProperties()).isEmpty(); - assertAll( - () -> assertThat(invoiceBillingAddress).isNotNull(), - () -> assertThat(invoiceBillingAddress.getStreet()).isEqualTo("My Billing Address"), - () -> assertThat(invoiceBillingAddress.getLine2()).isNull(), - () -> assertThat(invoiceBillingAddress.getCity()).isEqualTo("New York"), - () -> assertThat(invoiceBillingAddress.getState()).isEqualTo("NY"), - () -> assertThat(invoiceBillingAddress.getZip()).isEqualTo("10001"), - () -> assertThat(invoiceBillingAddress.getCountry()).isEqualTo("USA") - ); - - InvoiceAddress invoiceShippingAddress = proformaInvoice.getShippingAddress(); - assertThat(invoiceShippingAddress.getAdditionalProperties()).isEmpty(); - assertAll( - () -> assertThat(invoiceShippingAddress).isNotNull(), - () -> assertThat(invoiceShippingAddress.getStreet()).isEqualTo(customer.getAddress()), - () -> assertThat(invoiceShippingAddress.getLine2()).isEqualTo(customer.getAddress2()), - () -> assertThat(invoiceShippingAddress.getCity()).isEqualTo(customer.getCity()), - () -> assertThat(invoiceShippingAddress.getState()).isEqualTo(customer.getState()), - () -> assertThat(invoiceShippingAddress.getZip()).isEqualTo(customer.getZip()), - () -> assertThat(invoiceShippingAddress.getCountry()).isEqualTo(customer.getCountry()) - ); - - assertThat(proformaInvoice.getCollectionMethod()).isEqualTo(CollectionMethod.AUTOMATIC); - assertThat(proformaInvoice.getConsolidationLevel()).isEqualTo(InvoiceConsolidationLevel.NONE); - assertThat(proformaInvoice.getCreatedAt()).isNotNull(); - assertThat(proformaInvoice.getCreditAmount()).isNotNull(); - - assertThat(proformaInvoice.getCredits()).hasSize(1); - ProformaInvoiceCredit credit = proformaInvoice.getCredits().get(0); - assertThat(credit.getAppliedAmount()).isEqualTo("5.0"); - assertThat(credit.getMemo()).isEqualTo("This credit amount is anticipated to apply when the invoice is generated"); - assertThat(credit.getOriginalAmount()).isEqualTo("5.0"); - - assertThat(proformaInvoice.getCurrency()).isEqualTo("USD"); - assertThat(proformaInvoice.getCustomFields()).isEmpty(); - - InvoiceCustomer invoiceCustomer = proformaInvoice.getCustomer(); - assertThat(invoiceCustomer.getAdditionalProperties()).isEmpty(); - assertAll( - () -> assertThat(invoiceCustomer).isNotNull(), - () -> assertThat(invoiceCustomer.getChargifyId()).isEqualTo(customer.getId()), - () -> assertThat(invoiceCustomer.getFirstName()).isEqualTo(customer.getFirstName()), - () -> assertThat(invoiceCustomer.getLastName()).isEqualTo(customer.getLastName()), - () -> assertThat(invoiceCustomer.getOrganization()).isEqualTo(customer.getOrganization()), - () -> assertThat(invoiceCustomer.getEmail()).isEqualTo(customer.getEmail()), - () -> assertThat(invoiceCustomer.getVatNumber()).isNull(), - () -> assertThat(invoiceCustomer.getReference()).isEqualTo(customer.getReference()) - ); - - assertThat(proformaInvoice.getCustomerId()).isEqualTo(customer.getId()); - assertThat(proformaInvoice.getDeliveryDate()).isAfterOrEqualTo(LocalDate.now()); - assertThat(proformaInvoice.getDiscountAmount()).isEqualTo("0.0"); - assertThat(proformaInvoice.getDiscounts()).isEmpty(); - assertThat(proformaInvoice.getDueAmount()).isEqualTo("277.5"); - assertThat(proformaInvoice.getMemo()).isEqualTo("Thanks for your business! If you have any questions, please contact your account manager."); - assertThat(proformaInvoice.getPaidAmount()).isEqualTo("0.0"); - assertThat(proformaInvoice.getPaymentInstructions()).isEqualTo("Please make checks payable to \"Acme, Inc.\""); - assertThat(proformaInvoice.getProductFamilyName()).isEqualTo(productFamily.getName()); - assertThat(proformaInvoice.getProductName()).isEqualTo(product.getName()); - assertThat(proformaInvoice.getRefundAmount()).isEqualTo("0.0"); - assertThat(proformaInvoice.getRole()).isEqualTo(ProformaInvoiceRole.PROFORMA_ADHOC); - - InvoiceSeller invoiceSeller = proformaInvoice.getSeller(); - assertThat(invoiceSeller.getAdditionalProperties()).isEmpty(); - assertThat(invoiceSeller) - .usingRecursiveComparison() - .isEqualTo(INVOICE_SELLER); - assertThat(proformaInvoice.getSiteId()).isNotNull(); - assertThat(proformaInvoice.getStatus()).isEqualTo(ProformaInvoiceStatus.DRAFT); - assertThat(proformaInvoice.getSubscriptionId()).isNotNull(); - assertThat(proformaInvoice.getSubtotalAmount()).isEqualTo("282.5"); - assertThat(proformaInvoice.getTaxAmount()).isEqualTo("0.0"); - assertThat(proformaInvoice.getTaxes()).isEmpty(); - assertThat(proformaInvoice.getTotalAmount()).isEqualTo("282.5"); - - List lineItems = proformaInvoice.getLineItems(); - assertThat(lineItems) - .hasSize(4) - .extracting(BaseModel::getAdditionalProperties) - .containsExactlyInAnyOrder( - Collections.singletonMap("billing_schedule_item_id", null), - Collections.singletonMap("billing_schedule_item_id", null), - Collections.singletonMap("billing_schedule_item_id", null), - Collections.singletonMap("billing_schedule_item_id", null) - ); - assertThat(lineItems) - .usingRecursiveFieldByFieldElementComparatorIgnoringFields("uid", "additionalProperties") - .containsExactlyInAnyOrder( - new InvoiceLineItem.Builder() - .title(product.getName()) - .description("%s - %s".formatted(formatDescriptionDate(LocalDate.now().plusMonths(1)), - formatDescriptionDate(LocalDate.now().plusMonths(1).plusMonths(1)))) - .quantity("1.0") - .unitPrice("12.5") - .subtotalAmount("12.5") - .discountAmount("0.0") - .taxAmount("0.0") - .totalAmount("12.5") - .kind("baseline") - .tieredUnitPrice(false) - .periodRangeStart(LocalDate.now().plusMonths(1)) - .periodRangeEnd(LocalDate.now().plusMonths(1).plusMonths(1)) - .productId(product.getId()) - .productVersion(null) - .componentId(null) - .pricePointId(null) - .productPricePointId(product.getDefaultProductPricePointId()) - .customItem(false) - .build(), - new InvoiceLineItem.Builder() - .title("%s: 0 to 20 units".formatted(quantityBasedComponent.getName())) - .description("Prorated: %s - %s (100.0%% of original period)" - .formatted(formatDescriptionDate(LocalDate.now()), - formatDescriptionDate(LocalDate.now().plusMonths(1)))) - .quantity("20.0") - .unitPrice("1.0") - .subtotalAmount("20.0") - .discountAmount("0.0") - .taxAmount("0.0") - .totalAmount("20.0") - .kind("quantity_based_component") - .tieredUnitPrice(false) - .periodRangeStart(LocalDate.now()) - .periodRangeEnd(LocalDate.now().plusMonths(1)) - .productId(product.getId()) - .componentId(quantityBasedComponent.getId()) - .productVersion(1) - .pricePointId(quantityBasedComponent.getDefaultPricePointId()) - .productPricePointId(product.getDefaultProductPricePointId()) - .customItem(false) - .build(), - new InvoiceLineItem.Builder() - .title(meteredComponent.getName()) - .description("%s - %s" - .formatted(formatDescriptionDate(LocalDate.now()), - formatDescriptionDate(LocalDate.now().plusMonths(1)))) - .quantity("20.0") - .unitPrice("11.5") - .subtotalAmount("230.0") - .discountAmount("0.0") - .taxAmount("0.0") - .totalAmount("230.0") - .kind("metered_component") - .tieredUnitPrice(false) - .periodRangeStart(LocalDate.now()) - .periodRangeEnd(LocalDate.now().plusMonths(1)) - .productId(product.getId()) - .componentId(meteredComponent.getId()) - .productVersion(null) - .pricePointId(meteredComponent.getDefaultPricePointId()) - .productPricePointId(product.getDefaultProductPricePointId()) - .customItem(false) - .build(), - new InvoiceLineItem.Builder() - .title(quantityBasedComponent.getName()) - .description("%s - %s" - .formatted(formatDescriptionDate(LocalDate.now().plusMonths(1)), - formatDescriptionDate(LocalDate.now().plusMonths(1).plusMonths(1)))) - .quantity("20.0") - .unitPrice("1.0") - .subtotalAmount("20.0") - .discountAmount("0.0") - .taxAmount("0.0") - .totalAmount("20.0") - .kind("quantity_based_component") - .tieredUnitPrice(false) - .periodRangeStart(LocalDate.now().plusMonths(1)) - .periodRangeEnd(LocalDate.now().plusMonths(1).plusMonths(1)) - .productId(product.getId()) - .componentId(quantityBasedComponent.getId()) - .productVersion(null) - .pricePointId(quantityBasedComponent.getDefaultPricePointId()) - .productPricePointId(product.getDefaultProductPricePointId()) - .customItem(false) - .build() - ); - } - - private String formatDescriptionDate(LocalDate localDate) { - return localDate - .format(DateTimeFormatter.ofPattern("MM/dd/yyyy")); - } - - record ProformaInvoiceWithComponents(ProformaInvoice invoice, Component quantityBasedComponent, - Component meteredComponent) { - } -} diff --git a/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesTestBase.java b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesTestBase.java new file mode 100644 index 00000000..3f65655f --- /dev/null +++ b/tests/src/test/java/com/maxio/advancedbilling/controllers/proformainvoices/ProformaInvoicesTestBase.java @@ -0,0 +1,380 @@ +package com.maxio.advancedbilling.controllers.proformainvoices; + +import com.maxio.advancedbilling.AdvancedBillingClient; +import com.maxio.advancedbilling.TestClient; +import com.maxio.advancedbilling.controllers.ProformaInvoicesController; +import com.maxio.advancedbilling.exceptions.ApiException; +import com.maxio.advancedbilling.models.AllocateComponents; +import com.maxio.advancedbilling.models.CardType; +import com.maxio.advancedbilling.models.CollectionMethod; +import com.maxio.advancedbilling.models.Component; +import com.maxio.advancedbilling.models.CreateAllocation; +import com.maxio.advancedbilling.models.CreateSubscription; +import com.maxio.advancedbilling.models.CreateSubscriptionComponent; +import com.maxio.advancedbilling.models.CreateUsage; +import com.maxio.advancedbilling.models.CreateUsageRequest; +import com.maxio.advancedbilling.models.Customer; +import com.maxio.advancedbilling.models.InvoiceAddress; +import com.maxio.advancedbilling.models.InvoiceConsolidationLevel; +import com.maxio.advancedbilling.models.InvoiceCustomer; +import com.maxio.advancedbilling.models.InvoiceLineItem; +import com.maxio.advancedbilling.models.InvoiceSeller; +import com.maxio.advancedbilling.models.IssueServiceCredit; +import com.maxio.advancedbilling.models.IssueServiceCreditRequest; +import com.maxio.advancedbilling.models.PaymentProfileAttributes; +import com.maxio.advancedbilling.models.Product; +import com.maxio.advancedbilling.models.ProductFamily; +import com.maxio.advancedbilling.models.ProformaInvoice; +import com.maxio.advancedbilling.models.ProformaInvoiceCredit; +import com.maxio.advancedbilling.models.ProformaInvoiceRole; +import com.maxio.advancedbilling.models.SignupProformaPreview; +import com.maxio.advancedbilling.models.Subscription; +import com.maxio.advancedbilling.models.containers.CreateSubscriptionComponentAllocatedQuantity; +import com.maxio.advancedbilling.models.containers.CreateSubscriptionComponentComponentId; +import com.maxio.advancedbilling.models.containers.CreateUsageComponentId; +import com.maxio.advancedbilling.models.containers.IssueServiceCreditAmount; +import com.maxio.advancedbilling.models.containers.PaymentProfileAttributesExpirationMonth; +import com.maxio.advancedbilling.models.containers.PaymentProfileAttributesExpirationYear; +import com.maxio.advancedbilling.utils.TestSetup; + +import java.io.IOException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +import static com.maxio.advancedbilling.models.ProformaInvoiceStatus.DRAFT; +import static com.maxio.advancedbilling.utils.TestFixtures.INVOICE_SELLER; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +abstract class ProformaInvoicesTestBase { + + protected static final TestSetup TEST_SETUP = new TestSetup(); + protected static final AdvancedBillingClient CLIENT = TestClient.createClient(); + protected static final ProformaInvoicesController PROFORMA_INVOICES_CONTROLLER = CLIENT + .getProformaInvoicesController(); + + protected final Product product; + protected final ProductFamily productFamily; + + ProformaInvoicesTestBase() { + try { + productFamily = TEST_SETUP.createProductFamily(); + product = TEST_SETUP.createProduct(productFamily, b -> b.priceInCents(1250)); + } catch (IOException | ApiException e) { + throw new RuntimeException(e); + } + } + + protected ProformaInvoiceWithComponents createProformaInvoiceWithComponents(Customer customer) throws IOException, ApiException { + Component meteredComponent = TEST_SETUP.createMeteredComponent(productFamily, 11.5); + Component quantityBasedComponent = TEST_SETUP.createQuantityBasedComponent(productFamily.getId()); + Subscription subscription = setupSubscription(customer, quantityBasedComponent, meteredComponent); + + return new ProformaInvoiceWithComponents( + CLIENT.getProformaInvoicesController().createProformaInvoice(subscription.getId()), + quantityBasedComponent, meteredComponent + ); + } + + protected CreateSubscription getCreateSubscription(Customer customer, Component meteredComponent, + Component quantityBasedComponent) { + return new CreateSubscription.Builder() + .productId(product.getId()) + .customerId(customer.getId()) + .components( + List.of( + new CreateSubscriptionComponent.Builder() + .unitBalance(20) + .componentId(CreateSubscriptionComponentComponentId + .fromNumber(meteredComponent.getId())) + .build(), + new CreateSubscriptionComponent.Builder() + .allocatedQuantity(CreateSubscriptionComponentAllocatedQuantity + .fromNumber(20)) + .componentId(CreateSubscriptionComponentComponentId + .fromNumber(quantityBasedComponent.getId())) + .build() + ) + ) + .creditCardAttributes( + new PaymentProfileAttributes.Builder() + .billingAddress("My Billing Address") + .billingCity("New York") + .billingCountry("USA") + .billingState("NY") + .billingZip("10001") + .customerId(customer.getId()) + .cardType(CardType.VISA) + .cvv("123") + .expirationMonth(PaymentProfileAttributesExpirationMonth.fromNumber(5)) + .expirationYear(PaymentProfileAttributesExpirationYear.fromNumber(2050)) + .build() + ) + .build(); + } + + + protected Subscription setupSubscription(Customer customer, Component quantityBasedComponent, + Component meteredComponent) throws IOException, ApiException { + Subscription subscription = TEST_SETUP.createSubscription(customer, product); + CLIENT.getSubscriptionInvoiceAccountController().issueServiceCredit(subscription.getId(), + new IssueServiceCreditRequest( + new IssueServiceCredit(IssueServiceCreditAmount.fromString("5"), "credit") + )); + CLIENT.getSubscriptionComponentsController().allocateComponents(subscription.getId(), + new AllocateComponents.Builder() + .allocations( + List.of( + new CreateAllocation.Builder() + .componentId(quantityBasedComponent.getId()) + .quantity(20) + .build() + ) + ) + .build()); + CLIENT.getSubscriptionComponentsController().createUsage(subscription.getId(), + CreateUsageComponentId.fromNumber(meteredComponent.getId()), + new CreateUsageRequest(new CreateUsage.Builder() + .quantity(20.0) + .build())); + return subscription; + } + + void assertProformaInvoice(Customer customer, + ProformaInvoiceWithComponents invoiceWithData, + boolean assertPreservationDataNonEmpty, + // signup proforma won't contain service credits and subscription id and its periods + // won't be shifted + boolean isSignup) { + ProformaInvoice proformaInvoice = invoiceWithData.invoice(); + assertThat(proformaInvoice.getAdditionalProperties()).isEmpty(); + + Component quantityBasedComponent = invoiceWithData.quantityBasedComponent(); + assertThat(quantityBasedComponent.getAdditionalProperties()).isEmpty(); + + Component meteredComponent = invoiceWithData.meteredComponent(); + assertThat(meteredComponent.getAdditionalProperties()).isEmpty(); + + if (assertPreservationDataNonEmpty) { + assertThat(proformaInvoice.getNumber()).isNotNull(); + assertThat(proformaInvoice.getSequenceNumber()).isNotNull(); + assertThat(proformaInvoice.getPublicUrl()).isNotNull().isNotBlank(); + } else { + assertThat(proformaInvoice.getNumber()).isNull(); + assertThat(proformaInvoice.getSequenceNumber()).isNull(); + assertThat(proformaInvoice.getPublicUrl()).isNull(); + } + + if (!isSignup) { + assertThat(proformaInvoice.getCredits()).hasSize(1); + ProformaInvoiceCredit credit = proformaInvoice.getCredits().get(0); + assertThat(credit.getAppliedAmount()).isEqualTo("5.0"); + assertThat(credit.getMemo()).isEqualTo("This credit amount is anticipated to apply when the invoice is generated"); + assertThat(credit.getOriginalAmount()).isEqualTo("5.0"); + assertThat(proformaInvoice.getSubscriptionId()).isNotNull(); + } else { + assertThat(proformaInvoice.getCredits()).isEmpty(); + assertThat(proformaInvoice.getSubscriptionId()).isNull(); + } + + assertThat(proformaInvoice.getUid()).isNotNull().isNotBlank(); + + InvoiceAddress invoiceBillingAddress = proformaInvoice.getBillingAddress(); + assertThat(invoiceBillingAddress.getAdditionalProperties()).isEmpty(); + assertAll( + () -> assertThat(invoiceBillingAddress).isNotNull(), + () -> assertThat(invoiceBillingAddress.getStreet()).isEqualTo("My Billing Address"), + () -> assertThat(invoiceBillingAddress.getLine2()).isNull(), + () -> assertThat(invoiceBillingAddress.getCity()).isEqualTo("New York"), + () -> assertThat(invoiceBillingAddress.getState()).isEqualTo("NY"), + () -> assertThat(invoiceBillingAddress.getZip()).isEqualTo("10001"), + () -> assertThat(invoiceBillingAddress.getCountry()).isEqualTo("USA") + ); + + InvoiceAddress invoiceShippingAddress = proformaInvoice.getShippingAddress(); + assertThat(invoiceShippingAddress.getAdditionalProperties()).isEmpty(); + assertAll( + () -> assertThat(invoiceShippingAddress).isNotNull(), + () -> assertThat(invoiceShippingAddress.getStreet()).isEqualTo(customer.getAddress()), + () -> assertThat(invoiceShippingAddress.getLine2()).isEqualTo(customer.getAddress2()), + () -> assertThat(invoiceShippingAddress.getCity()).isEqualTo(customer.getCity()), + () -> assertThat(invoiceShippingAddress.getState()).isEqualTo(customer.getState()), + () -> assertThat(invoiceShippingAddress.getZip()).isEqualTo(customer.getZip()), + () -> assertThat(invoiceShippingAddress.getCountry()).isEqualTo(customer.getCountry()) + ); + + assertThat(proformaInvoice.getCollectionMethod()).isEqualTo(CollectionMethod.AUTOMATIC); + assertThat(proformaInvoice.getConsolidationLevel()).isEqualTo(InvoiceConsolidationLevel.NONE); + assertThat(proformaInvoice.getCreatedAt()).isNotNull(); + assertThat(proformaInvoice.getCreditAmount()).isNotNull(); + + assertThat(proformaInvoice.getCurrency()).isEqualTo("USD"); + assertThat(proformaInvoice.getCustomFields()).isEmpty(); + + InvoiceCustomer invoiceCustomer = proformaInvoice.getCustomer(); + assertThat(invoiceCustomer.getAdditionalProperties()).isEmpty(); + assertAll( + () -> assertThat(invoiceCustomer).isNotNull(), + () -> assertThat(invoiceCustomer.getChargifyId()).isEqualTo(customer.getId()), + () -> assertThat(invoiceCustomer.getFirstName()).isEqualTo(customer.getFirstName()), + () -> assertThat(invoiceCustomer.getLastName()).isEqualTo(customer.getLastName()), + () -> assertThat(invoiceCustomer.getOrganization()).isEqualTo(customer.getOrganization()), + () -> assertThat(invoiceCustomer.getEmail()).isEqualTo(customer.getEmail()), + () -> assertThat(invoiceCustomer.getVatNumber()).isNull(), + () -> assertThat(invoiceCustomer.getReference()).isEqualTo(customer.getReference()) + ); + + assertThat(proformaInvoice.getCustomerId()).isEqualTo(customer.getId()); + assertThat(proformaInvoice.getDeliveryDate()).isAfterOrEqualTo(LocalDate.now()); + assertThat(proformaInvoice.getDiscountAmount()).isEqualTo("0.0"); + assertThat(proformaInvoice.getDiscounts()).isEmpty(); + assertThat(proformaInvoice.getDueAmount()).isEqualTo(isSignup ? "262.5" : "277.5"); + assertThat(proformaInvoice.getMemo()).isEqualTo("Thanks for your business! If you have any questions, please contact your account manager."); + assertThat(proformaInvoice.getPaidAmount()).isEqualTo("0.0"); + assertThat(proformaInvoice.getPaymentInstructions()).isEqualTo("Please make checks payable to \"Acme, Inc.\""); + assertThat(proformaInvoice.getProductFamilyName()).isEqualTo(productFamily.getName()); + assertThat(proformaInvoice.getProductName()).isEqualTo(product.getName()); + assertThat(proformaInvoice.getRefundAmount()).isEqualTo("0.0"); + assertThat(proformaInvoice.getRole()).isEqualTo(ProformaInvoiceRole.PROFORMA_ADHOC); + + InvoiceSeller invoiceSeller = proformaInvoice.getSeller(); + assertThat(invoiceSeller.getAdditionalProperties()).isEmpty(); + assertThat(invoiceSeller) + .usingRecursiveComparison() + .isEqualTo(INVOICE_SELLER); + assertThat(proformaInvoice.getSiteId()).isNotNull(); + assertThat(proformaInvoice.getStatus()).isEqualTo(DRAFT); + assertThat(proformaInvoice.getSubtotalAmount()).isEqualTo(isSignup ? "262.5" : "282.5"); + assertThat(proformaInvoice.getTaxAmount()).isEqualTo("0.0"); + assertThat(proformaInvoice.getTaxes()).isEmpty(); + assertThat(proformaInvoice.getTotalAmount()).isEqualTo(isSignup ? "262.5" : "282.5"); + + // line items + String lineItemDescription = "%s - %s".formatted( + isSignup ? formatDescriptionDate(LocalDate.now()) : + formatDescriptionDate(LocalDate.now().plusMonths(1)), + isSignup ? formatDescriptionDate(LocalDate.now().plusMonths(1)) : + formatDescriptionDate(LocalDate.now().plusMonths(1).plusMonths(1))); + + List expectedLineItems = new ArrayList<>(); + expectedLineItems.add( + new InvoiceLineItem.Builder() + .title(product.getName()) + .description(lineItemDescription) + .quantity("1.0") + .unitPrice("12.5") + .subtotalAmount("12.5") + .discountAmount("0.0") + .taxAmount("0.0") + .totalAmount("12.5") + .kind("baseline") + .tieredUnitPrice(false) + .periodRangeStart(isSignup ? LocalDate.now() : LocalDate.now().plusMonths(1)) + .periodRangeEnd(isSignup ? LocalDate.now().plusMonths(1) : + LocalDate.now().plusMonths(1).plusMonths(1)) + .productId(product.getId()) + .productVersion(null) + .componentId(null) + .pricePointId(null) + .productPricePointId(product.getDefaultProductPricePointId()) + .customItem(false) + .build()); + expectedLineItems.add( + new InvoiceLineItem.Builder() + .title(meteredComponent.getName()) + .description(isSignup ? formatDescriptionDate(LocalDate.now()) : "%s - %s" + .formatted(formatDescriptionDate(LocalDate.now()), + formatDescriptionDate(LocalDate.now().plusMonths(1)))) + .quantity("20.0") + .unitPrice("11.5") + .subtotalAmount("230.0") + .discountAmount("0.0") + .taxAmount("0.0") + .totalAmount("230.0") + .kind("metered_component") + .tieredUnitPrice(false) + .periodRangeStart(LocalDate.now()) + .periodRangeEnd(isSignup ? LocalDate.now() : + LocalDate.now().plusMonths(1)) + .productId(product.getId()) + .componentId(meteredComponent.getId()) + .productVersion(null) + .pricePointId(meteredComponent.getDefaultPricePointId()) + .productPricePointId(product.getDefaultProductPricePointId()) + .customItem(false) + .build()); + expectedLineItems.add( + new InvoiceLineItem.Builder() + .title(quantityBasedComponent.getName()) + .description(lineItemDescription) + .quantity("20.0") + .unitPrice("1.0") + .subtotalAmount("20.0") + .discountAmount("0.0") + .taxAmount("0.0") + .totalAmount("20.0") + .kind("quantity_based_component") + .tieredUnitPrice(false) + .periodRangeStart(isSignup ? LocalDate.now() : LocalDate.now().plusMonths(1)) + .periodRangeEnd(isSignup ? LocalDate.now().plusMonths(1) : + LocalDate.now().plusMonths(1).plusMonths(1)) + .productId(product.getId()) + .componentId(quantityBasedComponent.getId()) + .productVersion(null) + .pricePointId(quantityBasedComponent.getDefaultPricePointId()) + .productPricePointId(product.getDefaultProductPricePointId()) + .customItem(false) + .build() + ); + + if (!isSignup) { + expectedLineItems.add( + new InvoiceLineItem.Builder() + .title("%s: 0 to 20 units".formatted(quantityBasedComponent.getName())) + .description("Prorated: %s - %s (100.0%% of original period)" + .formatted(formatDescriptionDate(LocalDate.now()), + formatDescriptionDate(LocalDate.now().plusMonths(1)))) + .quantity("20.0") + .unitPrice("1.0") + .subtotalAmount("20.0") + .discountAmount("0.0") + .taxAmount("0.0") + .totalAmount("20.0") + .kind("quantity_based_component") + .tieredUnitPrice(false) + .periodRangeStart(LocalDate.now()) + .periodRangeEnd(LocalDate.now().plusMonths(1)) + .productId(product.getId()) + .componentId(quantityBasedComponent.getId()) + .productVersion(1) + .pricePointId(quantityBasedComponent.getDefaultPricePointId()) + .productPricePointId(product.getDefaultProductPricePointId()) + .customItem(false) + .build() + ); + } + + assertThat(proformaInvoice.getLineItems()) + .hasSize(expectedLineItems.size()) + .usingRecursiveFieldByFieldElementComparatorIgnoringFields("uid", "additionalProperties") + .containsExactlyInAnyOrder( + expectedLineItems.toArray(new InvoiceLineItem[0]) + ); + } + + static String formatDescriptionDate(LocalDate localDate) { + return localDate + .format(DateTimeFormatter.ofPattern("MM/dd/yyyy")); + } + + protected record ProformaInvoiceWithComponents(ProformaInvoice invoice, Component quantityBasedComponent, + Component meteredComponent) { + } + + protected record SignupProformaPreviewWithComponents(SignupProformaPreview preview, Component quantityBasedComponent, + Component meteredComponent) { + } + +} diff --git a/tests/src/test/java/com/maxio/advancedbilling/utils/TestSetup.java b/tests/src/test/java/com/maxio/advancedbilling/utils/TestSetup.java index 9266245a..aff09dbe 100644 --- a/tests/src/test/java/com/maxio/advancedbilling/utils/TestSetup.java +++ b/tests/src/test/java/com/maxio/advancedbilling/utils/TestSetup.java @@ -461,6 +461,9 @@ public SubscriptionGroupSignupResponse signupWithSubscriptionGroup(Product produ .fullNumber(SubscriptionGroupCreditCardFullNumber.fromString("4111 1111 1111 1111")) .expirationMonth(SubscriptionGroupCreditCardExpirationMonth.fromNumber(11)) .expirationYear(SubscriptionGroupCreditCardExpirationYear.fromNumber(LocalDate.now().getYear() + 1)) + .billingAddress("1703 Edsel Road") + .billingCity("Los Angeles") + .billingState("CA") .build()) .payerAttributes(new PayerAttributes.Builder() .firstName("Payer")