Skip to content

Commit

Permalink
Merge pull request #16941 from mozilla/FXA-8896
Browse files Browse the repository at this point in the history
feat(cartService): update total in `CartService.setupCart`
  • Loading branch information
sardesam authored May 21, 2024
2 parents ef9ccd4 + 0d11e8a commit 32a8f3a
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 7 deletions.
58 changes: 56 additions & 2 deletions libs/payments/cart/src/lib/cart.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ describe('CartService', () => {

describe('setupCart', () => {
it('calls createCart with expected parameters', async () => {
const mockAccountCustomer = ResultAccountCustomerFactory();
const mockCustomer = StripeResponseFactory(StripeCustomerFactory());
const mockAccountCustomer = ResultAccountCustomerFactory({
stripeCustomerId: mockCustomer.id,
});
const mockResultCart = ResultCartFactory();
const args = {
interval: SubplatInterval.Monthly,
Expand All @@ -127,21 +130,71 @@ describe('CartService', () => {
ip: faker.internet.ipv4(),
};
const taxAddress = TaxAddressFactory();
const mockPrice = StripePriceFactory();
const mockUpcomingInvoice = StripeResponseFactory(
StripeUpcomingInvoiceFactory({
discount: StripeDiscountFactory(),
total_discount_amounts: [
{
amount: 500,
discount: StripeDiscountFactory(),
},
],
total_tax_amounts: [
{
amount: faker.number.int(1000),
inclusive: false,
tax_rate: StripeTaxRateFactory(),
taxability_reason: null,
taxable_amount: null,
},
],
})
);

const mockInvoicePreview = {
currency: mockUpcomingInvoice.currency,
listAmount: mockUpcomingInvoice.amount_due,
totalAmount: mockUpcomingInvoice.total,
taxAmounts: [
{
title:
mockUpcomingInvoice.total_tax_amounts[0].tax_rate.display_name,
inclusive: mockUpcomingInvoice.total_tax_amounts[0].inclusive,
amount: mockUpcomingInvoice.total_tax_amounts[0].amount,
},
],
discountAmount:
mockUpcomingInvoice.discount &&
mockUpcomingInvoice.total_discount_amounts &&
mockUpcomingInvoice.total_discount_amounts[0].amount,
subTotal: mockUpcomingInvoice.subtotal,
};

jest
.spyOn(eligibilityService, 'checkEligibility')
.mockResolvedValue(EligibilityStatus.CREATE);
jest.spyOn(geodbManager, 'getTaxAddress').mockReturnValue(taxAddress);
jest
.spyOn(accountCustomerManager, 'getAccountCustomerByUid')
.mockResolvedValue(mockAccountCustomer);
jest
.spyOn(contentfulService, 'retrieveStripePlanId')
.mockResolvedValue(mockPrice.id);
jest
.spyOn(stripeManager, 'fetchActiveCustomer')
.mockResolvedValue(mockCustomer);
jest
.spyOn(stripeManager, 'previewInvoice')
.mockResolvedValue(mockInvoicePreview);
jest.spyOn(cartManager, 'createCart').mockResolvedValue(mockResultCart);

const result = await cartService.setupCart(args);

expect(cartManager.createCart).toHaveBeenCalledWith({
interval: args.interval,
offeringConfigId: args.offeringConfigId,
amount: 0,
amount: mockUpcomingInvoice.subtotal,
uid: args.uid,
stripeCustomerId: mockAccountCustomer.stripeCustomerId,
experiment: args.experiment,
Expand Down Expand Up @@ -419,6 +472,7 @@ describe('CartService', () => {
mockUpcomingInvoice.discount &&
mockUpcomingInvoice.total_discount_amounts &&
mockUpcomingInvoice.total_discount_amounts[0].amount,
subTotal: mockUpcomingInvoice.subtotal,
};

it('returns cart and invoicePreview', async () => {
Expand Down
19 changes: 17 additions & 2 deletions libs/payments/cart/src/lib/cart.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export class CartService {
// - Fetch information about interval, offering, experiments from Contentful
// - Guess TaxAddress via maxmind client
// - Check if user is eligible to subscribe to plan, else throw error
// - Fetch invoice preview total from Stripe for `amount`
// - Fetch stripeCustomerId if uid is passed and has a customer id
let accountCustomer;
if (args.uid) {
Expand All @@ -64,10 +63,26 @@ export class CartService {
}
}

const stripeCustomerId = accountCustomer?.stripeCustomerId;
const stripeCustomer = stripeCustomerId
? await this.stripeManager.fetchActiveCustomer(stripeCustomerId)
: undefined;

const taxAddress = args.ip
? this.geodbManager.getTaxAddress(args.ip)
: undefined;

const priceId = await this.contentfulService.retrieveStripePlanId(
args.offeringConfigId,
args.interval
);

const upcomingInvoice = await this.stripeManager.previewInvoice({
priceId: priceId,
customer: stripeCustomer,
taxAddress: taxAddress,
});

const eligibility = await this.eligibilityService.checkEligibility(
args.interval,
args.offeringConfigId,
Expand All @@ -79,7 +94,7 @@ export class CartService {
const cart = await this.cartManager.createCart({
interval: args.interval,
offeringConfigId: args.offeringConfigId,
amount: 0,
amount: upcomingInvoice.subTotal,
uid: args.uid,
stripeCustomerId: accountCustomer?.stripeCustomerId || undefined,
experiment: args.experiment,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ export const ResultAccountCustomerFactory = (
prefix: '',
casing: 'lower',
}),
stripeCustomerId: faker.string.alphanumeric({
length: 14,
}),
stripeCustomerId: `cus_${faker.string.alphanumeric({ length: 14 })}`,
createdAt: faker.date.recent().getTime(),
updatedAt: faker.date.recent().getTime(),
...override,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ describe('stripeInvoiceToFirstInvoicePreviewDTO', () => {
discountAmount:
mockUpcomingInvoice.discount &&
mockUpcomingInvoice.total_discount_amounts?.[0].amount,
subTotal: mockUpcomingInvoice.subtotal,
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ export function stripeInvoiceToFirstInvoicePreviewDTO(
totalAmount: invoice.total,
taxAmounts,
discountAmount,
subTotal: invoice.subtotal,
};
}

0 comments on commit 32a8f3a

Please sign in to comment.