mirror of
https://github.com/i701/sarlink-portal.git
synced 2025-07-03 06:48:21 +00:00
Enhance payment processing and device management features
- Introduced wallet payment option in verifyPayment function to allow users to pay using their wallet balance. - Added new BlockDeviceDialog component for managing device blocking and unblocking actions. - Updated DeviceCard component to display device status and integrate blocking functionality. - Refactored DevicesTable to utilize DeviceCard for better UI representation of devices. - Implemented Wallet component to manage wallet balance and top-up functionality. - Enhanced API routes and Prisma schema to support wallet transactions and device blocking reasons. - Improved overall user experience with responsive design adjustments and new UI elements. These changes improve user control over payments and device management, enhancing the overall functionality of the application.
This commit is contained in:
@ -4,6 +4,7 @@ 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) {
|
||||
@ -28,77 +29,159 @@ export async function createPayment(data: PaymentType) {
|
||||
}
|
||||
|
||||
type VerifyPaymentType = {
|
||||
userId: string;
|
||||
paymentId?: string;
|
||||
benefName: string;
|
||||
accountNo?: string;
|
||||
absAmount: string;
|
||||
time: string;
|
||||
type?: "TRANSFER" | "WALLET";
|
||||
};
|
||||
|
||||
export async function verifyPayment(data: VerifyPaymentType) {
|
||||
console.log({ data });
|
||||
try {
|
||||
const payment = await prisma.payment.findUnique({
|
||||
where: {
|
||||
id: data.paymentId,
|
||||
},
|
||||
include: {
|
||||
devices: true,
|
||||
},
|
||||
});
|
||||
const response = await fetch(
|
||||
"https://verifypaymentsapi.baraveli.dev/verify-payment",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
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 },
|
||||
},
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
},
|
||||
);
|
||||
const json = await response.json();
|
||||
console.log(json);
|
||||
const newDevices = payment?.devices.map((d) => {
|
||||
return {
|
||||
name: d.name,
|
||||
macAddress: formatMacAddress(d.mac),
|
||||
}),
|
||||
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> {
|
||||
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 },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (json.success === true) {
|
||||
await Promise.all([
|
||||
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 res = await addDevicesToGroup({
|
||||
groupId: process.env.OMADA_GROUP_ID,
|
||||
siteId: process.env.OMADA_SITE_ID,
|
||||
newDevices: newDevices || [],
|
||||
});
|
||||
const verificationResult = await verifyExternalPayment(data, payment);
|
||||
await updateDevices(payment);
|
||||
|
||||
revalidatePath("/payment[paymentId]");
|
||||
console.log(res);
|
||||
return res;
|
||||
|
||||
return verificationResult;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
console.error("Payment verification failed:", error);
|
||||
throw error; // Re-throw to handle at a higher level
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user