diff --git a/README.md b/README.md index a97197f..020f450 100644 --- a/README.md +++ b/README.md @@ -167,19 +167,19 @@ This API route is used by the local listener to receive asynchronous Stripe even Set up event forwarding with the [Stripe CLI](https://docs.stripe.com/stripe-cli) and send all Stripe events to your local webhook endpoint for testing and/or monitoring purposes: ```zsh -stripe listen --forward-to localhost:5000/api/v1/stripe-checkout/webhook +stripe listen --events=payment_intent.succeeded --forward-to localhost:5000/api/v1/stripe-checkout/webhook ``` Use the PM2 process manager to run the `listen` command in production: ```zsh -pm2 start --name stripe-listener "stripe listen --events checkout.session.completed --forward-to localhost:5000/api/v1/stripe-checkout/webhook" +pm2 start --name stripe-listener "stripe listen --events=checkout.session.completed --forward-to localhost:5000/api/v1/stripe-checkout/webhook" ``` [Read more about the Stripe webhooks](https://docs.stripe.com/webhooks/quickstart)
-## TODOs (Limitations) +## TODOs (Improvements) -- Enable checkout session with more than 99 items +- Enable checkout session with more than 99 products diff --git a/index.js b/index.js index 3eb57a9..7e6c7d9 100644 --- a/index.js +++ b/index.js @@ -59,62 +59,59 @@ module.exports = { return { post: { [stripeWebhookEndpoint]: async function (req, res, next) { - class StripeCheckoutHandler { - async handleCheckoutSession(req, res) { - try { - if (!req.headers['stripe-signature']) { - throw new Error('Stripe signature was not provided in the header.'); - } - const event = await this.constructStripeEvent(req); - if (event.type === 'checkout.session.completed') { - const checkoutSession = await stripe.checkout.sessions.retrieve(event.data.object.id); - const checkoutSessionInstance = this.createCheckoutSessionInstance(checkoutSession); - await this.insertCheckoutSessionInstance(checkoutSessionInstance); - } - return res.status(200).end(); - } catch (error) { - console.error('Error handling checkout session:', error); - return res.status(500).send(error.message); + async function handleCheckoutSession(req, res) { + try { + if (!req.headers['stripe-signature']) { + throw new Error('Stripe signature was not provided in the header.'); } - } - - async constructStripeEvent(req) { - if (process.env.STRIPE_MOCK_TEST_MODE === 'true') { - return { - type: 'checkout.session.completed', - data: { object: { id: 'cs_xyz' } } - }; - } else { - return stripe.webhooks.constructEvent(req.body, req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_ENDPOINT_SECRET); + const event = await constructStripeEvent(req); + if (event.type === 'checkout.session.completed') { + const checkoutSession = await stripe.checkout.sessions.retrieve(event.data.object.id); + const checkoutSessionInstance = createCheckoutSessionInstance(checkoutSession); + await insertCheckoutSessionInstance(checkoutSessionInstance); } + return res.status(200).end(); + } catch (error) { + console.error('Error handling checkout session:', error); + return res.status(500).send(error.message); } + } - createCheckoutSessionInstance(checkoutSession) { - const checkoutSessionInstance = self.apos.stripeCheckoutSession.newInstance(); - checkoutSessionInstance.slug = checkoutSession.id; - checkoutSessionInstance.stripeCheckoutSessionObject = checkoutSession; - checkoutSessionInstance.stripeCheckoutSessionObject.created_timestamp = new Date(checkoutSession.created * 1000).toISOString(); - checkoutSessionInstance.stripeCheckoutSessionObject.amount_subtotal = (checkoutSession.amount_subtotal / 100).toFixed(2); - checkoutSessionInstance.stripeCheckoutSessionObject.amount_total = (checkoutSession.amount_total / 100).toFixed(2); - return checkoutSessionInstance; + async function constructStripeEvent(req) { + if (process.env.STRIPE_MOCK_TEST_MODE === 'true') { + return { + type: 'checkout.session.completed', + data: { object: { id: 'cs_xyz' } } + }; + } else { + return stripe.webhooks.constructEvent(req.body, req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_ENDPOINT_SECRET); } + } - async insertCheckoutSessionInstance(checkoutSessionInstance) { - const lineItems = await stripe.checkout.sessions.listLineItems(checkoutSessionInstance.slug, { limit: 99 }); - checkoutSessionInstance.stripeCheckoutSessionObject.line_items_quantity_total = lineItems.data.reduce((sum, item) => sum + item.quantity, 0); - lineItems.data.forEach(item => { - [ 'amount_total', 'amount_subtotal', 'amount_discount', 'amount_tax' ].forEach(field => { - item[field] = (item[field] / 100).toFixed(2); - }); - item.price.unit_amount = (item.price.unit_amount / 100).toFixed(2); + function createCheckoutSessionInstance(checkoutSession) { + const checkoutSessionInstance = self.apos.stripeCheckoutSession.newInstance(); + checkoutSessionInstance.slug = checkoutSession.id; + checkoutSessionInstance.stripeCheckoutSessionObject = checkoutSession; + checkoutSessionInstance.stripeCheckoutSessionObject.created_timestamp = new Date(checkoutSession.created * 1000).toISOString(); + checkoutSessionInstance.stripeCheckoutSessionObject.amount_subtotal = (checkoutSession.amount_subtotal / 100).toFixed(2); + checkoutSessionInstance.stripeCheckoutSessionObject.amount_total = (checkoutSession.amount_total / 100).toFixed(2); + return checkoutSessionInstance; + } + + async function insertCheckoutSessionInstance(checkoutSessionInstance) { + const lineItems = await stripe.checkout.sessions.listLineItems(checkoutSessionInstance.slug, { limit: 99 }); + checkoutSessionInstance.stripeCheckoutSessionObject.line_items_quantity_total = lineItems.data.reduce((sum, item) => sum + item.quantity, 0); + lineItems.data.forEach(item => { + [ 'amount_total', 'amount_subtotal', 'amount_discount', 'amount_tax' ].forEach(field => { + item[field] = (item[field] / 100).toFixed(2); }); - checkoutSessionInstance.stripeCheckoutSessionLineItemsObject = lineItems; - await self.apos.stripeCheckoutSession.insert(req, checkoutSessionInstance, { permissions: false }); - } + item.price.unit_amount = (item.price.unit_amount / 100).toFixed(2); + }); + checkoutSessionInstance.stripeCheckoutSessionLineItemsObject = lineItems; + await self.apos.stripeCheckoutSession.insert(req, checkoutSessionInstance, { permissions: false }); } - const stripeCheckoutHandler = new StripeCheckoutHandler(); - stripeCheckoutHandler.handleCheckoutSession(req, res); + await handleCheckoutSession(req, res); } } }; diff --git a/package.json b/package.json index 9b4a63f..e2249b0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stepanjakl/apostrophe-stripe-checkout", - "version": "0.0.4", + "version": "0.0.5", "description": "Stripe Checkout For ApostropheCMS", "keywords": [ "apostrophe",