To create attendance you need 3 Collections.
Collection 1 : Shift
Shift Document will have Schema like below
const MYDBSchema = new mongoose.Schema({
name: { type: String, default: 'Default' },
weekend: { type: Array, default: [] },
time: {type: Array, default: [] },
lateIn: { type: Number, default: 0 },
earlyOut: { type: Number, default: 0},
halfDayHour: { type: Number }, // Half Day
fullDayHour: { type: Number } // Full Day
offset: { type: Number } // Timezone offset
assignedEmployee: { type: Array, default: [] }
});
As described above schema LateIn, Early Out will have number in format of Minute
Collection 2 : DailyReport
Daily Report Document will have Schema like below
const MYDBSchema = new mongoose.Schema({
user: { type: mongoose.Types.ObjectId}, // Reference of User
shift: { type: mongoose.Types.ObjectId}, // Reference of User
date: { type: Date }, // Start Of The Day Date . Example your offset -330 then store it as "2021-11-26T18:30:00.000Z"
lateIn: { type: Number, default: 0 }, // Will have total LAte In Seconds
earlyOut: { type: Number, default: 0}, // Will have total Early Out Seconds
overTime: { type: Number } // Will have Overtime
breakTime: { type: Number } // Will have total Break Time
initialInTime: { type: Date }, // Will have First Clock In
finalOutTime: { type: Date } // Will have Final Clock Out
totalWorkHour: { type: Number } // Will have Total Working Hour Seconds
dayStatus: { type: Number } // Will define that day is Holiday or Weekend or Working Day
timeStatus: { type: Number } // Will have initial (absent), work (working), break (on break), end (Clocked Out),
});
Collection 3 : TimeSheets
Timesheet Document will look like this
const MYDBSchema = new mongoose.Schema({
user: { type: mongoose.Types.ObjectId}, // Reference of User
dailyReport: { type: mongoose.Types.ObjectId}, // Reference of Daily Report
date: { type: Date }, // Start Of The Day Date . Example your offset -330 then store it as "2021-11-26T18:30:00.000Z"
inTime: { type: Date }, // Will have Clock In / Break In
outTime: { type: Date } // Will have Clock Out / Break Out
duration: { type: Number } // Will have Duration in Seconds difference between inTime and outTime
type: { type: Number } // Break or Work
});
-> How shift will work
Everyday Run CRON either create Function that will create entry for everyday of each user by set timeStatus as initial
-> How Daily Report Will work
When ever user sends request for clock in. First need to grab Shift and then get timezone offset from the shift convert that date and fetch daily Report.
-> Create function like this
getShiftTiming({ shiftObject, date }) -> will return Object that contain { willStartAt: Date, endAt: Date }
getCurrentTiming({ date }) -> Will fetch Daily Report to send it to client
addIn ({ date, type }) -> Will fetch DailyReport and then create entry in TimeSheets collection as inTime and then change timeStatus to WORK / BREAK based on param type
addOut ({ date }) -> Will Fetch Daily Report and then fetch last TimeSheet and then set outTime
calculateDailyReport({ shiftDetail, dailyReportDetail }) -> Will calculate report based on TimeSheet Collection. It will fetch all records based on Daily Report and sum up duration and update dailyReport's totalWorkingHour, break and then take first timesheet's inTime and last timesheet's outTime and then set dailyReport's initialInTime = inTime and finalOutTime = outTime. Another function within this function will get called and it will ( lateIn -> getShiftTiming call this function and then get difference between initialInTime and willStart at it will be Late In seconds, overTime -> Substract breakTime from totalTime and then check it with shiftDetail's fullDayWorkingHour you will get overTime Seconds same way reverse logic you can get earlyOutTime )
At this way you can manage Shift. I also successfully managed Shift at ubsapp.com which is heavily dynamic than this example. It has extra feature that will allow user to update and add slots and request ( GEO Location and IP Access based Clock In And Clock Out lot other. )