2025-08-10 23:29:48 +02:00
// server/api/members/overdue-count.get.ts
2025-08-10 23:42:17 +02:00
2025-08-10 23:29:48 +02:00
export default defineEventHandler ( async ( event ) = > {
try {
const { getMembers } = await import ( '~/server/utils/nocodb' ) ;
2025-08-31 18:28:38 +02:00
const { calculateDuesStatus } = await import ( '~/server/utils/dues-calculator' ) ;
2025-08-10 23:29:48 +02:00
// Get all members
const allMembers = await getMembers ( ) ;
if ( ! allMembers ? . list ) {
return {
success : true ,
2025-08-10 23:42:17 +02:00
data : {
count : 0 ,
2025-08-31 18:28:38 +02:00
overdueMembers : [ ] ,
dataSource : 'unavailable'
2025-08-10 23:42:17 +02:00
}
2025-08-10 23:29:48 +02:00
} ;
}
const today = new Date ( ) ;
2025-08-10 23:42:17 +02:00
const overdueMembers : any [ ] = [ ] ;
2025-08-10 23:29:48 +02:00
for ( const member of allMembers . list ) {
2025-08-31 18:28:38 +02:00
// Use dues-calculator for proper dues status calculation
const duesStatus = await calculateDuesStatus ( member ) ;
2025-08-10 23:29:48 +02:00
2025-08-31 18:28:38 +02:00
// Only include members who are overdue
if ( duesStatus . isOverdue && duesStatus . daysOverdue !== null ) {
// Format overdue duration
const totalMonths = Math . floor ( duesStatus . daysOverdue / 30.44 ) ;
const years = Math . floor ( totalMonths / 12 ) ;
const months = totalMonths % 12 ;
2025-08-10 23:29:48 +02:00
2025-08-31 18:28:38 +02:00
let formattedDuration = '' ;
if ( years > 0 ) {
formattedDuration = ` ${ years } year ${ years !== 1 ? 's' : '' } ` ;
if ( months > 0 ) {
formattedDuration += ` ${ months } month ${ months !== 1 ? 's' : '' } ` ;
}
} else if ( totalMonths > 0 ) {
formattedDuration = ` ${ totalMonths } month ${ totalMonths !== 1 ? 's' : '' } ` ;
2025-08-10 23:29:48 +02:00
} else {
2025-08-31 18:28:38 +02:00
const days = duesStatus . daysOverdue ;
formattedDuration = ` ${ days } day ${ days !== 1 ? 's' : '' } ` ;
2025-08-10 23:29:48 +02:00
}
2025-08-31 18:28:38 +02:00
formattedDuration += ' overdue' ;
2025-08-10 23:29:48 +02:00
2025-08-10 23:42:17 +02:00
overdueMembers . push ( {
id : member.Id ,
name : member.FullName || ` ${ member . first_name } ${ member . last_name } ` ,
email : member.email ,
status : member.membership_status ,
2025-08-31 18:28:38 +02:00
overdueDuration : formattedDuration ,
daysOverdue : duesStatus.daysOverdue ,
totalMonthsOverdue : totalMonths ,
dueDate : duesStatus.dueDate ,
amount : duesStatus.amount ,
currency : duesStatus.currency ,
dataSource : duesStatus.source ,
confidence : duesStatus.confidence ,
2025-08-10 23:42:17 +02:00
isInactive : member.membership_status === 'Inactive'
} ) ;
2025-08-10 23:29:48 +02:00
}
}
2025-08-31 18:28:38 +02:00
// Sort by most overdue first (by days)
overdueMembers . sort ( ( a , b ) = > b . daysOverdue - a . daysOverdue ) ;
// Log data quality metrics
const highConfidenceCount = overdueMembers . filter ( m = > m . confidence === 'high' ) . length ;
const mediumConfidenceCount = overdueMembers . filter ( m = > m . confidence === 'medium' ) . length ;
const lowConfidenceCount = overdueMembers . filter ( m = > m . confidence === 'low' ) . length ;
console . log ( ` [overdue-count] Found ${ overdueMembers . length } overdue members: ` , {
highConfidence : highConfidenceCount ,
mediumConfidence : mediumConfidenceCount ,
lowConfidence : lowConfidenceCount
} ) ;
// Alert if many low confidence results
if ( lowConfidenceCount > overdueMembers . length * 0.3 ) {
console . warn ( ` [overdue-count] High percentage of low confidence dues data ( ${ lowConfidenceCount } / ${ overdueMembers . length } ). Data quality review recommended. ` ) ;
}
2025-08-10 23:42:17 +02:00
2025-08-10 23:29:48 +02:00
return {
success : true ,
2025-08-10 23:42:17 +02:00
data : {
count : overdueMembers.length ,
2025-08-31 18:28:38 +02:00
overdueMembers : overdueMembers ,
dataQuality : {
highConfidence : highConfidenceCount ,
mediumConfidence : mediumConfidenceCount ,
lowConfidence : lowConfidenceCount
}
2025-08-10 23:42:17 +02:00
}
2025-08-10 23:29:48 +02:00
} ;
} catch ( error : any ) {
console . error ( '[API] Error fetching overdue count:' , error ) ;
throw createError ( {
statusCode : error.statusCode || 500 ,
statusMessage : error.message || 'Failed to fetch overdue count'
} ) ;
}
} ) ;