From b831e89f49c1d051226ee80e22b8aaa59e12e6b7 Mon Sep 17 00:00:00 2001 From: chark1es Date: Mon, 16 Jun 2025 01:42:11 -0700 Subject: [PATCH] Update send-reimbursement-email.ts --- .../api/email/send-reimbursement-email.ts | 190 +++++++++++++----- 1 file changed, 136 insertions(+), 54 deletions(-) diff --git a/src/pages/api/email/send-reimbursement-email.ts b/src/pages/api/email/send-reimbursement-email.ts index 5b29bcd..589d79a 100644 --- a/src/pages/api/email/send-reimbursement-email.ts +++ b/src/pages/api/email/send-reimbursement-email.ts @@ -40,8 +40,10 @@ export const POST: APIRoute = async ({ request }) => { // Initialize services const { pb, resend, fromEmail, replyToEmail } = await initializeEmailServices(); - // Authenticate with PocketBase if auth data is provided - authenticatePocketBase(pb, authData); + // Authenticate with PocketBase if auth data is provided (skip for test emails) + if (type !== 'test') { + authenticatePocketBase(pb, authData); + } let success = false; @@ -141,19 +143,51 @@ async function sendStatusChangeEmail(pb: any, resend: any, fromEmail: string, re pocketbaseUrl: import.meta.env.POCKETBASE_URL }); - // Get reimbursement details - console.log('๐Ÿ” Fetching reimbursement details for:', data.reimbursementId); - const reimbursement = await pb.collection('reimbursement').getOne(data.reimbursementId); - console.log('โœ… Reimbursement fetched:', { id: reimbursement.id, title: reimbursement.title }); + // Check if this is a test scenario + const isTestData = data.reimbursementId?.includes('test') || data.reimbursementId === 'test-id'; - // Get submitter user details - console.log('๐Ÿ‘ค Fetching user details for:', reimbursement.submitted_by); - const user = await pb.collection('users').getOne(reimbursement.submitted_by); - if (!user || !user.email) { - console.error('โŒ User not found or no email:', reimbursement.submitted_by); - return false; + let reimbursement, user; + + if (isTestData) { + console.log('๐Ÿงช Using test data for demonstration'); + // Use mock data for testing + reimbursement = { + id: data.reimbursementId, + title: 'Test Reimbursement Request', + total_amount: 125.50, + date_of_purchase: new Date().toISOString(), + department: 'general', + payment_method: 'Personal Card', + status: data.previousStatus || 'submitted', + submitted_by: 'test-user-id', + audit_notes: '' + }; + + user = { + id: 'test-user-id', + name: 'Test User', + email: data.additionalContext?.testEmail || 'test@example.com' + }; + + console.log('โœ… Test data prepared:', { + reimbursementTitle: reimbursement.title, + userEmail: user.email + }); + } else { + // Get real reimbursement details + console.log('๐Ÿ” Fetching reimbursement details for:', data.reimbursementId); + reimbursement = await pb.collection('reimbursement').getOne(data.reimbursementId); + console.log('โœ… Reimbursement fetched:', { id: reimbursement.id, title: reimbursement.title }); + + // Get submitter user details + console.log('๐Ÿ‘ค Fetching user details for:', reimbursement.submitted_by); + user = await pb.collection('users').getOne(reimbursement.submitted_by); + if (!user || !user.email) { + console.error('โŒ User not found or no email:', reimbursement.submitted_by); + return false; + } + console.log('โœ… User fetched:', { id: user.id, name: user.name, email: user.email }); } - console.log('โœ… User fetched:', { id: user.id, name: user.name, email: user.email }); // Get changed by user name if provided let changedByName = 'System'; @@ -177,7 +211,39 @@ async function sendStatusChangeEmail(pb: any, resend: any, fromEmail: string, re status: data.newStatus }); - // Helper function to generate status progress bar HTML + // Add audit note when reimbursement is declined (skip for test data) + if (data.newStatus === 'rejected' && !isTestData) { + try { + console.log('๐Ÿ“ Adding audit note for declined reimbursement...'); + + // Prepare audit note content + let auditNote = `Status changed to REJECTED by ${changedByName}`; + if (data.additionalContext?.rejectionReason) { + auditNote += `\nRejection Reason: ${data.additionalContext.rejectionReason}`; + } + auditNote += `\nDate: ${new Date().toLocaleString()}`; + + // Get existing audit notes or initialize empty string + const existingNotes = reimbursement.audit_notes || ''; + const updatedNotes = existingNotes + ? `${existingNotes}\n\n--- DECLINE RECORD ---\n${auditNote}` + : `--- DECLINE RECORD ---\n${auditNote}`; + + // Update the reimbursement record with the new audit notes + await pb.collection('reimbursement').update(data.reimbursementId, { + audit_notes: updatedNotes + }); + + console.log('โœ… Audit note added successfully for declined reimbursement'); + } catch (auditError) { + console.error('โŒ Failed to add audit note for declined reimbursement:', auditError); + // Don't fail the entire email process if audit note fails + } + } else if (data.newStatus === 'rejected' && isTestData) { + console.log('๐Ÿงช Skipping audit note update for test data'); + } + + // Helper function to generate status progress bar HTML (email-compatible) function generateStatusProgressBar(currentStatus: string): string { const statusOrder = ['submitted', 'under_review', 'approved', 'in_progress', 'paid']; const rejectedStatus = ['submitted', 'under_review', 'rejected']; @@ -187,10 +253,10 @@ async function sendStatusChangeEmail(pb: any, resend: any, fromEmail: string, re const statusIcons: Record = { submitted: 'โ†’', - under_review: 'โ—‹', + under_review: 'โ€ข', approved: 'โœ“', rejected: 'โœ—', - in_progress: 'โ—', + in_progress: 'โ—‹', paid: 'โœ“' }; @@ -208,8 +274,11 @@ async function sendStatusChangeEmail(pb: any, resend: any, fromEmail: string, re let progressBarHtml = `

Request Progress

-
-
+ + + + + `; statuses.forEach((status, index) => { @@ -245,51 +314,64 @@ async function sendStatusChangeEmail(pb: any, resend: any, fromEmail: string, re lineColor = '#e2e8f0'; } + // Status circle progressBarHtml += ` -
-
- ${statusIcons[status]} -
- - ${statusLabels[status]} - -
+ `; - // Add colored line segment for active states - if (index < statuses.length - 1 && isActive) { + // Connecting line (except for the last status) + if (index < statuses.length - 1) { + const nextIsActive = (index + 1) <= currentIndex; + const connectionColor = nextIsActive ? lineColor : '#e2e8f0'; + progressBarHtml += ` -
+ `; } }); progressBarHtml += ` - + +
+
+
+ ${statusIcons[status]} +
+
+ ${statusLabels[status]} +
+
+
+
+
`;