in libs/payments/cart/src/lib/checkout.service.ts [92:238]
async prePaySteps(
cart: ResultCart,
customerData: CheckoutCustomerData
): Promise<PrePayStepsResult> {
const taxAddress = cart.taxAddress;
if (!taxAddress) {
throw new CartNoTaxAddressError(cart.id);
}
let version = cart.version;
if (!cart.currency) {
throw new CartCurrencyNotFoundError(
cart.currency || undefined,
taxAddress.countryCode
);
}
const uid = cart.uid;
if (!uid) {
throw new CartUidNotFoundError(cart.id);
}
const fxaAccounts = await this.accountManager.getAccounts([uid]);
if (!(fxaAccounts && fxaAccounts.length > 0)) {
throw new CartAccountNotFoundError(cart.id);
}
const email = fxaAccounts[0].email;
let stripeCustomerId = cart.stripeCustomerId;
let customer: StripeCustomer;
if (!stripeCustomerId) {
customer = await this.customerManager.create({
uid,
email,
displayName: customerData.displayName,
taxAddress,
});
stripeCustomerId = customer.id;
} else {
customer = await this.customerManager.retrieve(stripeCustomerId);
await this.customerManager.update(stripeCustomerId, {
shipping: {
name: email,
address: {
country: taxAddress.countryCode,
postal_code: taxAddress.postalCode,
},
},
});
}
if (uid && !cart.stripeCustomerId) {
await this.accountCustomerManager.createAccountCustomer({
uid,
stripeCustomerId,
});
}
// Cart only needs to be updated if we created a customer
if (!cart.uid || !cart.stripeCustomerId) {
await this.cartManager.updateFreshCart(cart.id, cart.version, {
uid,
stripeCustomerId,
});
version += 1;
}
// validate customer is eligible for product via eligibility service
// throws cart eligibility mismatch error if no match found
const eligibility = await this.eligibilityService.checkEligibility(
cart.interval as SubplatInterval,
cart.offeringConfigId,
uid,
stripeCustomerId
);
const cartEligibilityStatus =
handleEligibilityStatusMap[eligibility.subscriptionEligibilityResult];
if (cartEligibilityStatus !== cart.eligibilityStatus) {
throw new CartEligibilityMismatchError(
cart.id,
cart.eligibilityStatus,
cartEligibilityStatus
);
}
// re-validate total amount against upcoming invoice
// throws cart total mismatch error if no match found
const price = await this.productConfigurationManager.retrieveStripePrice(
cart.offeringConfigId,
cart.interval as SubplatInterval
);
const upcomingInvoice = await this.invoiceManager.previewUpcoming({
priceId: price.id,
currency: cart.currency,
customer: customer,
taxAddress: taxAddress,
});
if (upcomingInvoice.subtotal !== cart.amount) {
throw new CartTotalMismatchError(
cart.id,
cart.amount,
upcomingInvoice.subtotal
);
}
// check if customer already has subscription to price and cancel if they do
await this.subscriptionManager.cancelIncompleteSubscriptionsToPrice(
stripeCustomerId,
price.id
);
const enableAutomaticTax = this.customerManager.isTaxEligible(customer);
let promotionCode: StripePromotionCode | undefined;
if (cart.couponCode) {
try {
await this.promotionCodeManager.assertValidPromotionCodeNameForPrice(
cart.couponCode,
price,
cart.currency
);
promotionCode = await this.promotionCodeManager.retrieveByName(
cart.couponCode
);
} catch (e) {
throw new CartInvalidPromoCodeError(cart.couponCode, cart.id);
}
}
return {
uid: uid,
customer,
enableAutomaticTax,
promotionCode,
version,
price,
eligibility,
};
}