// Next.js API route support: https://nextjs.org/docs/api-routes/introduction import type { NextApiRequest, NextApiResponse } from "next"; import { withIronSessionApiRoute } from "iron-session/next"; import { sessionOptions } from "@/lib/session"; import { Group, User } from "@/interfaces/user"; import { DurationUnit, Package, Payment } from "@/interfaces/paypal"; import { v4 } from "uuid"; import ShortUniqueId from "short-unique-id"; import axios from "axios"; import { IntentionResult, PaymentIntention, TransactionResult } from "@/interfaces/paymob"; import moment from "moment"; import client from "@/lib/mongodb"; import { getEntity } from "@/utils/entities.be"; import { Entity } from "@/interfaces/entity"; import { getEntityUsers } from "@/utils/users.be"; import { mapBy } from "@/utils"; const db = client.db(process.env.MONGODB_DB); export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method === "POST") await post(req, res); } async function post(req: NextApiRequest, res: NextApiResponse) { const transactionResult = req.body as TransactionResult; const authToken = await authenticatePaymob(); console.log("WEBHOOK: ", transactionResult); if (!checkTransaction(authToken, transactionResult.transaction.order.id)) return res.status(404).json({ ok: false }); if (!transactionResult.transaction.success) return res.status(400).json({ ok: false }); const { userID, duration, duration_unit, entity: entityID } = transactionResult.intention.extras.creation_extras as { userID: string; duration: number; duration_unit: DurationUnit; entity: string }; const user = await db.collection("users").findOne({ id: userID as string }); if (!user || !duration || !duration_unit) return res.status(404).json({ ok: false }); const subscriptionExpirationDate = user.subscriptionExpirationDate; if (!subscriptionExpirationDate) return res.status(200).json({ ok: false }); const initialDate = moment(subscriptionExpirationDate).isAfter(moment()) ? moment(subscriptionExpirationDate) : moment(); const updatedSubscriptionExpirationDate = moment(initialDate).add(duration, duration_unit).endOf("day").subtract(2, "hours").toISOString(); await db.collection("users").updateOne( { id: userID as string }, { $set: { subscriptionExpirationDate: updatedSubscriptionExpirationDate, status: "active" } } ); await db.collection("paypalpayments").insertOne({ id: v4(), createdAt: new Date().toISOString(), currency: transactionResult.transaction.currency, orderId: transactionResult.transaction.id, status: "COMPLETED", subscriptionDuration: duration, subscriptionDurationUnit: duration_unit, subscriptionExpirationDate: updatedSubscriptionExpirationDate, userId: userID, value: transactionResult.transaction.amount_cents / 1000, }); if (entityID) { const entity = await getEntity(entityID) await db.collection("entities").updateOne({ id: entityID }, { $set: { expiryDate: req.body.expiryDate } }); const users = await getEntityUsers(entityID, 0, { subscriptionExpirationDate: entity?.expiryDate, $and: [ { type: { $ne: "admin" } }, { type: { $ne: "developer" } }, ] }) await db.collection("users").updateMany({ id: { $in: mapBy(users, 'id') } }, { $set: { subscriptionExpirationDate: req.body.expiryDate } }) } res.status(200).json({ ok: true, }); } const authenticatePaymob = async () => { const response = await axios.post<{ token: string }>( "https://oman.paymob.com/api/auth/tokens", { api_key: process.env.PAYMOB_API_KEY, }, { headers: { Authorization: `Bearer ${process.env.PAYMOB_SECRET_KEY}` } }, ); return response.data.token; }; const checkTransaction = async (token: string, orderID: number) => { const response = await axios.post("https://oman.paymob.com/api/ecommerce/orders/transaction_inquiry", { auth_token: token, order_id: orderID }); return response.status === 200; };