import logging from '../lib/logging.js'; import { Payment } from "../lib/models.js"; const log = logging.create("/queues/stripe.js"); const find_payment = async (msg) => { // sys_primary_id is the payment_intent and sys_secondary_id is charge_id const dobj = msg.data.object; // stripe is stupid and changes the name/location of payment_intent IDs if(dobj.payment_intent) { // it has a payment intent so need to find by that return await Payment.first({sys_primary_id: dobj.payment_intent}); } else { switch(dobj.object) { case "payment_intent": return await Payment.first({sys_primary_id: dobj.id}); case "charge": return await Payment.first({sys_secondary_id: dobj.id}); default: return undefined; } } } export const webhook = async (job) => { try { const msg = job.data; const payment = await find_payment(msg); log.debug(`Stripe WebHook event ${msg.type} ID ${msg.id} created ${msg.created} payment ID ${payment ? payment.id : "none"}`); if(payment) { switch(msg.type) { case "payment_intent.created": log.debug(`Payment intent created, payment ${payment.id} is in process for user ${payment.user_id}`) break; // these create a refunded status case "charge.dispute.created": case "charge.refunded": await Payment.update({id: payment.id}, {status: "refunded", status_reason: msg.type}); break; // these result in pending case "charge.failed": // not sure if this is temporary case "payment_intent.requires_action": await Payment.update({id: payment.id}, {status: "pending", status_reason: msg.type}); break; // these all result in complete status case "charge.succeeded": await Payment.update({id: payment.id}, { sys_secondary_id: msg.data.object.id, status: "complete", status_reason: msg.type }); break; case "payment_intent.succeeded": // on charge success we need to start tracking the charge id await Payment.update({id: payment.id}, { status: "complete", status_reason: msg.type }); break; case "charge.dispute.funds_reinstated": case "charge.dispute.funds_withdrawn": await Payment.update({id: payment.id}, {status: "complete", status_reason: msg.type}); break; case "radar.early_fraud_warning.created": await Payment.update({id: payment.id}, {status: "failed", status_reason: msg.type}); break; default: log.info(`UNKNOWN STRIPE EVENT ${msg.type} ID: ${payment.id}`); } } else { console.log("<<< UNKNOWN WEBHOOK POST", msg.type, msg); } } catch (error) { log.error(error); } }