summaryrefslogtreecommitdiff
path: root/pages/api/po/webhook.ts
diff options
context:
space:
mode:
Diffstat (limited to 'pages/api/po/webhook.ts')
-rw-r--r--pages/api/po/webhook.ts337
1 files changed, 337 insertions, 0 deletions
diff --git a/pages/api/po/webhook.ts b/pages/api/po/webhook.ts
new file mode 100644
index 00000000..50b3c1f4
--- /dev/null
+++ b/pages/api/po/webhook.ts
@@ -0,0 +1,337 @@
+export const config = {
+ api: {
+ bodyParser: true, // ✅ 이게 false면 안 됨!
+ },
+};
+
+import type { NextApiRequest, NextApiResponse } from "next";
+import path from "path";
+import fs from "fs";
+import * as z from "zod";
+import db from "@/db/db";
+import { GetPOSchema } from "@/lib/po/validations";
+import { unstable_cache } from "@/lib/unstable-cache";
+import { filterColumns } from "@/lib/filter-columns";
+import {
+ asc,
+ desc,
+ ilike,
+ inArray,
+ and,
+ gte,
+ lte,
+ not,
+ or,
+ eq,
+ count,
+} from "drizzle-orm";
+import { countPos, selectPos } from "@/lib/po/repository";
+import {
+ contractEnvelopes,
+ contractsDetailView,
+ contractSigners,
+ contracts,
+} from "@/db/schema/contract";
+import { vendors, vendorContacts } from "@/db/schema/vendors";
+import dayjs from "dayjs";
+
+import { POContent } from "@/lib/docuSign/types";
+import { downloadContractFile, getRecipients } from "@/lib/docuSign/docuSignFns";
+
+export default async function handler(
+ req: NextApiRequest,
+ res: NextApiResponse
+) {
+ if (req.method !== "POST") {
+ return res.status(405).end();
+ }
+
+ try {
+ const { event, data = {} } = req.body;
+
+ //recipientId === "1" 첫번째 서명자 서명 완료
+ //recipientId === "2" 두번쨰 서명자 서명 완료
+ const { envelopeId, recipientId } = data;
+
+ console.log(req.body)
+
+ const contractList = [
+ {
+ dbName: "contract_envelopes",
+ dbSchma: contractEnvelopes,
+ recipients: [
+ {
+ recipientId: "1",
+ role: "VENDOR",
+ },
+ {
+ recipientId: "2",
+ role: "REQUESTER",
+ },
+ ],
+ },
+ ];
+
+ //서명 요청 발송
+ if (event === "recipient-sent") {
+ await db.transaction(async (tx) => {
+ for (const targetDB of contractList) {
+ const { dbSchma, dbName, recipients = [] } = targetDB;
+ const [targetContract] = await tx
+ .select()
+ .from(dbSchma)
+ .where(eq(dbSchma.envelopeId, envelopeId))
+ .limit(1);
+
+ if (!targetContract) {
+ continue;
+ }
+
+ const { contractId, id } = targetContract;
+
+ if (contractId === null || contractId === undefined) {
+ continue;
+ }
+
+ const { result: sendResult, message } = await getRecipients(
+ envelopeId,
+ recipientId
+ );
+
+ if (!sendResult) {
+ const targetRole = recipients.find(
+ (c) => c.recipientId === recipientId
+ );
+
+ if (targetRole) {
+ const { role } = targetRole;
+
+ const safeRole = role as "REQUESTER" | "VENDOR";
+
+ await tx
+ .update(contracts)
+ .set({ status: `$FAILED_${safeRole}_SEND_MAIL(${message})` })
+ .where(eq(contracts.id, contractId));
+
+ await tx
+ .update(dbSchma)
+ .set({ envelopeStatus: `${safeRole}_${message}` })
+ .where(eq(dbSchma.id, id));
+ }
+
+ continue;
+ }
+
+ // const createContractFile = await downloadContractFile(envelopeId);
+
+ // const { result, buffer, error } = createContractFile;
+
+ // if (!result || !buffer) {
+ // console.error(
+ // `${dbName}: ${envelopeId} can not download contract file, ${error}`
+ // );
+ // continue;
+ // }
+
+ // const fullFilePath = createFolderTree(fileName, filePath);
+
+ // fs.writeFileSync(fullFilePath, buffer);
+ }
+ });
+ }
+
+ //서명 요청 수신
+ if (event === "recipient-delivered") {
+ }
+
+ //서명 부분 거절
+ if (event === "recipient-declined") {
+ await db.transaction(async (tx) => {
+ for (const targetDB of contractList) {
+ const { dbSchma, recipients = [] } = targetDB;
+
+ const [targetContract] = await tx
+ .select()
+ .from(dbSchma)
+ .where(eq(dbSchma.envelopeId, envelopeId))
+ .limit(1);
+
+ const { id, contractId } = targetContract;
+
+ if (contractId === null || contractId === undefined) {
+ continue;
+ }
+
+ const targetRole = recipients.find(
+ (c) => c.recipientId === recipientId
+ );
+
+ if (targetRole) {
+ const { role } = targetRole;
+
+ const safeRole = role as "REQUESTER" | "VENDOR";
+
+ await tx
+ .update(contracts)
+ .set({ status: `${safeRole}_DECLINED_SIGNATURE` })
+ .where(eq(contracts.id, contractId));
+
+ if (["REQUESTER", "VENDOR"].includes(role)) {
+ await tx
+ .update(contractEnvelopes)
+ .set({ envelopeStatus: `${role}_DECLINED` })
+ .where(and(eq(contractEnvelopes.envelopeId, envelopeId)));
+
+ await tx
+ .update(contractSigners)
+ .set({
+ signerStatus: "DECLINED",
+ signedAt: new Date(),
+ })
+ .where(
+ and(
+ eq(contractSigners.envelopeId, id),
+ eq(contractSigners.signerType, safeRole)
+ )
+ );
+ }
+ }
+ }
+ });
+ }
+
+ //서명 부분 완료
+ if (event === "recipient-completed") {
+ await db.transaction(async (tx) => {
+ for (const targetDB of contractList) {
+ const { dbSchma, dbName, recipients = [] } = targetDB;
+
+ const [targetContract] = await tx
+ .select()
+ .from(dbSchma)
+ .where(eq(dbSchma.envelopeId, envelopeId))
+ .limit(1);
+
+ const { id, contractId, fileName, filePath } = targetContract;
+
+ if (contractId === null || contractId === undefined) {
+ continue;
+ }
+
+ const createContractFile = await downloadContractFile(envelopeId);
+
+ const { result, buffer, error } = createContractFile;
+
+ if (!result || !buffer) {
+ console.error(
+ `${dbName}: ${envelopeId} can not download contract file, ${error}`
+ );
+ continue;
+ }
+
+ const fullFilePath = createFolderTree(fileName, filePath);
+
+ fs.writeFileSync(fullFilePath, buffer);
+
+ const targetRole = recipients.find(
+ (c) => c.recipientId === recipientId
+ );
+
+ if (targetRole) {
+ const { role } = targetRole;
+
+ const safeRole = role as "REQUESTER" | "VENDOR";
+
+ await tx
+ .update(contracts)
+ .set({ status: `${safeRole}_FINISHED_SIGNATURE` })
+ .where(eq(contracts.id, contractId));
+
+ if (["REQUESTER", "VENDOR"].includes(role)) {
+ await tx
+ .update(contractEnvelopes)
+ .set({ envelopeStatus: `${role}_FINISHED` })
+ .where(and(eq(contractEnvelopes.envelopeId, envelopeId)));
+
+ await tx
+ .update(contractSigners)
+ .set({ signerStatus: "FINISHED", signedAt: new Date() })
+ .where(
+ and(
+ eq(contractSigners.envelopeId, id),
+ eq(contractSigners.signerType, safeRole)
+ )
+ );
+ }
+ }
+ }
+ });
+ }
+
+ if (event === "envelope-completed") {
+ await db.transaction(async (tx) => {
+ for (const targetDB of contractList) {
+ const { dbSchma, dbName } = targetDB;
+
+ const [targetContract] = await tx
+ .select()
+ .from(dbSchma)
+ .where(eq(dbSchma.envelopeId, envelopeId))
+ .limit(1);
+
+ const { contractId, fileName, filePath } = targetContract;
+
+ if (contractId === null || contractId === undefined) {
+ continue;
+ }
+
+ const createContractFile = await downloadContractFile(envelopeId);
+
+ const { result, buffer, error } = createContractFile;
+
+ if (!result || !buffer) {
+ console.error(
+ `${dbName}: ${envelopeId} can not download contract file, ${error}`
+ );
+ continue;
+ }
+
+ const fullFilePath = createFolderTree(fileName, filePath);
+
+ fs.writeFileSync(fullFilePath, buffer);
+
+ await tx
+ .update(contracts)
+ .set({ status: "COMPLETED_SIGNATURE" })
+ .where(eq(contracts.id, contractId));
+
+ await tx
+ .update(contractEnvelopes)
+ .set({ envelopeStatus: "COMPLETED_SIGNATURE" })
+ .where(and(eq(contractEnvelopes.envelopeId, envelopeId)));
+ }
+ });
+ }
+
+ if (event === "envelope-declined") {
+ }
+
+ return res.status(200).json("OK");
+ } catch (error: any) {
+ return res
+ .status(500)
+ .json({ success: false, message: error?.message || "Unknown error" });
+ }
+}
+
+const createFolderTree = (fileName: string, filePath: string): string => {
+ const cleanedPath = filePath.replace(/^\/+/, "");
+ const dirPath = path.resolve(process.cwd(), "public", cleanedPath); // 예: 'contracts/185/signatures'
+ const fullFilePath = path.join(dirPath, fileName); // 예: 'contracts/185/signatures/xxx.pdf'
+
+ if (!fs.existsSync(dirPath)) {
+ fs.mkdirSync(dirPath, { recursive: true });
+ }
+
+ return fullFilePath;
+};