Implement grace period system for member dues management
All checks were successful
Build And Push Image / docker (push) Successful in 2m55s
All checks were successful
Build And Push Image / docker (push) Successful in 2m55s
- Add grace period logic for new members (1 month from join date) - Enhance dues status computation with actual payment date validation - Update member card to show grace period status with warning indicators - Remove overdue dues banner from member list - Add payment due date calculation in registration process - Update email templates for improved member communication
This commit is contained in:
101
server/api/admin/assign-member-ids.post.ts
Normal file
101
server/api/admin/assign-member-ids.post.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { getMembers, updateMember } from '~/server/utils/nocodb';
|
||||
import { findMembersWithoutMemberID, generateMemberID, extractMemberIDNumber } from '~/server/utils/member-id';
|
||||
import type { Member } from '~/utils/types';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
console.log('[api/admin/assign-member-ids.post] =========================');
|
||||
console.log('[api/admin/assign-member-ids.post] POST /api/admin/assign-member-ids - Assign member IDs to existing members');
|
||||
|
||||
try {
|
||||
// Check if user is admin
|
||||
const sessionManager = createSessionManager();
|
||||
const cookieHeader = getHeader(event, 'cookie');
|
||||
const session = sessionManager.getSession(cookieHeader);
|
||||
|
||||
if (!session || session.user.tier !== 'admin') {
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: 'Admin access required'
|
||||
});
|
||||
}
|
||||
|
||||
// Get all members and find those without member IDs
|
||||
const allMembersResult = await getMembers();
|
||||
const allMembers = allMembersResult.list || [];
|
||||
console.log(`[api/admin/assign-member-ids.post] Found ${allMembers.length} total members`);
|
||||
|
||||
// Find members without member_id
|
||||
const membersWithoutIds = await findMembersWithoutMemberID();
|
||||
console.log(`[api/admin/assign-member-ids.post] Found ${membersWithoutIds.length} members without IDs`);
|
||||
|
||||
if (membersWithoutIds.length === 0) {
|
||||
return {
|
||||
success: true,
|
||||
message: 'All members already have member IDs assigned',
|
||||
data: {
|
||||
totalMembers: allMembers.length,
|
||||
membersUpdated: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Get the highest existing member ID number to continue sequence
|
||||
const existingMemberIds = allMembers
|
||||
.filter((member: Member) => member.member_id)
|
||||
.map((member: Member) => extractMemberIDNumber(member.member_id!))
|
||||
.filter(num => num !== null) as number[];
|
||||
|
||||
// Start from next available number, or 1 if no existing IDs
|
||||
let nextIdNumber = existingMemberIds.length > 0 ? Math.max(...existingMemberIds) + 1 : 1;
|
||||
console.log(`[api/admin/assign-member-ids.post] Starting with member ID number: ${nextIdNumber}`);
|
||||
|
||||
// Assign IDs to members without them
|
||||
const updatedMembers = [];
|
||||
|
||||
for (const member of membersWithoutIds) {
|
||||
// Use 4-digit padding for member IDs (MUSA-0001, MUSA-0002, etc.)
|
||||
const memberId = `MUSA-${nextIdNumber.toString().padStart(4, '0')}`;
|
||||
|
||||
try {
|
||||
await updateMember(member.Id, {
|
||||
member_id: memberId
|
||||
});
|
||||
|
||||
updatedMembers.push({
|
||||
id: member.Id,
|
||||
name: `${member.first_name || ''} ${member.last_name || ''}`.trim() || 'Unknown',
|
||||
email: member.email || 'No email',
|
||||
memberId
|
||||
});
|
||||
|
||||
console.log(`[api/admin/assign-member-ids.post] Assigned ${memberId} to ${member.first_name} ${member.last_name}`);
|
||||
nextIdNumber++;
|
||||
|
||||
} catch (updateError: any) {
|
||||
console.error(`[api/admin/assign-member-ids.post] Failed to assign ID to member ${member.Id}:`, updateError);
|
||||
// Continue with next member rather than failing the entire operation
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[api/admin/assign-member-ids.post] ✅ Successfully assigned IDs to ${updatedMembers.length} members`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Successfully assigned member IDs to ${updatedMembers.length} members`,
|
||||
data: {
|
||||
totalMembers: allMembers.length,
|
||||
membersUpdated: updatedMembers.length,
|
||||
updatedMembers: updatedMembers.slice(0, 10), // Return first 10 for display
|
||||
startingId: updatedMembers.length > 0 ? `MUSA-${(nextIdNumber - updatedMembers.length).toString().padStart(4, '0')}` : null,
|
||||
endingId: updatedMembers.length > 0 ? updatedMembers[updatedMembers.length - 1].memberId : null
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('[api/admin/assign-member-ids.post] ❌ Failed to assign member IDs:', error);
|
||||
throw createError({
|
||||
statusCode: error.statusCode || 500,
|
||||
statusMessage: error.statusMessage || 'Failed to assign member IDs'
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -94,6 +94,9 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
// 5. Create Keycloak user with role-based registration
|
||||
console.log('[api/registration.post] Creating Keycloak user with role-based system...');
|
||||
const paymentDueDate = new Date();
|
||||
paymentDueDate.setMonth(paymentDueDate.getMonth() + 1); // 1 month from registration
|
||||
|
||||
const membershipData = {
|
||||
membershipStatus: 'Active',
|
||||
duesStatus: 'unpaid' as const,
|
||||
@@ -101,7 +104,7 @@ export default defineEventHandler(async (event) => {
|
||||
phone: body.phone,
|
||||
address: body.address,
|
||||
registrationDate: new Date().toISOString(),
|
||||
paymentDueDate: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
paymentDueDate: paymentDueDate.toISOString(),
|
||||
membershipTier: 'user' as const
|
||||
};
|
||||
|
||||
@@ -129,7 +132,7 @@ export default defineEventHandler(async (event) => {
|
||||
registration_date: new Date().toISOString(),
|
||||
member_since: new Date().getFullYear().toString(),
|
||||
membership_date_paid: '',
|
||||
payment_due_date: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString() // 3 months from now
|
||||
payment_due_date: paymentDueDate.toISOString() // 1 month from registration
|
||||
};
|
||||
|
||||
const member = await nocodb.create('members', memberData);
|
||||
|
||||
Reference in New Issue
Block a user