Skip to content

Instantly share code, notes, and snippets.

@cptiwari20
Created September 14, 2020 16:35
Show Gist options
  • Select an option

  • Save cptiwari20/836e7875d38dd4965faeb14fb8f3a4ad to your computer and use it in GitHub Desktop.

Select an option

Save cptiwari20/836e7875d38dd4965faeb14fb8f3a4ad to your computer and use it in GitHub Desktop.
Handle Thrivecart events in Node.js Expressjs API
const Subscriptions = require("../models/subscriptions"); //Any Subscription Model
const Users = require("../models/users"); // User Model
const Plans = require("../models/plans"); // Plans Model
const Payments = require('../models/payments')
const { send: sendMail } = require('../services/smtp');
const { generatePassword, getExpiryDate } = require('../utils/helpers');
let thrivecart_secret = process.env.THRIVECART_SECRET; //Add your API Secret in .env file
const thriveCartWebhook = async (req, res, next) => {
const subscriptionData = req.body
const {
customer,
order_id,
customer_id,
base_product, order
} = subscriptionData
console.log('the thrivecart webhook request data =>', subscriptionData)
try {
if(subscriptionData.thrivecart_secret === thrivecart_secret){
switch (req.body.event) {
case 'order.success':
// Find if existing User (this data is Optional You can add a passthrough inside the plan URL)
const userId = customer.passthrough ? customer.passthrough.userId : undefined
// check the event whether the subscription is available or not
const subscription = await Subscriptions.findOne({ order_id, customer_id })
if(!!subscription) return await createSubscriptionPayment({subscriptionData}, res) //create a new payment
if (userId) {
const user = await Users.findById(userId);
if(!user){ //if failed to find user
const existingUser = await Users.findOne({email: customer.email}); //then find using email
if (existingUser) { // if email exists
return await findUserAndSubscribe({ user: existingUser, subscriptionData }, res)
}else{ // email doesn't exist
return await createUserAndSubscribe({ subscriptionData }, res)
}
}
return await findUserAndSubscribe({ user, subscriptionData }, res)
} else {
// If no existing User
// Check if users email already exists
const existingUser = await Users.findOne({email: customer.email});
if (existingUser) {
return await findUserAndSubscribe({ user: existingUser, subscriptionData }, res)
}else{
return await createUserAndSubscribe({ subscriptionData }, res)
}
}
case 'order.subscription_payment':
return await createSubscriptionPayment({subscriptionData}, res)
case 'order.subscription_cancelled':
return await updateSubscription({
subscriptionData,
status: 'cancelled',
message: 'Subscription cancelled!'
}, res)
case 'order.subscription_paused':
return await updateSubscription({
subscriptionData,
status: 'paused',
message: 'Subscription paused!'
}, res)
case 'order.subscription_resumed':
return await updateSubscription({
subscriptionData,
status: 'live',
message: 'Subscription resumed!'
}, res)
case 'order.refund':
return await updateSubscription({
subscriptionData,
status: 'refunded',
message: 'Subscription updated!'
}, res)
case 'order.rebill_failed':
return await updateSubscription({
subscriptionData,
status: 'rebill_failed',
message: 'Subscription updated!'
}, res)
default:
// const subscription = await Subscriptions.findOne({ order_id, customer_id })
// await subscription.updateOne(
// {
// $set: {
// ...subscriptionData
// }
// }
// )
console.log('Event recieved but nothing updated!')
return res.status(200).json({ status: false, message: 'Event recieved but nothing updated!' })
}
}else{
console.log('Getting data from unknown source!')
res.status(403).json({status: false, message: 'Getting data from unknown source.'})
}
} catch (error) {
console.log(error)
return res.status(500).json({ status: false, message: error.message, error })
}
}
const findUserAndSubscribe = async ({ user, subscriptionData }, res) => {
const { base_product, order, customer } = subscriptionData
try {
const plan = await Plans.findOne({ product: base_product })
if (!plan) res.status(400).json({ status: false, message: 'Plan not found.' })
const subscription = new Subscriptions({
...subscriptionData,
user: user._id,
plan: plan._id,
amount: order.total_str,
product: base_product,
payment_method: order.processor,
email_id: customer.email,
customer_details: customer,
interval: plan.interval.billing_period,
starts_at: new Date(subscriptionData.order_date),
expiry_date: getExpiryDate(plan.interval.billing_period, new Date(subscriptionData.order_date))
})
const createdSubscription = await subscription.save()
user.subscriptions = [...user.subscriptions, createdSubscription._id],
user.thrivecart_customer_id = subscriptionData.customer_id
const payment = await new Payments({
...subscriptionData,
user: user._id,
plan: plan._id,
subscription: createdSubscription._id,
amount: order.total_str,
payment_method: order.processor,
}).save();
// console.log('Existing uSer',{user})
await user.save()
res.status(200).json({ status: true, message: 'Plan has been subscribed Successfully!' })
} catch (error) {
res.status(500).json({ status: false, message: error.message})
}
}
const createUserAndSubscribe = async ({ subscriptionData, hostedpage }, res) => {
try {
const { customer, base_product, order } = subscriptionData
const plan = await Plans.findOne({ product: base_product })
if (!plan) res.status(400).json({ status: false, message: 'Plan not found.' })
const { first_name, last_name, email, address } = customer
let addressUpdated = ""
if (address) {
addressUpdated = Object.values(address).join(', ');
}
const password = generatePassword()
const user = new Users({
first_name,
last_name,
email,
password,
address: addressUpdated,
})
const createdUser = await user.save()
const subscription = new Subscriptions({
...subscriptionData,
user: user._id,
plan: plan._id,
amount: order.total_str,
product: base_product,
payment_method: order.processor,
email_id: customer.email,
customer_details: customer,
interval: plan.interval.billing_period,
starts_at: new Date(subscriptionData.order_date),
expiry_date: getExpiryDate(plan.interval.billing_period, new Date(subscriptionData.order_date))
})
const createdSubscription = await subscription.save()
createdUser.subscriptions = [...user.subscriptions, createdSubscription._id],
createdUser.thrivecart_customer_id = customer.id
await createdUser.save()
const payment = await new Payments({
...subscriptionData,
user: createdUser._id,
plan: plan._id,
subscription: createdSubscription._id,
amount: order.total_str,
payment_method: order.processor,
}).save();
return res.status(200).json({ status: true, message: 'New user has been registered with a new subscription!' })
} catch (error) {
res.status(500).json({ status: false, message: error.message })
}
}
const updateSubscription = async ({ subscriptionData, status, message }, res) => {
const subscription = await Subscriptions.findOne({
order_id: subscriptionData.order_id,
customer_id: subscriptionData.customer_id
})
await subscription.updateOne(
{
$set: {
updated_at: new Date().now,
status: status,
}
}
);
return res.status(200).json({ status: true, message })
}
const createSubscriptionPayment = async ({subscriptionData}, res) => {
const {order_id, customer_id, order } = subscriptionData
try{
const subscription = await Subscriptions.findOne({ order_id, customer_id });
if(!subscription) return res.status(400).json({ status: false, message: 'No subscription found!' })
const resp = await subscription.updateOne(
{
$set: {
updated_at: new Date().now,
status: 'live',
expiry_date: getExpiryDate(subscription.interval, new Date())
}
},
{ runValidators: true }
);
const payment = await new Payments({
...subscriptionData,
user: subscription.user,
plan: subscription.plan,
subscription: subscription._id,
amount: order.total_str,
payment_method: order.processor,
})
const createdPayment = await payment.save()
console.log(createdPayment)
return res.status(200).json({ status: true, message: 'Subscription Payment created' })
} catch (error) {
console.log(error)
res.status(500).json({ status: false, message: error.message })
}
}
module.exports = {
thriveCartWebhook
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment