diff --git a/server/api/debug/test-documenso-connectivity.ts b/server/api/debug/test-documenso-connectivity.ts new file mode 100644 index 0000000..a3fa8ed --- /dev/null +++ b/server/api/debug/test-documenso-connectivity.ts @@ -0,0 +1,57 @@ +export default defineEventHandler(async (event) => { + console.log('[DEBUG] Testing Documenso connectivity...') + + try { + // Test basic connectivity to Documenso + const documensoBaseUrl = process.env.NUXT_DOCUMENSO_BASE_URL; + const documensoApiKey = process.env.NUXT_DOCUMENSO_API_KEY; + + if (!documensoBaseUrl || !documensoApiKey) { + return { + success: false, + message: 'Documenso configuration missing', + error: { + message: 'NUXT_DOCUMENSO_BASE_URL or NUXT_DOCUMENSO_API_KEY environment variables not set' + } + } + } + + const testUrl = `${documensoBaseUrl}/api/v1/documents` + + const response = await $fetch(testUrl, { + method: 'GET', + headers: { + 'Authorization': `Bearer ${documensoApiKey}`, + 'Content-Type': 'application/json' + }, + params: { + perPage: 1 // Just get 1 document to test connectivity + }, + retry: 0 + }) as any + + return { + success: true, + message: 'Documenso connectivity successful', + endpoint: testUrl, + response: { + total: response.total || 0, + documentsFound: response.documents ? response.documents.length : 0, + statusCode: 200 + } + } + } catch (error: any) { + console.error('[DEBUG] Documenso connectivity test failed:', error) + + return { + success: false, + message: 'Documenso connectivity failed', + error: { + message: error.message, + status: error.status, + statusCode: error.statusCode, + cause: error.cause?.message + } + } + } +}) diff --git a/server/api/eoi/check-signature-status.ts b/server/api/eoi/check-signature-status.ts index f47a903..22df176 100644 --- a/server/api/eoi/check-signature-status.ts +++ b/server/api/eoi/check-signature-status.ts @@ -1,4 +1,4 @@ -import { getDocumesoDocumentByExternalId, checkDocumentSignatureStatus } from '~/server/utils/documeso'; +import { getDocumensoDocumentByExternalId, checkDocumentSignatureStatus } from '~/server/utils/documeso'; import { getInterestById, updateInterest } from '~/server/utils/nocodb'; import { requireAuth } from '~/server/utils/auth'; import type { InterestSalesProcessLevel, EOIStatus } from '~/utils/types'; @@ -89,7 +89,7 @@ export default defineEventHandler(async (event) => { // Otherwise, try to find by external ID (using interestId) - fallback method console.log('[check-signature-status] No documensoID stored, trying external ID fallback'); const externalId = `loi-${interestId}`; - const document = await getDocumesoDocumentByExternalId(externalId); + const document = await getDocumensoDocumentByExternalId(externalId); if (!document) { console.log('[check-signature-status] No document found by external ID either'); diff --git a/server/api/eoi/delete-generated-document.ts b/server/api/eoi/delete-generated-document.ts index 6e0ad61..f926350 100644 --- a/server/api/eoi/delete-generated-document.ts +++ b/server/api/eoi/delete-generated-document.ts @@ -55,8 +55,13 @@ export default defineEventHandler(async (event) => { } } catch (error: any) { console.error('[Delete Generated EOI] Failed to check signature status:', error); - // If we can't check status, we'll proceed with deletion but warn - console.warn('[Delete Generated EOI] Proceeding with deletion despite signature status check failure'); + + // 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 diff --git a/server/api/eoi/send-reminders.ts b/server/api/eoi/send-reminders.ts index 6732475..d6c578f 100644 --- a/server/api/eoi/send-reminders.ts +++ b/server/api/eoi/send-reminders.ts @@ -1,5 +1,5 @@ import { requireAuth } from '~/server/utils/auth'; -import { getDocumesoDocument, checkDocumentSignatureStatus, formatRecipientName } from '~/server/utils/documeso'; +import { getDocumensoDocument, checkDocumentSignatureStatus, formatRecipientName } from '~/server/utils/documeso'; import { getInterestById } from '~/server/utils/nocodb'; import { sendEmail } from '~/server/utils/email'; @@ -45,7 +45,7 @@ export default defineEventHandler(async (event) => { } // Get document and check signature status - const document = await getDocumesoDocument(parseInt(documentId)); + const document = await getDocumensoDocument(parseInt(documentId)); const status = await checkDocumentSignatureStatus(parseInt(documentId)); const emailsToSend: ReminderEmail[] = []; diff --git a/server/api/eoi/validate-document.ts b/server/api/eoi/validate-document.ts index c9205d7..01c6554 100644 --- a/server/api/eoi/validate-document.ts +++ b/server/api/eoi/validate-document.ts @@ -1,5 +1,5 @@ import { getInterestById, updateInterest } from '~/server/utils/nocodb'; -import { getDocumesoDocument } from '~/server/utils/documeso'; +import { getDocumensoDocument } from '~/server/utils/documeso'; import { requireAuth } from '~/server/utils/auth'; import type { InterestSalesProcessLevel, EOIStatus } from '~/utils/types'; @@ -52,7 +52,7 @@ export default defineEventHandler(async (event) => { try { console.log('[Validate Document] Checking document existence in Documenso'); - const document = await getDocumesoDocument(parseInt(documensoID)); + const document = await getDocumensoDocument(parseInt(documensoID)); documentStatus = document.status; console.log('[Validate Document] Document exists with status:', documentStatus); } catch (error: any) { diff --git a/server/utils/documeso.ts b/server/utils/documeso.ts index 9af1af6..20e692d 100644 --- a/server/utils/documeso.ts +++ b/server/utils/documeso.ts @@ -1,10 +1,10 @@ -// Documeso API client utilities -interface DocumesoConfig { +// Documenso API client utilities +interface DocumensoConfig { apiUrl: string; apiKey: string; } -interface DocumesoRecipient { +interface DocumensoRecipient { id: number; documentId: number; email: string; @@ -19,7 +19,7 @@ interface DocumesoRecipient { signingUrl: string; } -interface DocumesoDocument { +interface DocumensoDocument { id: number; externalId: string; userId: number; @@ -30,30 +30,40 @@ interface DocumesoDocument { createdAt: string; updatedAt: string; completedAt: string | null; - recipients: DocumesoRecipient[]; + recipients: DocumensoRecipient[]; } -interface DocumesoListResponse { - documents: DocumesoDocument[]; +interface DocumensoListResponse { + documents: DocumensoDocument[]; total: number; page: number; perPage: number; } -// Get Documeso configuration -const getDocumesoConfig = (): DocumesoConfig => { +// Get Documenso configuration from environment variables +const getDocumensoConfig = (): DocumensoConfig => { + const apiUrl = process.env.NUXT_DOCUMENSO_BASE_URL; + const apiKey = process.env.NUXT_DOCUMENSO_API_KEY; + + if (!apiUrl || !apiKey) { + throw createError({ + statusCode: 500, + statusMessage: 'Documenso configuration missing. Please check NUXT_DOCUMENSO_BASE_URL and NUXT_DOCUMENSO_API_KEY environment variables.' + }); + } + return { - apiUrl: 'https://signatures.portnimara.dev/api/v1', - apiKey: 'Bearer api_malptg62zqyb0wrp' + apiUrl: `${apiUrl}/api/v1`, + apiKey: `Bearer ${apiKey}` }; }; // Fetch a single document by ID -export const getDocumesoDocument = async (documentId: number): Promise => { - const config = getDocumesoConfig(); +export const getDocumensoDocument = async (documentId: number): Promise => { + const config = getDocumensoConfig(); try { - const response = await $fetch(`${config.apiUrl}/documents/${documentId}`, { + const response = await $fetch(`${config.apiUrl}/documents/${documentId}`, { headers: { 'Authorization': config.apiKey, 'Content-Type': 'application/json' @@ -62,17 +72,17 @@ export const getDocumesoDocument = async (documentId: number): Promise => { - const config = getDocumesoConfig(); +export const searchDocumensoDocuments = async (externalId?: string): Promise => { + const config = getDocumensoConfig(); try { - const response = await $fetch(`${config.apiUrl}/documents`, { + const response = await $fetch(`${config.apiUrl}/documents`, { headers: { 'Authorization': config.apiKey, 'Content-Type': 'application/json' @@ -84,37 +94,37 @@ export const searchDocumesoDocuments = async (externalId?: string): Promise doc.externalId === externalId); + return response.documents.filter((doc: DocumensoDocument) => doc.externalId === externalId); } return response.documents; } catch (error) { - console.error('Failed to search Documeso documents:', error); + console.error('Failed to search Documenso documents:', error); throw error; } }; // Get document by external ID (e.g., 'loi-94') -export const getDocumesoDocumentByExternalId = async (externalId: string): Promise => { - const documents = await searchDocumesoDocuments(externalId); +export const getDocumensoDocumentByExternalId = async (externalId: string): Promise => { + const documents = await searchDocumensoDocuments(externalId); return documents.length > 0 ? documents[0] : null; }; // Check signature status for a document export const checkDocumentSignatureStatus = async (documentId: number): Promise<{ documentStatus: string; - unsignedRecipients: DocumesoRecipient[]; - signedRecipients: DocumesoRecipient[]; + unsignedRecipients: DocumensoRecipient[]; + signedRecipients: DocumensoRecipient[]; clientSigned: boolean; allSigned: boolean; }> => { - const document = await getDocumesoDocument(documentId); + const document = await getDocumensoDocument(documentId); - const unsignedRecipients = document.recipients.filter(r => r.signingStatus === 'NOT_SIGNED'); - const signedRecipients = document.recipients.filter(r => r.signingStatus === 'SIGNED'); + const unsignedRecipients = document.recipients.filter((r: DocumensoRecipient) => r.signingStatus === 'NOT_SIGNED'); + const signedRecipients = document.recipients.filter((r: DocumensoRecipient) => r.signingStatus === 'SIGNED'); // Check if client (signingOrder = 1) has signed - const clientRecipient = document.recipients.find(r => r.signingOrder === 1); + const clientRecipient = document.recipients.find((r: DocumensoRecipient) => r.signingOrder === 1); const clientSigned = clientRecipient ? clientRecipient.signingStatus === 'SIGNED' : false; const allSigned = unsignedRecipients.length === 0; @@ -129,7 +139,7 @@ export const checkDocumentSignatureStatus = async (documentId: number): Promise< }; // Get recipients who need to sign (excluding client) -export const getRecipientsToRemind = async (documentId: number): Promise => { +export const getRecipientsToRemind = async (documentId: number): Promise => { const status = await checkDocumentSignatureStatus(documentId); // Only remind if client has signed @@ -138,16 +148,16 @@ export const getRecipientsToRemind = async (documentId: number): Promise 1 - return status.unsignedRecipients.filter(r => r.signingOrder > 1); + return status.unsignedRecipients.filter((r: DocumensoRecipient) => r.signingOrder > 1); }; // Format recipient name for emails -export const formatRecipientName = (recipient: DocumesoRecipient): string => { +export const formatRecipientName = (recipient: DocumensoRecipient): string => { const firstName = recipient.name.split(' ')[0]; return firstName; }; // Get signing URL for a recipient -export const getSigningUrl = (recipient: DocumesoRecipient): string => { +export const getSigningUrl = (recipient: DocumensoRecipient): string => { return recipient.signingUrl; };