"use server"; import prisma from "@/lib/db"; import type { PaymentType } from "@/lib/types"; import { formatMacAddress } from "@/lib/utils"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { addDevicesToGroup } from "./omada-actions"; export async function createPayment(data: PaymentType) { console.log("data", data); const payment = await prisma.payment.create({ data: { amount: data.amount, numberOfMonths: data.numberOfMonths, paid: data.paid, userId: data.userId, devices: { connect: data.deviceIds.map((id) => { return { id, }; }), }, }, }); revalidatePath("/devices"); return payment; } type VerifyPaymentType = { userId: string; paymentId?: string; benefName: string; accountNo?: string; absAmount: string; time: string; type?: "TRANSFER" | "WALLET"; }; type PaymentWithDevices = { id: string; devices: Array<{ name: string; mac: string; }>; }; class InsufficientFundsError extends Error { constructor() { super("Insufficient funds in wallet"); this.name = "InsufficientFundsError"; } } async function processWalletPayment( user: { id: string; walletBalance: number } | null, payment: PaymentWithDevices | null, amount: number, ) { if (!user || !payment) { throw new Error("User or payment not found"); } const walletBalance = user.walletBalance ?? 0; if (walletBalance < amount) { throw new InsufficientFundsError(); } await prisma.$transaction([ prisma.payment.update({ where: { id: payment.id }, data: { paid: true, paidAt: new Date(), devices: { updateMany: { where: { paymentId: payment.id }, data: { isActive: true }, }, }, }, }), prisma.user.update({ where: { id: user.id }, data: { walletBalance: walletBalance - amount }, }), ]); } type VerifyPaymentResponse = | { success: boolean; message: string; } | { success: boolean; message: string; transaction: { ref: string; sourceBank: string; trxDate: string; }; }; async function verifyExternalPayment( data: VerifyPaymentType, payment: PaymentWithDevices | null, ): Promise { const response = await fetch( "https://verifypaymentsapi.baraveli.dev/verify-payment", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }, ); const json = await response.json(); if (!payment) { throw new Error("Payment verification failed or payment not found"); } if (json.success) { await prisma.payment.update({ where: { id: payment.id }, data: { paid: true, paidAt: new Date(), devices: { updateMany: { where: { paymentId: payment.id }, data: { isActive: true }, }, }, }, }); } return json; } async function updateDevices(payment: PaymentWithDevices | null) { if (!payment) return; const newDevices = payment.devices.map((d) => ({ name: d.name, macAddress: formatMacAddress(d.mac), })); return await addDevicesToGroup({ groupId: process.env.OMADA_GROUP_ID, siteId: process.env.OMADA_SITE_ID, newDevices, }); } export async function verifyPayment(data: VerifyPaymentType) { try { const [payment, user] = await Promise.all([ prisma.payment.findUnique({ where: { id: data.paymentId }, include: { devices: true }, }), prisma.user.findUnique({ where: { id: data.userId }, }), ]); if (data.type === "WALLET") { await processWalletPayment(user, payment, Number(data.absAmount)); redirect("/payments"); } const verificationResult = await verifyExternalPayment(data, payment); await updateDevices(payment); revalidatePath("/payment[paymentId]"); return verificationResult; } catch (error) { console.error("Payment verification failed:", error); throw error; // Re-throw to handle at a higher level } } export async function addDevicesToOmada() { console.log("hi"); }