This commit is contained in:
2025-06-11 13:54:04 +02:00
parent fca6321dcf
commit 0b6601fabc
8 changed files with 65 additions and 292 deletions

View File

@@ -13,7 +13,6 @@ interface EmailMessage {
timestamp: string;
direction: 'sent' | 'received';
threadId?: string;
attachments?: any[];
}
export default defineEventHandler(async (event) => {
@@ -305,15 +304,6 @@ async function fetchImapEmails(
return;
}
// Extract attachments
const attachments = parsed.attachments ? parsed.attachments.map((att: any) => ({
filename: att.filename || 'attachment',
name: att.filename || 'attachment',
size: att.size || 0,
type: att.contentType || 'application/octet-stream',
cid: att.cid || undefined
})) : [];
const email: EmailMessage = {
id: parsed.messageId || `${Date.now()}-${seqno}`,
from: fromEmail,
@@ -322,8 +312,7 @@ async function fetchImapEmails(
body: parsed.text || '',
html: parsed.html || undefined,
timestamp: parsed.date?.toISOString() || new Date().toISOString(),
direction: fromEmail.toLowerCase().includes(userEmail.toLowerCase()) ? 'sent' : 'received',
attachments: attachments
direction: fromEmail.toLowerCase().includes(userEmail.toLowerCase()) ? 'sent' : 'received'
};
if (parsed.headers.has('in-reply-to')) {

View File

@@ -29,9 +29,6 @@ export default defineEventHandler(async (event) => {
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
}
// Set longer timeout for this endpoint to prevent 502 errors
event.node.res.setTimeout(60000); // 60 seconds
try {
const body = await readBody(event);
const { interestId } = body;
@@ -46,83 +43,19 @@ export default defineEventHandler(async (event) => {
throw createError({ statusCode: 404, statusMessage: "Interest not found" });
}
// Documenso API configuration (declare early for use in regeneration)
const documensoApiKey = process.env.NUXT_DOCUMENSO_API_KEY;
const documensoBaseUrl = process.env.NUXT_DOCUMENSO_BASE_URL;
// Check if EOI already exists (has signature links)
const hasExistingEOI = !!(interest['Signature Link Client'] && interest['Signature Link CC'] && interest['Signature Link Developer']);
if (hasExistingEOI) {
console.log('EOI already exists, checking if regeneration is needed');
// For regeneration, we need to delete the old document first
const regenerateRequested = body.regenerate === true;
if (!regenerateRequested) {
console.log('Returning existing EOI links');
return {
success: true,
documentId: 'existing',
clientSigningUrl: interest['Signature Link Client'],
signingLinks: {
'Client': interest['Signature Link Client'],
'CC': interest['Signature Link CC'],
'Developer': interest['Signature Link Developer']
}
};
} else {
console.log('Regeneration requested, deleting old document first');
// Try to delete the old document from Documenso
try {
const externalId = `loi-${interestId}`;
// Import the delete utility functions
const { getDocumesoDocumentByExternalId, checkDocumentSignatureStatus } = await import('~/server/utils/documeso');
const document = await getDocumesoDocumentByExternalId(externalId);
if (document) {
// Check if all parties have signed
const signatureStatus = await checkDocumentSignatureStatus(document.id);
if (signatureStatus.allSigned) {
throw createError({
statusCode: 403,
statusMessage: 'Cannot regenerate: All parties have already signed this document',
});
}
console.log('Deleting old document from Documenso:', document.id);
const deleteResponse = await fetch(`${documensoBaseUrl}/api/v1/documents/${document.id}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${documensoApiKey}`,
'Content-Type': 'application/json'
}
});
if (!deleteResponse.ok) {
console.warn('Failed to delete old document from Documenso, continuing with new generation');
} else {
console.log('Successfully deleted old document from Documenso');
}
}
} catch (error: any) {
console.warn('Error during old document cleanup:', error.message);
// Continue with new document generation even if cleanup fails
if (interest['Signature Link Client'] && interest['Signature Link CC'] && interest['Signature Link Developer']) {
console.log('EOI already exists, returning existing links');
return {
success: true,
documentId: 'existing',
clientSigningUrl: interest['Signature Link Client'],
signingLinks: {
'Client': interest['Signature Link Client'],
'CC': interest['Signature Link CC'],
'Developer': interest['Signature Link Developer']
}
// Reset signature links so new ones will be generated
await updateInterest(interestId, {
'Signature Link Client': undefined,
'Signature Link CC': undefined,
'Signature Link Developer': undefined
});
console.log('Old document cleanup completed, proceeding with new generation');
}
};
}
// Validate required fields
@@ -172,6 +105,8 @@ export default defineEventHandler(async (event) => {
const berthNumbers = berths.map(b => b['Mooring Number']).join(', ');
// Documenso API configuration
const documensoApiKey = process.env.NUXT_DOCUMENSO_API_KEY;
const documensoBaseUrl = process.env.NUXT_DOCUMENSO_BASE_URL;
const templateId = '9';
if (!documensoApiKey || !documensoBaseUrl) {

View File

@@ -181,8 +181,7 @@ export default defineEventHandler(async (event) => {
html: htmlBody,
timestamp: new Date().toISOString(),
direction: 'sent',
interestId: interestId,
attachments: attachments // Include attachment info
interestId: interestId
};
const objectName = `interest-${interestId}/${Date.now()}-sent.json`;

View File

@@ -1,148 +0,0 @@
import { getInterestById, updateInterest } from '~/server/utils/nocodb';
import { getDocumesoDocumentByExternalId, checkDocumentSignatureStatus } from '~/server/utils/documeso';
export default defineEventHandler(async (event) => {
const xTagHeader = getRequestHeader(event, "x-tag");
console.log('[EOI Delete Generated] Request received with x-tag:', xTagHeader);
if (!xTagHeader || (xTagHeader !== "094ut234" && xTagHeader !== "pjnvü1230")) {
console.error('[EOI Delete Generated] Authentication failed - invalid x-tag');
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
}
try {
const body = await readBody(event);
const { interestId } = body;
console.log('[EOI Delete Generated] Interest ID:', interestId);
if (!interestId) {
console.error('[EOI Delete Generated] No interest ID provided');
throw createError({
statusCode: 400,
statusMessage: 'Interest ID is required',
});
}
// Get current interest data
const interest = await getInterestById(interestId);
if (!interest) {
throw createError({
statusCode: 404,
statusMessage: 'Interest not found',
});
}
// Check if there are signature links (indicating a generated document)
const hasSignatureLinks = !!(interest['Signature Link Client'] ||
interest['Signature Link CC'] ||
interest['Signature Link Developer']);
if (!hasSignatureLinks) {
throw createError({
statusCode: 400,
statusMessage: 'No generated EOI document found for this interest',
});
}
// Check signature status to prevent deletion of fully signed documents
const externalId = `loi-${interestId}`;
let documentId: number | null = null;
try {
const document = await getDocumesoDocumentByExternalId(externalId);
if (document) {
documentId = document.id;
// Check if all parties have signed
const signatureStatus = await checkDocumentSignatureStatus(documentId);
if (signatureStatus.allSigned) {
throw createError({
statusCode: 403,
statusMessage: 'Cannot delete: All parties have already signed this document',
});
}
console.log('[EOI Delete Generated] Document found in Documenso:', documentId);
console.log('[EOI Delete Generated] Signature status:', {
allSigned: signatureStatus.allSigned,
clientSigned: signatureStatus.clientSigned,
signedCount: signatureStatus.signedRecipients.length,
unsignedCount: signatureStatus.unsignedRecipients.length
});
}
} catch (error: any) {
console.warn('[EOI Delete Generated] Could not find or check Documenso document:', error.message);
// Continue with deletion even if Documenso document not found
}
// Delete document from Documenso if it exists
if (documentId) {
try {
const documensoApiKey = process.env.NUXT_DOCUMENSO_API_KEY;
const documensoBaseUrl = process.env.NUXT_DOCUMENSO_BASE_URL;
if (!documensoApiKey || !documensoBaseUrl) {
console.error('[EOI Delete Generated] Documenso configuration missing');
throw createError({
statusCode: 500,
statusMessage: 'Documenso configuration missing',
});
}
console.log('[EOI Delete Generated] Deleting document from Documenso:', documentId);
const deleteResponse = await fetch(`${documensoBaseUrl}/api/v1/documents/${documentId}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${documensoApiKey}`,
'Content-Type': 'application/json'
}
});
if (!deleteResponse.ok) {
const errorText = await deleteResponse.text();
console.error('[EOI Delete Generated] Failed to delete from Documenso:', errorText);
throw new Error(`Failed to delete document from Documenso: ${deleteResponse.statusText}`);
}
console.log('[EOI Delete Generated] Successfully deleted document from Documenso');
} catch (error: any) {
console.error('[EOI Delete Generated] Error deleting from Documenso:', error);
// Don't throw here - continue with database cleanup even if Documenso deletion fails
}
}
// Reset interest fields
const updateData = {
'EOI Status': 'Awaiting Further Details' as const,
'Sales Process Level': 'Specific Qualified Interest' as const,
'EOI Time Sent': undefined,
'Signature Link Client': undefined,
'Signature Link CC': undefined,
'Signature Link Developer': undefined,
'Documeso ID': undefined,
'reminder_enabled': false
};
console.log('[EOI Delete Generated] Resetting interest fields');
// Update the interest
await updateInterest(interestId, updateData);
console.log('[EOI Delete Generated] Delete completed successfully');
return {
success: true,
message: 'Generated EOI document deleted successfully',
};
} catch (error: any) {
console.error('[EOI Delete Generated] Failed to delete generated EOI document:', error);
console.error('[EOI Delete Generated] Error stack:', error.stack);
throw createError({
statusCode: error.statusCode || 500,
statusMessage: error.statusMessage || error.message || 'Failed to delete generated EOI document',
});
}
});

View File

@@ -196,7 +196,6 @@ export const createInterest = async (data: Partial<Interest>) => {
"Date Added",
"Width",
"Depth",
"Created At",
"Source",
"Contact Method Preferred",
"Lead Category",
@@ -214,11 +213,6 @@ export const createInterest = async (data: Partial<Interest>) => {
}
}
// Set Created At to current timestamp if not provided
if (!cleanData["Created At"]) {
cleanData["Created At"] = new Date().toISOString();
}
// Remove any computed or relation fields that shouldn't be sent
delete cleanData.Id;
delete cleanData.Berths;