feat: implement envelope item processing and enhance final envelope retrieval

This commit is contained in:
Catalin Pit
2025-11-03 12:42:47 +02:00
parent b37748654e
commit a9f1e39b10
2 changed files with 65 additions and 8 deletions

View File

@ -10,6 +10,7 @@ import {
} from '@prisma/client'; } from '@prisma/client';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { insertFieldsFromPlaceholdersInPDF } from '@documenso/lib/server-only/pdf/auto-place-fields';
import { normalizePdf as makeNormalizedPdf } from '@documenso/lib/server-only/pdf/normalize-pdf'; import { normalizePdf as makeNormalizedPdf } from '@documenso/lib/server-only/pdf/normalize-pdf';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs'; import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata'; import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
@ -233,7 +234,7 @@ export const createEnvelope = async ({
? await incrementDocumentId().then((v) => v.formattedDocumentId) ? await incrementDocumentId().then((v) => v.formattedDocumentId)
: await incrementTemplateId().then((v) => v.formattedTemplateId); : await incrementTemplateId().then((v) => v.formattedTemplateId);
return await prisma.$transaction(async (tx) => { const createdEnvelope = await prisma.$transaction(async (tx) => {
const envelope = await tx.envelope.create({ const envelope = await tx.envelope.create({
data: { data: {
id: prefixedId('envelope'), id: prefixedId('envelope'),
@ -353,8 +354,12 @@ export const createEnvelope = async ({
recipients: true, recipients: true,
fields: true, fields: true,
folder: true, folder: true,
envelopeItems: true,
envelopeAttachments: true, envelopeAttachments: true,
envelopeItems: {
include: {
documentData: true,
},
},
}, },
}); });
@ -390,4 +395,51 @@ export const createEnvelope = async ({
return createdEnvelope; return createdEnvelope;
}); });
for (const envelopeItem of createdEnvelope.envelopeItems) {
const buffer = await getFileServerSide(envelopeItem.documentData);
// Use normalized PDF if normalizePdf was true, otherwise use original
const pdfToProcess = normalizePdf
? await makeNormalizedPdf(Buffer.from(buffer))
: Buffer.from(buffer);
await insertFieldsFromPlaceholdersInPDF(
pdfToProcess,
userId,
teamId,
{
type: 'envelopeId',
id: createdEnvelope.id,
},
requestMetadata,
envelopeItem.id,
);
}
const finalEnvelope = await prisma.envelope.findFirst({
where: {
id: createdEnvelope.id,
},
include: {
documentMeta: true,
recipients: true,
fields: true,
folder: true,
envelopeAttachments: true,
envelopeItems: {
include: {
documentData: true,
},
},
},
});
if (!finalEnvelope) {
throw new AppError(AppErrorCode.NOT_FOUND, {
message: 'Envelope not found',
});
}
return finalEnvelope;
}; };

View File

@ -63,8 +63,8 @@ type RecipientPlaceholderInfo = {
- Does it handle multiple recipients on the same page? ✅ YES! ✅ - Does it handle multiple recipients on the same page? ✅ YES! ✅
- Does it handle multiple recipients on multiple pages? ✅ YES! ✅ - Does it handle multiple recipients on multiple pages? ✅ YES! ✅
- What happens with incorrect placeholders? E.g. those containing non-accepted properties. - What happens with incorrect placeholders? E.g. those containing non-accepted properties.
- The placeholder data is dynamic. How to handle this parsing? Perhaps we need to do it similar to the fieldMeta parsing. - The placeholder data is dynamic. How to handle this parsing? Perhaps we need to do it similar to the fieldMeta parsing.
- Need to handle envelopes with multiple items. - Need to handle envelopes with multiple items.
*/ */
/* /*
@ -202,9 +202,9 @@ export const extractPlaceholdersFromPDF = async (pdf: Buffer): Promise<Placehold
const placeholderMatches = pageText.matchAll(/{{([^}]+)}}/g); const placeholderMatches = pageText.matchAll(/{{([^}]+)}}/g);
for (const match of placeholderMatches) { for (const placeholderMatch of placeholderMatches) {
const placeholder = match[0]; const placeholder = placeholderMatch[0];
const placeholderData = match[1].split(',').map((part) => part.trim()); const placeholderData = placeholderMatch[1].split(',').map((part) => part.trim());
const [fieldTypeString, recipient, ...fieldMetaData] = placeholderData; const [fieldTypeString, recipient, ...fieldMetaData] = placeholderData;
@ -223,7 +223,12 @@ export const extractPlaceholdersFromPDF = async (pdf: Buffer): Promise<Placehold
Then find the position of where the placeholder ends in the text by adding the length of the placeholder to the index of the placeholder. Then find the position of where the placeholder ends in the text by adding the length of the placeholder to the index of the placeholder.
*/ */
const matchIndex = match.index; const matchIndex = placeholderMatch.index;
if (matchIndex === undefined) {
continue;
}
const placeholderLength = placeholder.length; const placeholderLength = placeholder.length;
const placeholderEndIndex = matchIndex + placeholderLength; const placeholderEndIndex = matchIndex + placeholderLength;