monacousa-portal/server/api/members/[id]/send-dues-reminder.post.ts

178 lines
5.2 KiB
TypeScript
Raw Normal View History

import { sendEmail } from '~/server/utils/email';
import { createNocoDBClient } from '~/server/utils/nocodb';
import { calculateDaysUntilDue, calculateOverdueDays, getNextDuesDate, isPaymentOverOneYear, isDuesActuallyCurrent } from '~/utils/dues-calculations';
import { getRegistrationConfig } from '~/server/utils/admin-config';
export default defineEventHandler(async (event) => {
try {
const memberId = getRouterParam(event, 'id');
const { reminderType } = await readBody(event);
if (!memberId) {
throw createError({
statusCode: 400,
statusMessage: 'Member ID is required'
});
}
if (!['due-soon', 'overdue'].includes(reminderType)) {
throw createError({
statusCode: 400,
statusMessage: 'Invalid reminder type. Must be "due-soon" or "overdue"'
});
}
// Get member data
const nocodb = createNocoDBClient();
const member = await nocodb.findOne('nc_members', memberId);
if (!member) {
throw createError({
statusCode: 404,
statusMessage: 'Member not found'
});
}
if (!member.email) {
throw createError({
statusCode: 400,
statusMessage: 'Member does not have an email address'
});
}
// Get current admin configuration for payment details
const registrationConfig = getRegistrationConfig();
// Calculate dues status
const memberName = member.FullName || `${member.first_name} ${member.last_name}`.trim() || 'Member';
const nextDueDate = getNextDuesDate(member);
const membershipFee = `${registrationConfig.membershipFee}`;
const paymentIban = registrationConfig.iban;
const accountHolder = registrationConfig.accountHolder;
const portalUrl = `${process.env.NUXT_PUBLIC_DOMAIN || 'https://monacousa.org'}/dashboard`;
const currentYear = new Date().getFullYear();
// Format dates
const formatDate = (dateString: string | Date | null | undefined): string => {
if (!dateString) return '';
try {
const date = new Date(dateString);
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
} catch {
return String(dateString);
}
};
let emailData;
let subject;
let template;
if (reminderType === 'due-soon') {
// Check if this member actually has dues coming due
const daysUntilDue = calculateDaysUntilDue(member);
if (!daysUntilDue || daysUntilDue.daysUntilDue <= 0) {
throw createError({
statusCode: 400,
statusMessage: 'Member does not have dues coming due soon'
});
}
subject = `🏎️ MonacoUSA - Annual Dues Due in ${daysUntilDue.daysUntilDue} Days`;
template = 'dues-due-soon';
emailData = {
memberName,
memberId: member.member_id || member.Id,
memberEmail: member.email,
memberSince: formatDate(member.member_since),
amount: membershipFee,
dueDate: formatDate(daysUntilDue.nextDueDate),
daysUntilDue: daysUntilDue.daysUntilDue,
paymentIban,
accountHolder,
portalUrl,
currentYear
};
} else if (reminderType === 'overdue') {
// Check if this member is actually overdue
const isDuesCurrent = isDuesActuallyCurrent(member);
if (isDuesCurrent) {
throw createError({
statusCode: 400,
statusMessage: 'Member does not have overdue dues'
});
}
const overdueDays = calculateOverdueDays(member);
const originalDueDate = member.payment_due_date || nextDueDate;
subject = `🚨 MonacoUSA - URGENT: Overdue Dues Notice (${overdueDays} days overdue)`;
template = 'dues-overdue';
emailData = {
memberName,
memberId: member.member_id || member.Id,
memberEmail: member.email,
memberSince: formatDate(member.member_since),
amount: membershipFee,
originalDueDate: formatDate(originalDueDate),
daysOverdue: overdueDays,
paymentIban,
accountHolder,
portalUrl,
currentYear
};
}
// Send the email
console.log(`[Dues Reminder] Sending ${reminderType} reminder to ${member.email}`, {
memberId,
memberName,
reminderType,
emailData
});
await sendEmail({
to: member.email,
subject,
template,
data: emailData
});
// Log the reminder sent (could store in database for tracking)
console.log(`[Dues Reminder] Successfully sent ${reminderType} reminder to ${memberName} (${member.email})`);
return {
success: true,
message: `${reminderType === 'due-soon' ? 'Due soon' : 'Overdue'} reminder sent successfully`,
data: {
memberId,
memberName,
memberEmail: member.email,
reminderType,
sentAt: new Date().toISOString()
}
};
} catch (error: any) {
console.error('[Dues Reminder] Error sending reminder:', error);
// Handle specific error cases
if (error.statusCode) {
throw error;
}
throw createError({
statusCode: 500,
statusMessage: error.message || 'Failed to send dues reminder'
});
}
});