www/stripe-webhook.js

76 lines
2.2 KiB
JavaScript

'use strict'
require('dotenv').config()
const fs = require('fs').promises
const express = require('express')
const app = express()
const ORDERS_DIR = `${__dirname}/orders`
const SHOP_DIR = `${__dirname}/_src/shop`
const SOLD_DIR = `${__dirname}/sold`
// Run a command
const run = (cmd) => {
require('child_process').exec(cmd, (err, stdout, stderr) => {
if (err) console.error(err.message)
if (stderr) console.log(stderr)
console.log(stdout)
})
}
// Format float to USD string
const formatUSD = (v) => v.toLocaleString(undefined, {
style: 'currency', currency: 'USD' })
// Start webhook forwarder so we don't need a public endpoint
run(`stripe listen --api-key '${process.env.STRIPE_SEC}' --forward-to 'http://localhost:${process.env.HOOK_PORT}/' --format 'JSON'`)
// Receive that webhook
app.listen(process.env.HOOK_PORT)
app.post('/', express.json(), async (req) => {
if (req.body.data.object.object==='charge') {
// Check if paid
if (!req.body.data.object.paid)
return console.log(`[${req.body.id}] Charge unpaid!`)
// Get order ID
const orderId = req.body.data.object.metadata.id
if (orderId == null)
return console.error(`[${req.body.id}] Charge has no metadata.id!`)
else
console.log(`[${req.body.id}] Charge paid for order ${orderId}`)
// Get order file
const orderFile = `${ORDERS_DIR}/${orderId}.json`
let order; try {
order = await JSON.parse(await fs.readFile(orderFile))
} catch (err) {
return console.error(`[${req.body.id}] Failed to retrieve order from ${orderFile}:\n${err}`)
}
// Save paidDate to order
try { order.paidDate = new Date()
fs.writeFile(orderFile, JSON.stringify(order,null,2))
} catch (err) {
console.error(`[${req.body.id}] Failed to write paidDate to ${orderFile}:\n${err}`)
}
// Email customer
run(`./hooks/email-customer ${order.id} ${order.contact.email} ${formatUSD(order.total)}`)
// Notify sales team
run(`./hooks/ntfy ${order.id} ${order.items.length} ${formatUSD(order.total)}`)
run(`./hooks/email-sales '${JSON.stringify(order)}'`)
// Remove single products from store
order.items.forEach((item) => {
if (item.sid)
run(`./hooks/remove_sid ${item.sid} ${SHOP_DIR} ${SOLD_DIR} ${__dirname}`)
})
}
})