UNPKG

@coursebuilder/core

Version:

Core package for Course Builder

177 lines (154 loc) 5.31 kB
import { PROVIDERS } from 'src/constants' import { parsePurchaseInfoFromCheckoutSession } from '../../lib/pricing/stripe-purchase-utils' import { User } from '../../schemas' import { CheckoutSessionCompletedEvent, checkoutSessionCompletedEvent, } from '../../schemas/stripe/checkout-session-completed' import { NEW_PURCHASE_CREATED_EVENT } from '../commerce/event-new-purchase-created' import { CoreInngestFunctionInput, CoreInngestHandler, CoreInngestTrigger, } from '../create-inngest-middleware' export const STRIPE_CHECKOUT_SESSION_COMPLETED_EVENT = 'stripe/checkout-session-completed' export type StripeCheckoutSessionCompleted = { name: typeof STRIPE_CHECKOUT_SESSION_COMPLETED_EVENT data: { stripeEvent: CheckoutSessionCompletedEvent } } export const stripeCheckoutSessionCompletedConfig = { id: 'stripe-checkout-session-completed', name: 'Stripe Checkout Session Completed', } export const stripeCheckoutSessionCompletedTrigger: CoreInngestTrigger = { event: STRIPE_CHECKOUT_SESSION_COMPLETED_EVENT, if: "event.data.stripeEvent.data.object.mode == 'payment'", } export const stripeCheckoutSessionCompletedHandler: CoreInngestHandler = async ({ event, step, db, siteRootUrl, paymentProvider, emailProvider, getAuthConfig, }: CoreInngestFunctionInput) => { // break down the checkout session into the info we need // recordNewPurchase(event.data.object.id) // getPurchaseInfo - load the details of the purchase from stripe // find or create a user // load the merchant product from the database // find or create the merchant customer in the database // create a merchant charge and purchase in the database const stripeEvent = checkoutSessionCompletedEvent.parse( event.data.stripeEvent, ) const paymentsAdapter = paymentProvider.options.paymentsAdapter const stripeCheckoutSession = stripeEvent.data.object const merchantAccount = await step.run( 'load the merchant account', async () => { return await db.getMerchantAccount({ provider: PROVIDERS.STRIPE, }) }, ) if (!merchantAccount) { throw new Error('Merchant account not found') } const checkoutSession = await step.run( 'get stripe checkout session', async () => { return await paymentsAdapter.getCheckoutSession( stripeCheckoutSession.id, ) }, ) const organizationId = checkoutSession.metadata?.organizationId // this could be a separate function that gets invoked here const purchaseInfo = await step.run('parse checkout session', async () => { return await parsePurchaseInfoFromCheckoutSession(checkoutSession, db) }) const { user, isNewUser } = await step.run('load the user', async () => { if (!purchaseInfo.email) { throw new Error('purchaseInfo.email is null') } return await db.findOrCreateUser(purchaseInfo.email) }) const merchantProduct = await step.run( 'load the merchant product', async () => { if (!purchaseInfo.productIdentifier) { throw new Error('purchaseInfo.productIdentifier is null') } return await db.getMerchantProduct(purchaseInfo.productIdentifier) }, ) const merchantCustomer = await step.run( 'load the merchant customer', async () => { if (!purchaseInfo.customerIdentifier) { throw new Error('purchaseInfo.customerIdentifier is null') } return await db.findOrCreateMerchantCustomer({ user: user as User, identifier: purchaseInfo.customerIdentifier, merchantAccountId: merchantAccount.id, }) }, ) const product = await step.run('load the product', async () => { if (!merchantProduct?.productId) { throw new Error('merchantProduct.productId is null') } return await db.getProduct(merchantProduct.productId) }) const purchase = await step.run( 'create a merchant charge and purchase', async () => { if (!merchantProduct) { throw new Error('merchantProduct is null') } if (!merchantCustomer) { throw new Error('merchantCustomer is null') } return await db.createMerchantChargeAndPurchase({ userId: user.id, organizationId, productId: merchantProduct.productId, stripeChargeId: purchaseInfo.chargeIdentifier, stripeCouponId: purchaseInfo.couponIdentifier, merchantAccountId: merchantAccount.id, merchantProductId: merchantProduct.id, merchantCustomerId: merchantCustomer.id, stripeChargeAmount: purchaseInfo.chargeAmount, quantity: purchaseInfo.quantity, checkoutSessionId: stripeCheckoutSession.id, country: purchaseInfo.metadata?.country, appliedPPPStripeCouponId: purchaseInfo.metadata?.appliedPPPStripeCouponId, upgradedFromPurchaseId: purchaseInfo.metadata?.upgradedFromPurchaseId, usedCouponId: purchaseInfo.metadata?.usedCouponId, }) }, ) await step.sendEvent(NEW_PURCHASE_CREATED_EVENT, { name: NEW_PURCHASE_CREATED_EVENT, data: { purchaseId: purchase.id, checkoutSessionId: stripeCheckoutSession.id, productType: product?.type || 'self-paced', }, user, }) return { purchase, purchaseInfo } } export const stripeCheckoutSessionComplete = { config: stripeCheckoutSessionCompletedConfig, trigger: stripeCheckoutSessionCompletedTrigger, handler: stripeCheckoutSessionCompletedHandler, }