mirror of
https://github.com/i701/sarlink-portal.git
synced 2025-02-22 20:42:01 +00:00
- Updated `package.json` to add a new script for pushing Prisma database changes. - Refactored payment processing functions to include payment method handling for both wallet and transfer options. - Improved `DevicesTable` and `AdminDevicesTable` components to support new payment method display and user association. - Updated Prisma schema to introduce a new `PaymentType` enum and modified the `Payment` model to include a `method` field. - Enhanced UI components to improve user experience in displaying payment and device information. These changes improve the overall functionality and maintainability of the application, particularly in payment processing and device management.
210 lines
4.6 KiB
TypeScript
210 lines
4.6 KiB
TypeScript
"use server";
|
|
|
|
import prisma from "@/lib/db";
|
|
import type { PaymentType } from "@/lib/types";
|
|
import { formatMacAddress } from "@/lib/utils";
|
|
import type { Prisma } from "@prisma/client";
|
|
import { revalidatePath } from "next/cache";
|
|
import { redirect } from "next/navigation";
|
|
import { addDevicesToGroup } from "./omada-actions";
|
|
|
|
export async function createPayment(data: PaymentType) {
|
|
try {
|
|
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,
|
|
};
|
|
}),
|
|
},
|
|
},
|
|
});
|
|
return { success: true, paymentId: payment.id };
|
|
} catch (error) {
|
|
console.error("Error creating payment:", error);
|
|
return { success: false, error: "Failed to create payment" };
|
|
}
|
|
}
|
|
|
|
type VerifyPaymentType = {
|
|
userId: string;
|
|
paymentId?: string;
|
|
benefName: string;
|
|
accountNo?: string;
|
|
absAmount: string;
|
|
time: string;
|
|
type?: "TRANSFER" | "WALLET";
|
|
};
|
|
|
|
type PaymentWithDevices = Prisma.PaymentGetPayload<{
|
|
include: {
|
|
devices: true;
|
|
};
|
|
}>;
|
|
|
|
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();
|
|
}
|
|
|
|
const expiryDate = new Date();
|
|
expiryDate.setMonth(expiryDate.getMonth() + payment.numberOfMonths);
|
|
await prisma.$transaction([
|
|
prisma.payment.update({
|
|
where: { id: payment.id },
|
|
data: {
|
|
paid: true,
|
|
paidAt: new Date(),
|
|
method: "WALLET",
|
|
devices: {
|
|
updateMany: payment.devices.map((device) => ({
|
|
where: { id: device.id },
|
|
data: {
|
|
isActive: true,
|
|
expiryDate: expiryDate,
|
|
},
|
|
})),
|
|
},
|
|
},
|
|
}),
|
|
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<VerifyPaymentResponse> {
|
|
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");
|
|
}
|