"use server"; import { authOptions } from "@/app/auth"; import type { ApiError, ApiResponse, NewPayment, Payment, } from "@/lib/backend-types"; import type { User } from "@/lib/types/user"; import { tryCatch } from "@/utils/tryCatch"; import { getServerSession } from "next-auth"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; export async function createPayment(data: NewPayment) { const session = await getServerSession(authOptions); console.log("data", data); const response = await fetch( `${ process.env.SARLINK_API_BASE_URL // }); }/api/billing/payment/`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Token ${session?.apiToken}`, }, body: JSON.stringify(data), }, ); if (!response.ok) { const errorData = (await response.json()) as ApiError; const errorMessage = errorData.message || errorData.detail || "An error occurred."; const error = new Error(errorMessage); (error as ApiError & { details?: ApiError }).details = errorData; // Attach the errorData to the error object throw error; } const payment = (await response.json()) as Payment; revalidatePath("/devices"); return payment; } export async function getPayment({ id }: { id: string }) { const session = await getServerSession(authOptions); const response = await fetch( `${process.env.SARLINK_API_BASE_URL}/api/billing/payment/${id}`, { method: "GET", headers: { "Content-Type": "application/json", Authorization: `Token ${session?.apiToken}`, }, }, ); if (!response.ok) { const errorData = (await response.json()) as ApiError; const errorMessage = errorData.message || errorData.detail || "An error occurred."; const error = new Error(errorMessage); (error as ApiError & { details?: ApiError }).details = errorData; // Attach the errorData to the error object throw error; } const data = (await response.json()) as Payment; return data; } export async function getPayments() { const session = await getServerSession(authOptions); const response = await fetch( `${process.env.SARLINK_API_BASE_URL}/api/billing/payment/`, { method: "GET", headers: { "Content-Type": "application/json", Authorization: `Token ${session?.apiToken}`, }, }, ); if (!response.ok) { const errorData = (await response.json()) as ApiError; const errorMessage = errorData.message || errorData.detail || "An error occurred."; const error = new Error(errorMessage); (error as ApiError & { details?: ApiError }).details = errorData; // Attach the errorData to the error object throw error; } const data = (await response.json()) as ApiResponse; return data; } export async function cancelPayment({ id }: { id: string }) { const session = await getServerSession(authOptions); const response = await fetch( `${process.env.SARLINK_API_BASE_URL}/api/billing/payment/${id}/delete/`, { method: "DELETE", headers: { "Content-Type": "application/json", Authorization: `Token ${session?.apiToken}`, }, }, ); if (!response.ok) { const errorData = (await response.json()) as ApiError; const errorMessage = errorData.message || errorData.detail || "An error occurred."; const error = new Error(errorMessage); (error as ApiError & { details?: ApiError }).details = errorData; // Attach the errorData to the error object throw error; } return { message: "Payment successfully canceled." }; } type UpdatePayment = Pick< Payment, "id" | "paid" | "paid_at" | "method" | "number_of_months" >; export async function updatePayment({ id, method, paid, paid_at, number_of_months, }: UpdatePayment) { const session = await getServerSession(authOptions); const response = await fetch( `${process.env.SARLINK_API_BASE_URL}/api/billing/payment/${id}/update/`, { method: "PUT", headers: { "Content-Type": "application/json", Authorization: `Token ${session?.apiToken}`, }, body: JSON.stringify({ method, paid, paid_at, number_of_months, }), }, ); if (!response.ok) { const errorData = (await response.json()) as ApiError; const errorMessage = errorData.message || errorData.detail || "An error occurred."; const error = new Error(errorMessage); (error as ApiError & { details?: ApiError }).details = errorData; // Attach the errorData to the error object throw error; } const payment = (await response.json()) as Payment; return payment; } type TUpdateWalletBalance = Pick; export async function updateWalletBalance({ id, wallet_balance, }: TUpdateWalletBalance) { const session = await getServerSession(authOptions); console.log("wallet bal in server action", wallet_balance); const response = await fetch( `${process.env.SARLINK_API_BASE_URL}/api/auth/update-wallet/${id}/`, { method: "PUT", headers: { "Content-Type": "application/json", Authorization: `Token ${session?.apiToken}`, }, body: JSON.stringify({ wallet_balance: Number.parseFloat(wallet_balance?.toFixed(2) ?? "0"), }), }, ); if (!response.ok) { const errorData = (await response.json()) as ApiError; const errorMessage = errorData.message || errorData.detail || "An error occurred."; const error = new Error(errorMessage); (error as ApiError & { details?: ApiError }).details = errorData; // Attach the errorData to the error object throw error; } const message = (await response.json()) as { message: "Wallet balance updated successfully."; }; return message; } type VerifyPaymentType = { userId: string; paymentId?: string; benefName: string; accountNo?: string; absAmount: string; time: string; type?: "TRANSFER" | "WALLET"; }; class InsufficientFundsError extends Error { constructor() { super("Insufficient funds in wallet"); this.name = "InsufficientFundsError"; } } export async function processWalletPayment({ payment, amount, }: { payment: Payment | undefined; amount: number }) { const session = await getServerSession(authOptions); if (!session?.user || !payment) { throw new Error("User or payment not found"); } const walletBalance = session.user.wallet_balance ?? 0; if (walletBalance < amount) { throw new InsufficientFundsError(); } const [updatePaymentError, _] = await tryCatch( updatePayment({ id: payment.id, method: "WALLET", paid: true, paid_at: new Date().toISOString(), number_of_months: payment.number_of_months, }), ); if (updatePaymentError) { throw new Error(updatePaymentError.message); } console.log("Wallet balance before update:", walletBalance); const updated_balance = walletBalance - amount; const [walletUpdateError, response] = await tryCatch( updateWalletBalance({ id: session.user.id, wallet_balance: Number.parseFloat(updated_balance?.toFixed(2) ?? "0"), }), ); if (walletUpdateError) { throw new Error(walletUpdateError.message); } revalidatePath("/payments/[paymentsId]", "page"); return response; } 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 { // console.log("payment verify data ->", data); // 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(); // console.log(json); // if (!payment) { // throw new Error("Payment verification failed or payment not found"); // } // if (json.success) { // const expiryDate = new Date(); // expiryDate.setMonth(expiryDate.getMonth() + payment.numberOfMonths); // await prisma.payment.update({ // where: { id: payment.id }, // data: { // paid: true, // paidAt: new Date(), // method: "TRANSFER", // devices: { // updateMany: payment.devices.map((device) => ({ // where: { id: device.id }, // data: { // isActive: true, // expiryDate: expiryDate, // }, // })), // }, // }, // }); // } // 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") { // console.log("WALLET"); // await processWalletPayment(user, payment, Number(data.absAmount)); // redirect("/payments"); // } // if (data.type === "TRANSFER") { // console.log({ data, payment }); // 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"); // }