payservedb 6.4.0 → 6.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
3
|
+
const DutyRosterChecklistSchema = new mongoose.Schema(
|
|
4
|
+
{
|
|
5
|
+
dutyRosterId: {
|
|
6
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
7
|
+
ref: "DutyRoster",
|
|
8
|
+
required: true,
|
|
9
|
+
},
|
|
10
|
+
facilityId: {
|
|
11
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
12
|
+
ref: "Facility",
|
|
13
|
+
required: true,
|
|
14
|
+
},
|
|
15
|
+
staffId: {
|
|
16
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
17
|
+
ref: "User",
|
|
18
|
+
required: true,
|
|
19
|
+
},
|
|
20
|
+
masterWorkplanId: {
|
|
21
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
22
|
+
ref: "MasterWorkplan",
|
|
23
|
+
required: true,
|
|
24
|
+
},
|
|
25
|
+
// Array of tasks with their individual dates and status
|
|
26
|
+
tasks: [
|
|
27
|
+
{
|
|
28
|
+
childWorkplanId: {
|
|
29
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
30
|
+
ref: "ChildWorkplan",
|
|
31
|
+
required: true,
|
|
32
|
+
},
|
|
33
|
+
// Each task can have multiple scheduled dates
|
|
34
|
+
scheduledDates: [
|
|
35
|
+
{
|
|
36
|
+
date: {
|
|
37
|
+
type: Date,
|
|
38
|
+
required: true,
|
|
39
|
+
},
|
|
40
|
+
status: {
|
|
41
|
+
type: String,
|
|
42
|
+
enum: [
|
|
43
|
+
"pending",
|
|
44
|
+
"completed",
|
|
45
|
+
"missed",
|
|
46
|
+
"cancelled",
|
|
47
|
+
"in-progress",
|
|
48
|
+
],
|
|
49
|
+
default: "pending",
|
|
50
|
+
required: true,
|
|
51
|
+
},
|
|
52
|
+
completedAt: {
|
|
53
|
+
type: Date,
|
|
54
|
+
},
|
|
55
|
+
completedBy: {
|
|
56
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
57
|
+
ref: "User",
|
|
58
|
+
},
|
|
59
|
+
notes: {
|
|
60
|
+
type: String,
|
|
61
|
+
maxlength: 500,
|
|
62
|
+
},
|
|
63
|
+
// Time tracking
|
|
64
|
+
startTime: String,
|
|
65
|
+
endTime: String,
|
|
66
|
+
actualDuration: Number, // in minutes
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
// Task metadata
|
|
70
|
+
priority: {
|
|
71
|
+
type: String,
|
|
72
|
+
enum: ["low", "medium", "high", "critical"],
|
|
73
|
+
default: "medium",
|
|
74
|
+
},
|
|
75
|
+
estimatedDuration: Number, // in minutes
|
|
76
|
+
isRecurring: {
|
|
77
|
+
type: Boolean,
|
|
78
|
+
default: false,
|
|
79
|
+
},
|
|
80
|
+
recurringPattern: {
|
|
81
|
+
type: String,
|
|
82
|
+
enum: ["daily", "weekly", "monthly", "custom"],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
// Overall checklist metadata
|
|
87
|
+
period: {
|
|
88
|
+
startDate: {
|
|
89
|
+
type: Date,
|
|
90
|
+
required: true,
|
|
91
|
+
},
|
|
92
|
+
endDate: {
|
|
93
|
+
type: Date,
|
|
94
|
+
required: true,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
// Summary statistics
|
|
98
|
+
summary: {
|
|
99
|
+
totalTasks: {
|
|
100
|
+
type: Number,
|
|
101
|
+
default: 0,
|
|
102
|
+
},
|
|
103
|
+
completedTasks: {
|
|
104
|
+
type: Number,
|
|
105
|
+
default: 0,
|
|
106
|
+
},
|
|
107
|
+
pendingTasks: {
|
|
108
|
+
type: Number,
|
|
109
|
+
default: 0,
|
|
110
|
+
},
|
|
111
|
+
missedTasks: {
|
|
112
|
+
type: Number,
|
|
113
|
+
default: 0,
|
|
114
|
+
},
|
|
115
|
+
completionPercentage: {
|
|
116
|
+
type: Number,
|
|
117
|
+
default: 0,
|
|
118
|
+
min: 0,
|
|
119
|
+
max: 100,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
status: {
|
|
123
|
+
type: String,
|
|
124
|
+
enum: ["active", "completed", "expired", "cancelled"],
|
|
125
|
+
default: "active",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
timestamps: true,
|
|
130
|
+
},
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// Pre-save middleware to update summary statistics
|
|
134
|
+
DutyRosterChecklistSchema.pre("save", function (next) {
|
|
135
|
+
// Validate period dates
|
|
136
|
+
if (this.period.startDate >= this.period.endDate) {
|
|
137
|
+
return next(new Error("End date must be after start date"));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Calculate summary statistics
|
|
141
|
+
let totalScheduledDates = 0;
|
|
142
|
+
let completedScheduledDates = 0;
|
|
143
|
+
let pendingScheduledDates = 0;
|
|
144
|
+
let missedScheduledDates = 0;
|
|
145
|
+
|
|
146
|
+
this.tasks.forEach((task) => {
|
|
147
|
+
task.scheduledDates.forEach((scheduledDate) => {
|
|
148
|
+
totalScheduledDates++;
|
|
149
|
+
switch (scheduledDate.status) {
|
|
150
|
+
case "completed":
|
|
151
|
+
completedScheduledDates++;
|
|
152
|
+
break;
|
|
153
|
+
case "pending":
|
|
154
|
+
case "in-progress":
|
|
155
|
+
pendingScheduledDates++;
|
|
156
|
+
break;
|
|
157
|
+
case "missed":
|
|
158
|
+
missedScheduledDates++;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
this.summary.totalTasks = totalScheduledDates;
|
|
165
|
+
this.summary.completedTasks = completedScheduledDates;
|
|
166
|
+
this.summary.pendingTasks = pendingScheduledDates;
|
|
167
|
+
this.summary.missedTasks = missedScheduledDates;
|
|
168
|
+
this.summary.completionPercentage =
|
|
169
|
+
totalScheduledDates > 0
|
|
170
|
+
? Math.round((completedScheduledDates / totalScheduledDates) * 100)
|
|
171
|
+
: 0;
|
|
172
|
+
|
|
173
|
+
next();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Static method to generate dates between start and end date
|
|
177
|
+
DutyRosterChecklistSchema.statics.generateDateRange = function (
|
|
178
|
+
startDate,
|
|
179
|
+
endDate,
|
|
180
|
+
frequency = "daily",
|
|
181
|
+
) {
|
|
182
|
+
const dates = [];
|
|
183
|
+
const current = new Date(startDate);
|
|
184
|
+
const end = new Date(endDate);
|
|
185
|
+
|
|
186
|
+
while (current <= end) {
|
|
187
|
+
dates.push(new Date(current));
|
|
188
|
+
|
|
189
|
+
switch (frequency) {
|
|
190
|
+
case "daily":
|
|
191
|
+
current.setDate(current.getDate() + 1);
|
|
192
|
+
break;
|
|
193
|
+
case "weekly":
|
|
194
|
+
current.setDate(current.getDate() + 7);
|
|
195
|
+
break;
|
|
196
|
+
case "monthly":
|
|
197
|
+
current.setMonth(current.getMonth() + 1);
|
|
198
|
+
break;
|
|
199
|
+
default:
|
|
200
|
+
current.setDate(current.getDate() + 1);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return dates;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// Instance method to update task status
|
|
208
|
+
DutyRosterChecklistSchema.methods.updateTaskStatus = function (
|
|
209
|
+
taskId,
|
|
210
|
+
dateId,
|
|
211
|
+
status,
|
|
212
|
+
completedBy,
|
|
213
|
+
notes,
|
|
214
|
+
) {
|
|
215
|
+
const task = this.tasks.id(taskId);
|
|
216
|
+
if (!task) {
|
|
217
|
+
throw new Error("Task not found");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const scheduledDate = task.scheduledDates.id(dateId);
|
|
221
|
+
if (!scheduledDate) {
|
|
222
|
+
throw new Error("Scheduled date not found");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
scheduledDate.status = status;
|
|
226
|
+
if (status === "completed") {
|
|
227
|
+
scheduledDate.completedAt = new Date();
|
|
228
|
+
scheduledDate.completedBy = completedBy;
|
|
229
|
+
}
|
|
230
|
+
if (notes) {
|
|
231
|
+
scheduledDate.notes = notes;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return this.save();
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// Add indexes for efficient queries
|
|
238
|
+
DutyRosterChecklistSchema.index({ dutyRosterId: 1 });
|
|
239
|
+
DutyRosterChecklistSchema.index({ facilityId: 1, staffId: 1 });
|
|
240
|
+
DutyRosterChecklistSchema.index({ masterWorkplanId: 1 });
|
|
241
|
+
DutyRosterChecklistSchema.index({ "period.startDate": 1, "period.endDate": 1 });
|
|
242
|
+
DutyRosterChecklistSchema.index({ "tasks.scheduledDates.date": 1 });
|
|
243
|
+
DutyRosterChecklistSchema.index({ status: 1 });
|
|
244
|
+
|
|
245
|
+
const DutyRosterChecklist = mongoose.model(
|
|
246
|
+
"DutyRosterChecklist",
|
|
247
|
+
DutyRosterChecklistSchema,
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
module.exports = DutyRosterChecklist;
|
package/src/models/dutyroster.js
CHANGED
|
@@ -36,7 +36,6 @@ const dutyRosterSchema = new mongoose.Schema(
|
|
|
36
36
|
ref: "MasterWorkplanAssignment",
|
|
37
37
|
required: true,
|
|
38
38
|
},
|
|
39
|
-
// Roster validity period
|
|
40
39
|
startDate: {
|
|
41
40
|
type: Date,
|
|
42
41
|
required: true,
|
|
@@ -45,7 +44,6 @@ const dutyRosterSchema = new mongoose.Schema(
|
|
|
45
44
|
type: Date,
|
|
46
45
|
required: true,
|
|
47
46
|
},
|
|
48
|
-
// Regular weekly schedule - now array of time slots for each day
|
|
49
47
|
weeklySchedule: {
|
|
50
48
|
monday: [timeSlotSchema],
|
|
51
49
|
tuesday: [timeSlotSchema],
|