242 lines
9.5 KiB
TypeScript
242 lines
9.5 KiB
TypeScript
import { requireAuth } from '~/server/utils/auth';
|
|
import { getInterestById, updateInterest } from '~/server/utils/nocodb';
|
|
import { checkDocumentSignatureStatus } from '~/server/utils/documeso';
|
|
import type { InterestSalesProcessLevel, EOIStatus } from '~/utils/types';
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
// Check authentication (x-tag header OR Keycloak session)
|
|
await requireAuth(event);
|
|
|
|
console.log('[Delete Generated EOI] Request received');
|
|
|
|
try {
|
|
const body = await readBody(event);
|
|
const { interestId } = body;
|
|
const query = getQuery(event);
|
|
|
|
console.log('[Delete Generated EOI] Interest ID:', interestId);
|
|
|
|
if (!interestId) {
|
|
console.error('[Delete Generated EOI] 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',
|
|
});
|
|
}
|
|
|
|
const documensoID = interest['documensoID'];
|
|
console.log('[Delete Generated EOI] Documenso ID:', documensoID);
|
|
|
|
if (!documensoID) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'No generated document found to delete',
|
|
});
|
|
}
|
|
|
|
// Check if document is fully signed - prevent deletion if it is
|
|
try {
|
|
const signatureStatus = await checkDocumentSignatureStatus(parseInt(documensoID));
|
|
console.log('[Delete Generated EOI] Signature status:', signatureStatus);
|
|
|
|
if (signatureStatus.allSigned) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'Cannot delete a fully signed document. All parties have already signed.',
|
|
});
|
|
}
|
|
} catch (error: any) {
|
|
console.error('[Delete Generated EOI] Failed to check signature status:', error);
|
|
|
|
// If it's a 404 error, the document is already gone from Documenso, so we can proceed with cleanup
|
|
if (error.status === 404 || error.statusCode === 404 || error.message?.includes('404')) {
|
|
console.log('[Delete Generated EOI] Document not found in Documenso (404) - proceeding with database cleanup');
|
|
} else {
|
|
console.warn('[Delete Generated EOI] Proceeding with deletion despite signature status check failure');
|
|
}
|
|
}
|
|
|
|
// Delete document from Documenso
|
|
const documensoApiKey = process.env.NUXT_DOCUMENSO_API_KEY;
|
|
const documensoBaseUrl = process.env.NUXT_DOCUMENSO_BASE_URL;
|
|
|
|
if (!documensoApiKey || !documensoBaseUrl) {
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: "Documenso configuration missing. Please check NUXT_DOCUMENSO_API_KEY and NUXT_DOCUMENSO_BASE_URL environment variables."
|
|
});
|
|
}
|
|
|
|
console.log('[Delete Generated EOI] Deleting document from Documenso');
|
|
let documensoDeleteSuccessful = false;
|
|
let retryCount = 0;
|
|
const maxRetries = 3;
|
|
|
|
// Retry logic for temporary failures
|
|
while (!documensoDeleteSuccessful && retryCount < maxRetries) {
|
|
try {
|
|
const deleteResponse = await fetch(`${documensoBaseUrl}/api/v1/documents/${documensoID}`, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'Authorization': `Bearer ${documensoApiKey}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
|
|
const responseStatus = deleteResponse.status;
|
|
let errorDetails = '';
|
|
|
|
try {
|
|
errorDetails = await deleteResponse.text();
|
|
} catch {
|
|
errorDetails = 'No error details available';
|
|
}
|
|
|
|
if (!deleteResponse.ok) {
|
|
console.error(`[Delete Generated EOI] Documenso deletion failed (attempt ${retryCount + 1}/${maxRetries}):`, {
|
|
status: responseStatus,
|
|
statusText: deleteResponse.statusText,
|
|
details: errorDetails
|
|
});
|
|
|
|
// Handle specific status codes
|
|
switch (responseStatus) {
|
|
case 404:
|
|
// Document already deleted - this is fine
|
|
console.log('[Delete Generated EOI] Document already deleted from Documenso (404) - proceeding with database cleanup');
|
|
documensoDeleteSuccessful = true;
|
|
break;
|
|
|
|
case 403:
|
|
// Permission denied - document might be in a protected state
|
|
console.warn('[Delete Generated EOI] Permission denied (403) - document may be in a protected state');
|
|
throw createError({
|
|
statusCode: 403,
|
|
statusMessage: 'Cannot delete document - it may be fully signed or in a protected state',
|
|
});
|
|
|
|
case 500:
|
|
case 502:
|
|
case 503:
|
|
case 504:
|
|
// Server errors - retry if we haven't exceeded retries
|
|
if (retryCount < maxRetries - 1) {
|
|
console.log(`[Delete Generated EOI] Server error (${responseStatus}) - retrying in ${(retryCount + 1) * 2} seconds...`);
|
|
await new Promise(resolve => setTimeout(resolve, (retryCount + 1) * 2000)); // Exponential backoff
|
|
retryCount++;
|
|
continue;
|
|
} else {
|
|
console.error('[Delete Generated EOI] Max retries exceeded for server error');
|
|
// Allow proceeding with cleanup for server errors after retries
|
|
if (query.forceCleanup === 'true') {
|
|
console.warn('[Delete Generated EOI] Force cleanup enabled - proceeding despite Documenso error');
|
|
documensoDeleteSuccessful = true;
|
|
break;
|
|
}
|
|
throw new Error(`Documenso server error after ${maxRetries} attempts (${responseStatus}): ${errorDetails}`);
|
|
}
|
|
|
|
default:
|
|
// Other errors - don't retry
|
|
throw new Error(`Documenso API error (${responseStatus}): ${errorDetails || deleteResponse.statusText}`);
|
|
}
|
|
} else {
|
|
console.log('[Delete Generated EOI] Successfully deleted document from Documenso');
|
|
documensoDeleteSuccessful = true;
|
|
}
|
|
} catch (error: any) {
|
|
console.error(`[Delete Generated EOI] Documenso deletion error (attempt ${retryCount + 1}/${maxRetries}):`, error);
|
|
|
|
// Network errors - retry if we haven't exceeded retries
|
|
if (error.code === 'ECONNREFUSED' || error.code === 'ETIMEDOUT' || error.code === 'ENOTFOUND') {
|
|
if (retryCount < maxRetries - 1) {
|
|
console.log(`[Delete Generated EOI] Network error - retrying in ${(retryCount + 1) * 2} seconds...`);
|
|
await new Promise(resolve => setTimeout(resolve, (retryCount + 1) * 2000));
|
|
retryCount++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Check if it's a 404 error wrapped in another error
|
|
if (error.message?.includes('404') || error.status === 404 || error.statusCode === 404) {
|
|
console.log('[Delete Generated EOI] Document not found in Documenso - proceeding with database cleanup');
|
|
documensoDeleteSuccessful = true;
|
|
break;
|
|
}
|
|
|
|
// Check if force cleanup is enabled
|
|
const query = getQuery(event);
|
|
if (query.forceCleanup === 'true') {
|
|
console.warn('[Delete Generated EOI] Force cleanup enabled - proceeding despite Documenso error:', error.message);
|
|
documensoDeleteSuccessful = true;
|
|
break;
|
|
}
|
|
|
|
// Don't wrap error messages multiple times
|
|
if (error.statusCode) {
|
|
throw error;
|
|
}
|
|
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: error.message || 'Failed to communicate with Documenso API',
|
|
});
|
|
}
|
|
}
|
|
|
|
if (!documensoDeleteSuccessful) {
|
|
const query = getQuery(event);
|
|
if (query.forceCleanup === 'true') {
|
|
console.warn('[Delete Generated EOI] Force cleanup enabled - proceeding with database cleanup despite Documenso failure');
|
|
documensoDeleteSuccessful = true;
|
|
} else {
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: 'Failed to delete document from Documenso after multiple attempts. You can add ?forceCleanup=true to force database cleanup.',
|
|
});
|
|
}
|
|
}
|
|
|
|
// Reset interest fields
|
|
const updateData = {
|
|
'EOI Status': 'Awaiting Further Details' as EOIStatus,
|
|
'Sales Process Level': 'Specific Qualified Interest' as InterestSalesProcessLevel,
|
|
'EOI Time Sent': undefined,
|
|
'Signature Link Client': undefined,
|
|
'Signature Link CC': undefined,
|
|
'Signature Link Developer': undefined,
|
|
'EmbeddedSignatureLinkClient': undefined,
|
|
'EmbeddedSignatureLinkCC': undefined,
|
|
'EmbeddedSignatureLinkDeveloper': undefined,
|
|
'documensoID': undefined
|
|
};
|
|
|
|
console.log('[Delete Generated EOI] Resetting interest fields');
|
|
|
|
// Update the interest
|
|
await updateInterest(interestId, updateData);
|
|
|
|
console.log('[Delete Generated EOI] Delete completed successfully');
|
|
return {
|
|
success: true,
|
|
message: 'Generated EOI document deleted successfully',
|
|
};
|
|
} catch (error: any) {
|
|
console.error('[Delete Generated EOI] Failed to delete generated EOI document:', error);
|
|
console.error('[Delete Generated EOI] Error stack:', error.stack);
|
|
throw createError({
|
|
statusCode: error.statusCode || 500,
|
|
statusMessage: error.statusMessage || error.message || 'Failed to delete generated EOI document',
|
|
});
|
|
}
|
|
});
|