// server/api/members/update-overdue-statuses.post.ts // Helper function to calculate overdue duration function calculateOverdueDuration(dueDate: Date, today: Date): { years: number; months: number; totalMonths: number; formattedDuration: string; } { const diffTime = today.getTime() - dueDate.getTime(); const diffMonths = Math.floor(diffTime / (1000 * 60 * 60 * 24 * 30.44)); // Average days per month const years = Math.floor(diffMonths / 12); const months = diffMonths % 12; let formattedDuration = ''; if (years > 0) { formattedDuration += `${years} year${years !== 1 ? 's' : ''}`; if (months > 0) { formattedDuration += ` ${months} month${months !== 1 ? 's' : ''}`; } } else { formattedDuration = `${diffMonths} month${diffMonths !== 1 ? 's' : ''}`; } return { years, months, totalMonths: diffMonths, formattedDuration: `${formattedDuration} overdue` }; } export default defineEventHandler(async (event) => { try { const { getMembers, updateMember } = await import('~/server/utils/nocodb'); // Get all members const allMembers = await getMembers(); if (!allMembers?.list) { return { success: true, data: { updatedCount: 0 }, message: 'No members found' }; } const today = new Date(); const membersToUpdate: any[] = []; const overdueDetails: any[] = []; for (const member of allMembers.list) { // Skip if already inactive if (member.membership_status === 'Inactive') { // Still check if this inactive member is overdue to include in details let overdueDuration = null; if (member.current_year_dues_paid === 'true' && member.membership_date_paid) { const lastPaidDate = new Date(member.membership_date_paid); const oneYearFromPayment = new Date(lastPaidDate); oneYearFromPayment.setFullYear(oneYearFromPayment.getFullYear() + 1); if (today > oneYearFromPayment) { overdueDuration = calculateOverdueDuration(oneYearFromPayment, today); } } else if (member.current_year_dues_paid !== 'true') { let dueDate: Date; if (member.payment_due_date) { dueDate = new Date(member.payment_due_date); } else if (member.member_since) { dueDate = new Date(member.member_since); dueDate.setFullYear(dueDate.getFullYear() + 1); } else { continue; } const oneYearOverdue = new Date(dueDate); oneYearOverdue.setFullYear(oneYearOverdue.getFullYear() + 1); if (today > oneYearOverdue) { overdueDuration = calculateOverdueDuration(oneYearOverdue, today); } } if (overdueDuration) { overdueDetails.push({ id: member.Id, name: member.FullName || `${member.first_name} ${member.last_name}`, status: 'Inactive', overdueDuration: overdueDuration.formattedDuration, totalMonthsOverdue: overdueDuration.totalMonths }); } continue; } // Check if member has overdue dues (more than 1 year) let isOverdue = false; let overdueDuration = null; if (member.current_year_dues_paid === 'true' && member.membership_date_paid) { // If dues are marked as paid, check if it's been more than 1 year since payment const lastPaidDate = new Date(member.membership_date_paid); const oneYearFromPayment = new Date(lastPaidDate); oneYearFromPayment.setFullYear(oneYearFromPayment.getFullYear() + 1); if (today > oneYearFromPayment) { isOverdue = true; overdueDuration = calculateOverdueDuration(oneYearFromPayment, today); } } else if (member.current_year_dues_paid !== 'true') { // If dues are not paid, check payment due date or member since date let dueDate: Date; if (member.payment_due_date) { dueDate = new Date(member.payment_due_date); } else if (member.member_since) { // Fallback: 1 year from member since date dueDate = new Date(member.member_since); dueDate.setFullYear(dueDate.getFullYear() + 1); } else { // Skip if we can't determine due date continue; } // Check if more than 1 year overdue const oneYearOverdue = new Date(dueDate); oneYearOverdue.setFullYear(oneYearOverdue.getFullYear() + 1); if (today > oneYearOverdue) { isOverdue = true; overdueDuration = calculateOverdueDuration(oneYearOverdue, today); } } if (isOverdue && overdueDuration) { membersToUpdate.push({ id: member.Id, name: member.FullName || `${member.first_name} ${member.last_name}`, currentStatus: member.membership_status, overdueDuration: overdueDuration.formattedDuration, totalMonthsOverdue: overdueDuration.totalMonths }); overdueDetails.push({ id: member.Id, name: member.FullName || `${member.first_name} ${member.last_name}`, status: member.membership_status, overdueDuration: overdueDuration.formattedDuration, totalMonthsOverdue: overdueDuration.totalMonths }); } } // Update all overdue members to inactive let updatedCount = 0; const errors: string[] = []; for (const memberInfo of membersToUpdate) { try { await updateMember(memberInfo.id, { membership_status: 'Inactive' }); updatedCount++; console.log(`[API] Marked member ${memberInfo.name} (${memberInfo.id}) as inactive - ${memberInfo.overdueDuration}`); } catch (error: any) { console.error(`[API] Failed to update member ${memberInfo.name} (${memberInfo.id}):`, error); errors.push(`Failed to update ${memberInfo.name}: ${error.message}`); } } console.log(`[API] Updated ${updatedCount} of ${membersToUpdate.length} overdue members to inactive status`); return { success: true, data: { updatedCount, totalOverdue: overdueDetails.length, overdueDetails: overdueDetails.sort((a, b) => b.totalMonthsOverdue - a.totalMonthsOverdue), // Sort by most overdue first errors: errors.length > 0 ? errors : undefined }, message: `Successfully updated ${updatedCount} overdue member${updatedCount !== 1 ? 's' : ''} to inactive status` }; } catch (error: any) { console.error('[API] Error updating overdue member statuses:', error); throw createError({ statusCode: error.statusCode || 500, statusMessage: error.message || 'Failed to update overdue member statuses' }); } });