Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DE-117] DE-629 - Java test CRUD for Invoices endpoints part 1 (Issue Invoice) #76

Merged
merged 1 commit into from
Jan 15, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
package com.maxio.advancedbilling.controllers.invoices;

import com.maxio.advancedbilling.AdvancedBillingClient;
import com.maxio.advancedbilling.TestClient;
import com.maxio.advancedbilling.controllers.InvoicesController;
import com.maxio.advancedbilling.exceptions.ApiException;
import com.maxio.advancedbilling.models.Component;
import com.maxio.advancedbilling.models.CreateAllocation;
import com.maxio.advancedbilling.models.CreateAllocationRequest;
import com.maxio.advancedbilling.models.CreateInvoiceCoupon;
import com.maxio.advancedbilling.models.CreateInvoiceItem;
import com.maxio.advancedbilling.models.CreateInvoiceStatus;
import com.maxio.advancedbilling.models.Customer;
import com.maxio.advancedbilling.models.FailedPaymentAction;
import com.maxio.advancedbilling.models.Invoice;
import com.maxio.advancedbilling.models.InvoiceAddress;
import com.maxio.advancedbilling.models.InvoiceBalanceItem;
import com.maxio.advancedbilling.models.InvoiceConsolidationLevel;
import com.maxio.advancedbilling.models.InvoiceCustomer;
import com.maxio.advancedbilling.models.InvoiceLineItem;
import com.maxio.advancedbilling.models.InvoicePreviousBalance;
import com.maxio.advancedbilling.models.InvoiceSeller;
import com.maxio.advancedbilling.models.InvoiceStatus;
import com.maxio.advancedbilling.models.IssueInvoiceRequest;
import com.maxio.advancedbilling.models.ListInvoicesInput;
import com.maxio.advancedbilling.models.Product;
import com.maxio.advancedbilling.models.ProductFamily;
import com.maxio.advancedbilling.models.Subscription;
import com.maxio.advancedbilling.models.containers.CreateInvoiceCouponAmount;
import com.maxio.advancedbilling.models.containers.CreateInvoiceItemProductId;
import com.maxio.advancedbilling.models.containers.CreateInvoiceItemQuantity;
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 org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.io.IOException;
import java.time.LocalDate;
import java.util.List;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

class InvoicesControllerIssueTest {
private static final TestSetup TEST_SETUP = new TestSetup();
private static final AdvancedBillingClient CLIENT = TestClient.createClient();
private static final InvoicesController INVOICES_CONTROLLER = CLIENT.getInvoicesController();

private static Product product;
private static Component quantityBasedComponent;
private static Subscription subscription;
private static Customer customer;
private static Invoice openInvoice;
private static Invoice paidInvoice;

@BeforeAll
static void setUp() throws IOException, ApiException {
ProductFamily productFamily = TEST_SETUP.createProductFamily();
product = TEST_SETUP.createProduct(productFamily, b -> b.priceInCents(1250));
customer = TEST_SETUP.createCustomer();
quantityBasedComponent = TEST_SETUP.createQuantityBasedComponent(
productFamily.getId(),
b -> b.allowFractionalQuantities(true)
);
subscription = TEST_SETUP.createSubscription(customer, product);
paidInvoice = INVOICES_CONTROLLER
.listInvoices(new ListInvoicesInput.Builder().subscriptionId(subscription.getId()).build())
.getInvoices()
.get(0);
openInvoice = TEST_SETUP.createInvoice(
subscription.getId(),
b -> b
.status(CreateInvoiceStatus.OPEN)
.lineItems(List.of(
new CreateInvoiceItem.Builder()
.productId(CreateInvoiceItemProductId.fromNumber(product.getId()))
.quantity(CreateInvoiceItemQuantity.fromString("1"))
.build()
))
.coupons(List.of(
new CreateInvoiceCoupon.Builder()
.code("MY_CUSTOM_CODE")
.amount(CreateInvoiceCouponAmount.fromString("8.5"))
.description("Super coupon with 8.5 amount.")
.build()
))
.build()
);
}

@AfterAll
static void teardown() throws IOException, ApiException {
new TestTeardown().deleteCustomer(customer);
}

@SuppressWarnings("DataFlowIssue")
@Test
void shouldIssuePendingInvoice() throws IOException, ApiException {
// given
CreateAllocation createAllocation = new CreateAllocation.Builder()
.quantity(5.4)
.memo("Recoding component purchase")
.build();

// this creates an invoice in the "PENDING" status
CLIENT.getSubscriptionComponentsController().allocateComponent(
subscription.getId(),
quantityBasedComponent.getId(),
new CreateAllocationRequest(createAllocation)
);

Invoice pendingInvoice = INVOICES_CONTROLLER
.listInvoices(new ListInvoicesInput.Builder().status(InvoiceStatus.PENDING).build())
.getInvoices()
.get(0);

// when
Invoice issuedInvoice = INVOICES_CONTROLLER.issueInvoice(
pendingInvoice.getUid(),
new IssueInvoiceRequest(FailedPaymentAction.LEAVE_OPEN_INVOICE)
);

// then
assertThat(issuedInvoice.getUid()).isEqualTo(pendingInvoice.getUid());
assertThat(issuedInvoice.getSiteId()).isNotNull();
assertThat(issuedInvoice.getCustomerId()).isEqualTo(customer.getId());
assertThat(issuedInvoice.getSubscriptionId()).isEqualTo(subscription.getId());
assertThat(issuedInvoice.getNumber()).isNotNull();
assertThat(issuedInvoice.getSequenceNumber()).isNotNull();
assertThat(issuedInvoice.getCreatedAt()).isNotNull();
assertThat(issuedInvoice.getUpdatedAt()).isNotNull();
assertThat(issuedInvoice.getIssueDate()).isEqualTo(LocalDate.now());
assertThat(issuedInvoice.getDueDate()).isNotNull();
assertThat(issuedInvoice.getPaidDate()).isNull();
assertThat(issuedInvoice.getStatus()).isEqualTo(InvoiceStatus.OPEN);
assertThat(issuedInvoice.getCollectionMethod()).isEqualTo("automatic");
assertThat(issuedInvoice.getPaymentInstructions()).isEqualTo("Please make checks payable to \"Acme, Inc.\"");
assertThat(issuedInvoice.getCurrency()).isEqualTo("USD");
assertThat(issuedInvoice.getConsolidationLevel()).isEqualTo(InvoiceConsolidationLevel.NONE);
assertThat(issuedInvoice.getParentInvoiceId()).isNull();
assertThat(issuedInvoice.getParentInvoiceNumber()).isNull();
assertThat(issuedInvoice.getGroupPrimarySubscriptionId()).isNull();
assertThat(issuedInvoice.getProductName()).isEqualTo(product.getName());
assertThat(issuedInvoice.getProductFamilyName()).isEqualTo(product.getProductFamily().getName());
assertThat(issuedInvoice.getRole()).isEqualTo("renewal");

InvoiceSeller invoiceSeller = issuedInvoice.getSeller();
InvoiceAddress sellerAddress = invoiceSeller.getAddress();
assertAll(
() -> assertThat(invoiceSeller).isNotNull(),
() -> assertThat(invoiceSeller.getName()).isEqualTo("Developer Experience"),
() -> assertThat(sellerAddress).isNotNull(),
() -> assertThat(sellerAddress.getStreet()).isEqualTo("Asdf Street"),
() -> assertThat(sellerAddress.getLine2()).isEqualTo("123/444"),
() -> assertThat(sellerAddress.getCity()).isEqualTo("San Antonio"),
() -> assertThat(sellerAddress.getState()).isEqualTo("TX"),
() -> assertThat(sellerAddress.getZip()).isEqualTo("78015"),
() -> assertThat(sellerAddress.getCountry()).isEqualTo("US"),
() -> assertThat(invoiceSeller.getPhone()).isEqualTo("555 111 222")
);

InvoiceCustomer invoiceCustomer = issuedInvoice.getCustomer();
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(issuedInvoice.getMemo()).isEqualTo("Thanks for your business! If you have any questions, please contact your account manager.");

InvoiceAddress invoiceBillingAddress = issuedInvoice.getBillingAddress();
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 = issuedInvoice.getShippingAddress();
assertAll(
() -> assertThat(invoiceShippingAddress).isNotNull(),
() -> assertThat(invoiceShippingAddress.getStreet()).isEqualTo(customer.getAddress()),
() -> assertThat(invoiceShippingAddress.getLine2()).isEqualTo(customer.getAddress2()),
() -> assertThat(invoiceShippingAddress.getCity()).isEqualTo("New York"),
() -> assertThat(invoiceShippingAddress.getState()).isEqualTo("NY"),
() -> assertThat(invoiceShippingAddress.getZip()).isEqualTo("111-11"),
() -> assertThat(invoiceShippingAddress.getCountry()).isEqualTo("USA")
);

assertThat(issuedInvoice.getSubtotalAmount()).isEqualTo("5.4");
assertThat(issuedInvoice.getDiscountAmount()).isEqualTo("0.0");
assertThat(issuedInvoice.getTaxAmount()).isEqualTo("0.0");
assertThat(issuedInvoice.getTotalAmount()).isEqualTo("5.4");
assertThat(issuedInvoice.getCreditAmount()).isEqualTo("0.0");
assertThat(issuedInvoice.getRefundAmount()).isEqualTo("0.0");
assertThat(issuedInvoice.getPaidAmount()).isEqualTo("0.0");
assertThat(issuedInvoice.getDueAmount()).isEqualTo("5.4");

assertThat(issuedInvoice.getLineItems())
.hasSize(1)
.usingRecursiveFieldByFieldElementComparatorIgnoringFields("uid", "description")
.containsExactly(
new InvoiceLineItem.Builder()
.title("%s: 0.0 to 5.4 units".formatted(quantityBasedComponent.getName()))
.quantity("5.4")
.unitPrice("1.0")
.subtotalAmount("5.4")
.discountAmount("0.0")
.taxAmount("0.0")
.totalAmount("5.4")
.tieredUnitPrice(false)
.periodRangeStart(LocalDate.now().toString())
.periodRangeEnd(LocalDate.now().plusMonths(1).toString())
.productId(product.getId())
.productVersion(1)
.productPricePointId(product.getProductPricePointId())
.componentId(quantityBasedComponent.getId())
.pricePointId(quantityBasedComponent.getDefaultPricePointId())
.customItem(false)
.build()
);

assertThat(issuedInvoice.getDiscounts()).isNotNull().isEmpty();
assertThat(issuedInvoice.getTaxes()).isNotNull().isEmpty();
assertThat(issuedInvoice.getCredits()).isNotNull().isEmpty();
assertThat(issuedInvoice.getPayments()).isNotNull().isEmpty();
assertThat(issuedInvoice.getRefunds()).isNotNull().isEmpty();
assertThat(issuedInvoice.getCustomFields()).isNotNull().isEmpty();

InvoicePreviousBalance previousBalanceData = issuedInvoice.getPreviousBalanceData();
assertThat(previousBalanceData).isNotNull();
assertThat(previousBalanceData.getCapturedAt()).isNotNull();
assertThat(previousBalanceData.getInvoices())
.hasSize(1)
.usingRecursiveFieldByFieldElementComparator()
.containsExactly(new InvoiceBalanceItem.Builder()
.uid(openInvoice.getUid())
.number(openInvoice.getNumber())
.outstandingAmount(openInvoice.getDueAmount())
.build()
);

assertThat(issuedInvoice.getPublicUrl()).isNotNull().isNotBlank();
}

@ParameterizedTest
@MethodSource("argsForShouldReturn422WhenIssuingInvoiceWithIncorrectStatus")
void shouldReturn422WhenIssuingInvoiceWithIncorrectStatus(String invoiceUid) {
// when - then
CommonAssertions
.assertThatErrorListResponse(() -> INVOICES_CONTROLLER.issueInvoice(invoiceUid, new IssueInvoiceRequest()))
.isUnprocessableEntity()
.hasErrors("Invoice must have 'pending' status");
}

private static Stream<Arguments> argsForShouldReturn422WhenIssuingInvoiceWithIncorrectStatus() {
return Stream.of(
Arguments.arguments(paidInvoice.getUid()),
Arguments.arguments(openInvoice.getUid())
);
}

@Test
void shouldReturn404WhenIssuingNotExistentInvoice() {
// when - then
CommonAssertions.assertNotFound(
() -> INVOICES_CONTROLLER.issueInvoice("123", new IssueInvoiceRequest(FailedPaymentAction.LEAVE_OPEN_INVOICE)),
"Not Found"
);
}

@Test
void shouldReturn401WhenProvidingInvalidCredentials() {
// when - then
CommonAssertions.assertUnauthorized(
() -> TestClient.createInvalidCredentialsClient().getInvoicesController().issueInvoice("123", null),
"Unauthorized"
);
}
}