@7365admin1/module-hygiene 4.21.0 → 4.22.0
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/CHANGELOG.md +6 -0
- package/dist/index.d.ts +30 -8
- package/dist/index.js +699 -392
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +714 -406
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
BadRequestError,
|
|
18
18
|
useCache,
|
|
19
19
|
makeCacheKey,
|
|
20
|
+
paginate,
|
|
20
21
|
logger
|
|
21
22
|
} from "@7365admin1/node-server-utils";
|
|
22
23
|
function useHygieneDashboardRepository() {
|
|
@@ -25,72 +26,57 @@ function useHygieneDashboardRepository() {
|
|
|
25
26
|
throw new InternalServerError("Unable to connect to server.");
|
|
26
27
|
}
|
|
27
28
|
const dashboard_namespace_collection = "hygiene.dashboard";
|
|
28
|
-
const feedback_namespace_collection = "feedbacks";
|
|
29
29
|
const cleaning_schedule_namespace_collection = "site.cleaning.schedules";
|
|
30
30
|
const area_checklist_namespace_collection = "site.cleaning.schedule.areas";
|
|
31
|
-
const schedule_task_namespace_collection = "site.schedule-tasks";
|
|
32
31
|
const supply_namespace_collection = "site.supplies";
|
|
33
|
-
const
|
|
34
|
-
const feedbackCollection = db.collection(feedback_namespace_collection);
|
|
32
|
+
const work_order_namespace_collection = "work-orders2";
|
|
35
33
|
const areaChecklistCollection = db.collection(
|
|
36
34
|
area_checklist_namespace_collection
|
|
37
35
|
);
|
|
38
|
-
const scheduleTaskCollection = db.collection(
|
|
39
|
-
schedule_task_namespace_collection
|
|
40
|
-
);
|
|
41
36
|
const supplyCollection = db.collection(supply_namespace_collection);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
);
|
|
37
|
+
const workOrderCollection = db.collection(work_order_namespace_collection);
|
|
38
|
+
const attendanceCollection = db.collection("site.attendances");
|
|
39
|
+
const feedbackCollection = db.collection("feedbacks2");
|
|
45
40
|
const { setCache, getCache } = useCache(dashboard_namespace_collection);
|
|
41
|
+
const workOrderServiceMap = {
|
|
42
|
+
security_agency: "Security",
|
|
43
|
+
cleaning_services: "Cleaning",
|
|
44
|
+
mechanical_electrical_services: "M&E",
|
|
45
|
+
landscaping_services: "Landscape",
|
|
46
|
+
pest_control_services: "Pest Control",
|
|
47
|
+
pool_maintenance_services: "Pool Maintenance"
|
|
48
|
+
};
|
|
49
|
+
function areaChecklistScheduleLookup(site, serviceType, createdAtRange) {
|
|
50
|
+
return [
|
|
51
|
+
{ $match: { serviceType } },
|
|
52
|
+
{
|
|
53
|
+
$lookup: {
|
|
54
|
+
from: cleaning_schedule_namespace_collection,
|
|
55
|
+
localField: "schedule",
|
|
56
|
+
foreignField: "_id",
|
|
57
|
+
as: "scheduleDoc",
|
|
58
|
+
pipeline: [
|
|
59
|
+
{
|
|
60
|
+
$match: {
|
|
61
|
+
site,
|
|
62
|
+
serviceType,
|
|
63
|
+
createdAt: createdAtRange
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{ $unwind: { path: "$scheduleDoc", preserveNullAndEmptyArrays: false } }
|
|
70
|
+
];
|
|
71
|
+
}
|
|
46
72
|
async function getHygieneDashboard({
|
|
47
73
|
site,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
toiletAreaPeriod = "today",
|
|
51
|
-
scheduleTaskPeriod = "today",
|
|
52
|
-
supplyPeriod = "today",
|
|
53
|
-
requestItemPeriod = "today"
|
|
74
|
+
serviceType,
|
|
75
|
+
period = "today"
|
|
54
76
|
}) {
|
|
55
|
-
const
|
|
56
|
-
feedback: {},
|
|
57
|
-
commonArea: {},
|
|
58
|
-
toiletArea: {},
|
|
59
|
-
scheduleTask: {},
|
|
60
|
-
supply: {},
|
|
61
|
-
requestItem: {}
|
|
62
|
-
};
|
|
63
|
-
const yesterDayQueries = {
|
|
64
|
-
feedback: {},
|
|
65
|
-
commonArea: {},
|
|
66
|
-
toiletArea: {},
|
|
67
|
-
scheduleTask: {},
|
|
68
|
-
supply: {},
|
|
69
|
-
requestItem: {}
|
|
70
|
-
};
|
|
71
|
-
const todayQueries = {
|
|
72
|
-
feedback: {},
|
|
73
|
-
commonArea: {},
|
|
74
|
-
toiletArea: {},
|
|
75
|
-
scheduleTask: {},
|
|
76
|
-
supply: {},
|
|
77
|
-
requestItem: {}
|
|
78
|
-
};
|
|
79
|
-
const cacheOptions = {
|
|
80
|
-
feedbackPeriod,
|
|
81
|
-
commonAreaPeriod,
|
|
82
|
-
toiletAreaPeriod,
|
|
83
|
-
scheduleTaskPeriod,
|
|
84
|
-
supplyPeriod,
|
|
85
|
-
requestItemPeriod
|
|
86
|
-
};
|
|
77
|
+
const cacheOptions = { serviceType, period };
|
|
87
78
|
try {
|
|
88
79
|
site = new ObjectId(site);
|
|
89
|
-
Object.keys(countQueries).forEach((key) => {
|
|
90
|
-
countQueries[key].site = site;
|
|
91
|
-
yesterDayQueries[key].site = site;
|
|
92
|
-
todayQueries[key].site = site;
|
|
93
|
-
});
|
|
94
80
|
cacheOptions.site = site.toString();
|
|
95
81
|
} catch (error) {
|
|
96
82
|
throw new BadRequestError("Invalid site ID format.");
|
|
@@ -118,32 +104,28 @@ function useHygieneDashboardRepository() {
|
|
|
118
104
|
});
|
|
119
105
|
return singaporeMoment.toDate();
|
|
120
106
|
}
|
|
121
|
-
function
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
$gte: today,
|
|
127
|
-
$lte: formatEndDate(today)
|
|
128
|
-
};
|
|
129
|
-
} else if (period === "thisWeek" || period === "thisMonth") {
|
|
130
|
-
const filterDate = period === "thisWeek" ? 7 : 30;
|
|
131
|
-
const filterStartDate = /* @__PURE__ */ new Date();
|
|
132
|
-
filterStartDate.setDate(today.getDate() - filterDate);
|
|
133
|
-
filterStartDate.setHours(0, 0, 0, 0);
|
|
134
|
-
query.createdAt = {
|
|
135
|
-
$gte: filterStartDate,
|
|
136
|
-
$lte: formatEndDate(/* @__PURE__ */ new Date())
|
|
137
|
-
};
|
|
107
|
+
function getDateRange(p) {
|
|
108
|
+
const start = /* @__PURE__ */ new Date();
|
|
109
|
+
start.setHours(0, 0, 0, 0);
|
|
110
|
+
if (p === "today") {
|
|
111
|
+
return { $gte: start, $lte: formatEndDate(start) };
|
|
138
112
|
}
|
|
139
|
-
|
|
113
|
+
const days = p === "thisWeek" ? 7 : 30;
|
|
114
|
+
const rangeStart = /* @__PURE__ */ new Date();
|
|
115
|
+
rangeStart.setDate(start.getDate() - days);
|
|
116
|
+
rangeStart.setHours(0, 0, 0, 0);
|
|
117
|
+
return { $gte: rangeStart, $lte: formatEndDate(/* @__PURE__ */ new Date()) };
|
|
118
|
+
}
|
|
119
|
+
const calculatePercentageChange = (currentCount, previousCount) => {
|
|
120
|
+
if (previousCount === 0) {
|
|
121
|
+
return currentCount > 0 ? 100 : 0;
|
|
122
|
+
}
|
|
123
|
+
return Math.round(
|
|
124
|
+
(currentCount - previousCount) / previousCount * 100 * 100
|
|
125
|
+
) / 100;
|
|
126
|
+
};
|
|
127
|
+
const workOrderService = workOrderServiceMap[serviceType] ?? serviceType;
|
|
140
128
|
try {
|
|
141
|
-
applyPeriodToQuery(countQueries.feedback, feedbackPeriod);
|
|
142
|
-
applyPeriodToQuery(countQueries.commonArea, commonAreaPeriod);
|
|
143
|
-
applyPeriodToQuery(countQueries.toiletArea, toiletAreaPeriod);
|
|
144
|
-
applyPeriodToQuery(countQueries.scheduleTask, scheduleTaskPeriod);
|
|
145
|
-
applyPeriodToQuery(countQueries.supply, supplyPeriod);
|
|
146
|
-
applyPeriodToQuery(countQueries.requestItem, requestItemPeriod);
|
|
147
129
|
const today = /* @__PURE__ */ new Date();
|
|
148
130
|
today.setHours(0, 0, 0, 0);
|
|
149
131
|
const yesterday = /* @__PURE__ */ new Date();
|
|
@@ -151,359 +133,566 @@ function useHygieneDashboardRepository() {
|
|
|
151
133
|
yesterday.setHours(0, 0, 0, 0);
|
|
152
134
|
const yesterdayEnd = new Date(yesterday);
|
|
153
135
|
yesterdayEnd.setHours(23, 59, 59, 999);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
$gte: yesterday,
|
|
157
|
-
$lte: yesterdayEnd
|
|
158
|
-
};
|
|
159
|
-
});
|
|
160
|
-
Object.keys(todayQueries).forEach((key) => {
|
|
161
|
-
todayQueries[key].createdAt = {
|
|
162
|
-
$gte: today,
|
|
163
|
-
$lte: formatEndDate(/* @__PURE__ */ new Date())
|
|
164
|
-
};
|
|
165
|
-
});
|
|
166
|
-
const calculatePercentageChange = (currentCount, previousCount) => {
|
|
167
|
-
if (previousCount === 0) {
|
|
168
|
-
return currentCount > 0 ? 100 : 0;
|
|
169
|
-
}
|
|
170
|
-
return Math.round(
|
|
171
|
-
(currentCount - previousCount) / previousCount * 100 * 100
|
|
172
|
-
) / 100;
|
|
173
|
-
};
|
|
136
|
+
const todayEnd = formatEndDate(/* @__PURE__ */ new Date());
|
|
137
|
+
const periodRange = getDateRange(period);
|
|
174
138
|
const [
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
139
|
+
workOrderReport,
|
|
140
|
+
supplyAlertReport,
|
|
141
|
+
taskCompletedReport,
|
|
142
|
+
yesterdayWorkOrderReport,
|
|
143
|
+
todayWorkOrderReport,
|
|
144
|
+
yesterdayTaskCompletedReport,
|
|
145
|
+
todayTaskCompletedReport
|
|
181
146
|
] = await Promise.all([
|
|
182
|
-
|
|
147
|
+
// 1. Open work orders (period-filtered) with inProgress breakdown
|
|
148
|
+
workOrderCollection.aggregate([
|
|
183
149
|
{
|
|
184
150
|
$match: {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
151
|
+
site,
|
|
152
|
+
service: workOrderService,
|
|
153
|
+
createdAt: periodRange,
|
|
154
|
+
status: { $nin: ["completed"] }
|
|
188
155
|
}
|
|
189
156
|
},
|
|
157
|
+
{
|
|
158
|
+
$facet: {
|
|
159
|
+
total: [{ $count: "count" }],
|
|
160
|
+
inProgress: [
|
|
161
|
+
{ $match: { status: "in-progress" } },
|
|
162
|
+
{ $count: "count" }
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
]).toArray(),
|
|
167
|
+
// 2. Supply alert — out-of-stock active supplies for site+serviceType
|
|
168
|
+
supplyCollection.aggregate([
|
|
169
|
+
{ $match: { site, serviceType, qty: 0, status: "active" } },
|
|
190
170
|
{ $count: "count" }
|
|
191
171
|
]).toArray(),
|
|
172
|
+
// 3. Task completed — area checklists (period-filtered via schedule join)
|
|
192
173
|
areaChecklistCollection.aggregate([
|
|
193
|
-
|
|
174
|
+
...areaChecklistScheduleLookup(site, serviceType, periodRange),
|
|
194
175
|
{
|
|
195
|
-
$
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
] : [{ $match: { site } }]
|
|
176
|
+
$facet: {
|
|
177
|
+
total: [{ $count: "count" }],
|
|
178
|
+
completed: [
|
|
179
|
+
{ $match: { status: "completed" } },
|
|
180
|
+
{ $count: "count" }
|
|
181
|
+
],
|
|
182
|
+
inProgress: [
|
|
183
|
+
{ $match: { status: { $in: ["open", "ongoing"] } } },
|
|
184
|
+
{ $count: "count" }
|
|
185
|
+
]
|
|
208
186
|
}
|
|
209
|
-
}
|
|
187
|
+
}
|
|
188
|
+
]).toArray(),
|
|
189
|
+
// 4. Yesterday open work orders (for % change)
|
|
190
|
+
workOrderCollection.aggregate([
|
|
210
191
|
{
|
|
211
|
-
$
|
|
212
|
-
|
|
213
|
-
|
|
192
|
+
$match: {
|
|
193
|
+
site,
|
|
194
|
+
service: workOrderService,
|
|
195
|
+
createdAt: { $gte: yesterday, $lte: yesterdayEnd },
|
|
196
|
+
status: { $nin: ["completed"] }
|
|
214
197
|
}
|
|
215
198
|
},
|
|
216
199
|
{ $count: "count" }
|
|
217
200
|
]).toArray(),
|
|
218
|
-
|
|
219
|
-
|
|
201
|
+
// 5. Today open work orders (for % change)
|
|
202
|
+
workOrderCollection.aggregate([
|
|
220
203
|
{
|
|
221
|
-
$
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
pipeline: countQueries.toiletArea.createdAt ? [
|
|
227
|
-
{
|
|
228
|
-
$match: {
|
|
229
|
-
site,
|
|
230
|
-
createdAt: countQueries.toiletArea.createdAt
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
] : [{ $match: { site } }]
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
$unwind: {
|
|
238
|
-
path: "$scheduleDoc",
|
|
239
|
-
preserveNullAndEmptyArrays: false
|
|
204
|
+
$match: {
|
|
205
|
+
site,
|
|
206
|
+
service: workOrderService,
|
|
207
|
+
createdAt: { $gte: today, $lte: todayEnd },
|
|
208
|
+
status: { $nin: ["completed"] }
|
|
240
209
|
}
|
|
241
210
|
},
|
|
242
211
|
{ $count: "count" }
|
|
243
212
|
]).toArray(),
|
|
244
|
-
|
|
245
|
-
|
|
213
|
+
// 6. Yesterday task completed — area checklists (for % change)
|
|
214
|
+
areaChecklistCollection.aggregate([
|
|
215
|
+
...areaChecklistScheduleLookup(site, serviceType, {
|
|
216
|
+
$gte: yesterday,
|
|
217
|
+
$lte: yesterdayEnd
|
|
218
|
+
}),
|
|
219
|
+
{ $match: { status: "completed" } },
|
|
246
220
|
{ $count: "count" }
|
|
247
221
|
]).toArray(),
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
222
|
+
// 7. Today task completed — area checklists (for % change)
|
|
223
|
+
areaChecklistCollection.aggregate([
|
|
224
|
+
...areaChecklistScheduleLookup(site, serviceType, {
|
|
225
|
+
$gte: today,
|
|
226
|
+
$lte: todayEnd
|
|
227
|
+
}),
|
|
228
|
+
{ $match: { status: "completed" } },
|
|
251
229
|
{ $count: "count" }
|
|
252
230
|
]).toArray()
|
|
253
231
|
]);
|
|
254
|
-
const [
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
232
|
+
const wFacet = workOrderReport[0] ?? { total: [], inProgress: [] };
|
|
233
|
+
const tFacet = taskCompletedReport[0] ?? {
|
|
234
|
+
total: [],
|
|
235
|
+
completed: [],
|
|
236
|
+
inProgress: []
|
|
237
|
+
};
|
|
238
|
+
const result = {
|
|
239
|
+
openWorkOrder: {
|
|
240
|
+
count: wFacet.total[0]?.count ?? 0,
|
|
241
|
+
inProgress: wFacet.inProgress[0]?.count ?? 0,
|
|
242
|
+
percentage: calculatePercentageChange(
|
|
243
|
+
todayWorkOrderReport[0]?.count ?? 0,
|
|
244
|
+
yesterdayWorkOrderReport[0]?.count ?? 0
|
|
245
|
+
)
|
|
246
|
+
},
|
|
247
|
+
supplyAlert: {
|
|
248
|
+
count: supplyAlertReport[0]?.count ?? 0,
|
|
249
|
+
percentage: 0
|
|
250
|
+
},
|
|
251
|
+
taskCompleted: {
|
|
252
|
+
completed: tFacet.completed[0]?.count ?? 0,
|
|
253
|
+
total: tFacet.total[0]?.count ?? 0,
|
|
254
|
+
inProgress: tFacet.inProgress[0]?.count ?? 0,
|
|
255
|
+
percentage: calculatePercentageChange(
|
|
256
|
+
todayTaskCompletedReport[0]?.count ?? 0,
|
|
257
|
+
yesterdayTaskCompletedReport[0]?.count ?? 0
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
setCache(dashboardCacheKey, result, 15 * 60).then(() => {
|
|
262
|
+
logger.info(`Cache set for dashboard: ${dashboardCacheKey}`);
|
|
263
|
+
}).catch((err) => {
|
|
264
|
+
logger.error(
|
|
265
|
+
`Failed to set cache for dashboard: ${dashboardCacheKey}`,
|
|
266
|
+
err
|
|
267
|
+
);
|
|
268
|
+
});
|
|
269
|
+
return result;
|
|
270
|
+
} catch (error) {
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
async function getWeeklyActivity({
|
|
275
|
+
site,
|
|
276
|
+
serviceType
|
|
277
|
+
}) {
|
|
278
|
+
const cacheOptions = { serviceType };
|
|
279
|
+
try {
|
|
280
|
+
site = new ObjectId(site);
|
|
281
|
+
cacheOptions.site = site.toString();
|
|
282
|
+
} catch {
|
|
283
|
+
throw new BadRequestError("Invalid site ID format.");
|
|
284
|
+
}
|
|
285
|
+
const cacheKey = makeCacheKey(
|
|
286
|
+
`${dashboard_namespace_collection}:weeklyActivity`,
|
|
287
|
+
cacheOptions
|
|
288
|
+
);
|
|
289
|
+
const cachedData = await getCache(cacheKey);
|
|
290
|
+
if (cachedData) {
|
|
291
|
+
logger.info(`Cache hit for weeklyActivity: ${cacheKey}`);
|
|
292
|
+
return cachedData;
|
|
293
|
+
}
|
|
294
|
+
const workOrderService = workOrderServiceMap[serviceType] ?? serviceType;
|
|
295
|
+
const weekStart = moment.tz("Asia/Singapore").startOf("isoWeek").toDate();
|
|
296
|
+
const weekEnd = moment.tz("Asia/Singapore").endOf("isoWeek").toDate();
|
|
297
|
+
const weekRange = { $gte: weekStart, $lte: weekEnd };
|
|
298
|
+
const dayLabels = {
|
|
299
|
+
1: "Sun",
|
|
300
|
+
2: "Mon",
|
|
301
|
+
3: "Tue",
|
|
302
|
+
4: "Wed",
|
|
303
|
+
5: "Thu",
|
|
304
|
+
6: "Fri",
|
|
305
|
+
7: "Sat"
|
|
306
|
+
};
|
|
307
|
+
const dayOrder = [2, 3, 4, 5, 6, 7, 1];
|
|
308
|
+
try {
|
|
309
|
+
const [workOrderByDay, taskCompletedByDay] = await Promise.all([
|
|
310
|
+
workOrderCollection.aggregate([
|
|
263
311
|
{
|
|
264
|
-
$match: {
|
|
265
|
-
...yesterDayQueries.feedback,
|
|
266
|
-
category: "cleaning_services",
|
|
267
|
-
status: "to-do"
|
|
268
|
-
}
|
|
312
|
+
$match: { site, service: workOrderService, createdAt: weekRange }
|
|
269
313
|
},
|
|
270
|
-
{
|
|
314
|
+
{
|
|
315
|
+
$group: { _id: { $dayOfWeek: "$createdAt" }, count: { $sum: 1 } }
|
|
316
|
+
}
|
|
271
317
|
]).toArray(),
|
|
272
318
|
areaChecklistCollection.aggregate([
|
|
273
|
-
|
|
319
|
+
...areaChecklistScheduleLookup(site, serviceType, weekRange),
|
|
320
|
+
{ $match: { status: "completed" } },
|
|
274
321
|
{
|
|
275
|
-
$
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
foreignField: "_id",
|
|
279
|
-
as: "scheduleDoc",
|
|
280
|
-
pipeline: [
|
|
281
|
-
{
|
|
282
|
-
$match: {
|
|
283
|
-
site,
|
|
284
|
-
createdAt: yesterDayQueries.commonArea.createdAt
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
]
|
|
322
|
+
$group: {
|
|
323
|
+
_id: { $dayOfWeek: "$completedAt" },
|
|
324
|
+
count: { $sum: 1 }
|
|
288
325
|
}
|
|
289
|
-
}
|
|
326
|
+
}
|
|
327
|
+
]).toArray()
|
|
328
|
+
]);
|
|
329
|
+
const workOrderMap = new Map(
|
|
330
|
+
workOrderByDay.map((d) => [d._id, d.count])
|
|
331
|
+
);
|
|
332
|
+
const taskMap = new Map(
|
|
333
|
+
taskCompletedByDay.map((d) => [d._id, d.count])
|
|
334
|
+
);
|
|
335
|
+
const result = dayOrder.map((dow) => ({
|
|
336
|
+
day: dayLabels[dow],
|
|
337
|
+
workOrder: workOrderMap.get(dow) ?? 0,
|
|
338
|
+
taskCompleted: taskMap.get(dow) ?? 0
|
|
339
|
+
}));
|
|
340
|
+
setCache(cacheKey, result, 15 * 60).then(() => {
|
|
341
|
+
logger.info(`Cache set for weeklyActivity: ${cacheKey}`);
|
|
342
|
+
}).catch((err) => {
|
|
343
|
+
logger.error(
|
|
344
|
+
`Failed to set cache for weeklyActivity: ${cacheKey}`,
|
|
345
|
+
err
|
|
346
|
+
);
|
|
347
|
+
});
|
|
348
|
+
return result;
|
|
349
|
+
} catch (error) {
|
|
350
|
+
throw error;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
async function getTodayTaskSchedule({
|
|
354
|
+
site,
|
|
355
|
+
serviceType,
|
|
356
|
+
page = 1,
|
|
357
|
+
limit = 10
|
|
358
|
+
}) {
|
|
359
|
+
page = page > 0 ? page - 1 : 0;
|
|
360
|
+
const cacheOptions = { serviceType, page, limit };
|
|
361
|
+
try {
|
|
362
|
+
site = new ObjectId(site);
|
|
363
|
+
cacheOptions.site = site.toString();
|
|
364
|
+
} catch {
|
|
365
|
+
throw new BadRequestError("Invalid site ID format.");
|
|
366
|
+
}
|
|
367
|
+
const cacheKey = makeCacheKey(
|
|
368
|
+
`${dashboard_namespace_collection}:todayTaskSchedule`,
|
|
369
|
+
cacheOptions
|
|
370
|
+
);
|
|
371
|
+
const cachedData = await getCache(cacheKey);
|
|
372
|
+
if (cachedData) {
|
|
373
|
+
logger.info(`Cache hit for todayTaskSchedule: ${cacheKey}`);
|
|
374
|
+
return cachedData;
|
|
375
|
+
}
|
|
376
|
+
const todayStart = moment.tz("Asia/Singapore").startOf("day").toDate();
|
|
377
|
+
const todayEnd = moment.tz("Asia/Singapore").endOf("day").toDate();
|
|
378
|
+
const todayRange = { $gte: todayStart, $lte: todayEnd };
|
|
379
|
+
try {
|
|
380
|
+
const [items, countResult] = await Promise.all([
|
|
381
|
+
areaChecklistCollection.aggregate([
|
|
382
|
+
...areaChecklistScheduleLookup(site, serviceType, todayRange),
|
|
290
383
|
{
|
|
291
|
-
$
|
|
292
|
-
|
|
293
|
-
|
|
384
|
+
$addFields: {
|
|
385
|
+
_assigneeId: {
|
|
386
|
+
$reduce: {
|
|
387
|
+
input: { $ifNull: ["$checklist", []] },
|
|
388
|
+
initialValue: null,
|
|
389
|
+
in: {
|
|
390
|
+
$cond: {
|
|
391
|
+
if: { $ne: ["$$value", null] },
|
|
392
|
+
then: "$$value",
|
|
393
|
+
else: {
|
|
394
|
+
$reduce: {
|
|
395
|
+
input: { $ifNull: ["$$this.units", []] },
|
|
396
|
+
initialValue: null,
|
|
397
|
+
in: {
|
|
398
|
+
$cond: {
|
|
399
|
+
if: { $ne: ["$$value", null] },
|
|
400
|
+
then: "$$value",
|
|
401
|
+
else: {
|
|
402
|
+
$cond: {
|
|
403
|
+
if: { $gt: ["$$this.completedBy", null] },
|
|
404
|
+
then: "$$this.completedBy",
|
|
405
|
+
else: null
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
294
416
|
}
|
|
295
417
|
},
|
|
296
|
-
{ $count: "count" }
|
|
297
|
-
]).toArray(),
|
|
298
|
-
areaChecklistCollection.aggregate([
|
|
299
|
-
{ $match: { type: "toilet" } },
|
|
300
418
|
{
|
|
301
419
|
$lookup: {
|
|
302
|
-
from:
|
|
303
|
-
localField: "
|
|
420
|
+
from: "users",
|
|
421
|
+
localField: "_assigneeId",
|
|
304
422
|
foreignField: "_id",
|
|
305
|
-
as: "
|
|
306
|
-
pipeline: [
|
|
307
|
-
{
|
|
308
|
-
$match: {
|
|
309
|
-
site,
|
|
310
|
-
createdAt: yesterDayQueries.toiletArea.createdAt
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
]
|
|
423
|
+
as: "_assigneeDoc"
|
|
314
424
|
}
|
|
315
425
|
},
|
|
426
|
+
{ $sort: { createdAt: -1, _id: -1 } },
|
|
316
427
|
{
|
|
317
|
-
$
|
|
318
|
-
|
|
319
|
-
|
|
428
|
+
$project: {
|
|
429
|
+
name: 1,
|
|
430
|
+
type: 1,
|
|
431
|
+
status: 1,
|
|
432
|
+
assigneeName: { $arrayElemAt: ["$_assigneeDoc.name", 0] }
|
|
320
433
|
}
|
|
321
434
|
},
|
|
322
|
-
{ $
|
|
435
|
+
{ $skip: page * limit },
|
|
436
|
+
{ $limit: limit }
|
|
323
437
|
]).toArray(),
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
{ $count: "count" }
|
|
327
|
-
]).toArray(),
|
|
328
|
-
supplyCollection.aggregate([{ $match: yesterDayQueries.supply }, { $count: "count" }]).toArray(),
|
|
329
|
-
requestItemCollection.aggregate([
|
|
330
|
-
{ $match: yesterDayQueries.requestItem },
|
|
438
|
+
areaChecklistCollection.aggregate([
|
|
439
|
+
...areaChecklistScheduleLookup(site, serviceType, todayRange),
|
|
331
440
|
{ $count: "count" }
|
|
332
441
|
]).toArray()
|
|
333
442
|
]);
|
|
334
|
-
const [
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
443
|
+
const length = countResult[0]?.count ?? 0;
|
|
444
|
+
const data = paginate(items, page, limit, length);
|
|
445
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
446
|
+
logger.info(`Cache set for todayTaskSchedule: ${cacheKey}`);
|
|
447
|
+
}).catch((err) => {
|
|
448
|
+
logger.error(
|
|
449
|
+
`Failed to set cache for todayTaskSchedule: ${cacheKey}`,
|
|
450
|
+
err
|
|
451
|
+
);
|
|
452
|
+
});
|
|
453
|
+
return data;
|
|
454
|
+
} catch (error) {
|
|
455
|
+
throw error;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
async function getStaffAttendance({
|
|
459
|
+
site,
|
|
460
|
+
serviceType,
|
|
461
|
+
page = 1,
|
|
462
|
+
limit = 10
|
|
463
|
+
}) {
|
|
464
|
+
page = page > 0 ? page - 1 : 0;
|
|
465
|
+
const cacheOptions = { serviceType, page, limit };
|
|
466
|
+
try {
|
|
467
|
+
site = new ObjectId(site);
|
|
468
|
+
cacheOptions.site = site.toString();
|
|
469
|
+
} catch {
|
|
470
|
+
throw new BadRequestError("Invalid site ID format.");
|
|
471
|
+
}
|
|
472
|
+
const cacheKey = makeCacheKey(
|
|
473
|
+
`${dashboard_namespace_collection}:staffAttendance`,
|
|
474
|
+
cacheOptions
|
|
475
|
+
);
|
|
476
|
+
const cachedData = await getCache(cacheKey);
|
|
477
|
+
if (cachedData) {
|
|
478
|
+
logger.info(`Cache hit for staffAttendance: ${cacheKey}`);
|
|
479
|
+
return cachedData;
|
|
480
|
+
}
|
|
481
|
+
const todayStart = moment.tz("Asia/Singapore").startOf("day").toDate();
|
|
482
|
+
const todayEnd = moment.tz("Asia/Singapore").endOf("day").toDate();
|
|
483
|
+
const todayStartStr = todayStart.toISOString();
|
|
484
|
+
const todayEndStr = todayEnd.toISOString();
|
|
485
|
+
try {
|
|
486
|
+
const [items, length] = await Promise.all([
|
|
487
|
+
attendanceCollection.aggregate([
|
|
343
488
|
{
|
|
344
489
|
$match: {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
490
|
+
site,
|
|
491
|
+
serviceType,
|
|
492
|
+
$or: [
|
|
493
|
+
{ createdAt: { $gte: todayStart, $lte: todayEnd } },
|
|
494
|
+
{ createdAt: { $gte: todayStartStr, $lte: todayEndStr } }
|
|
495
|
+
]
|
|
348
496
|
}
|
|
349
497
|
},
|
|
350
|
-
{ $count: "count" }
|
|
351
|
-
]).toArray(),
|
|
352
|
-
areaChecklistCollection.aggregate([
|
|
353
|
-
{ $match: { type: "common" } },
|
|
354
498
|
{
|
|
355
499
|
$lookup: {
|
|
356
|
-
from:
|
|
357
|
-
localField: "
|
|
500
|
+
from: "users",
|
|
501
|
+
localField: "user",
|
|
358
502
|
foreignField: "_id",
|
|
359
|
-
as: "
|
|
503
|
+
as: "_userDoc"
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
$lookup: {
|
|
508
|
+
from: "members",
|
|
509
|
+
let: { userId: "$user", siteId: "$site", type: "$serviceType" },
|
|
360
510
|
pipeline: [
|
|
361
511
|
{
|
|
362
512
|
$match: {
|
|
363
|
-
|
|
364
|
-
|
|
513
|
+
$expr: {
|
|
514
|
+
$and: [
|
|
515
|
+
{ $eq: ["$user", "$$userId"] },
|
|
516
|
+
{ $eq: ["$siteId", "$$siteId"] },
|
|
517
|
+
{ $eq: ["$type", "$$type"] },
|
|
518
|
+
{ $ne: ["$status", "deleted"] }
|
|
519
|
+
]
|
|
520
|
+
}
|
|
365
521
|
}
|
|
366
522
|
}
|
|
367
|
-
]
|
|
523
|
+
],
|
|
524
|
+
as: "_memberDoc"
|
|
368
525
|
}
|
|
369
526
|
},
|
|
370
527
|
{
|
|
371
528
|
$unwind: {
|
|
372
|
-
path: "$
|
|
373
|
-
preserveNullAndEmptyArrays:
|
|
529
|
+
path: "$_memberDoc",
|
|
530
|
+
preserveNullAndEmptyArrays: true
|
|
374
531
|
}
|
|
375
532
|
},
|
|
376
|
-
{ $count: "count" }
|
|
377
|
-
]).toArray(),
|
|
378
|
-
areaChecklistCollection.aggregate([
|
|
379
|
-
{ $match: { type: "toilet" } },
|
|
380
533
|
{
|
|
381
534
|
$lookup: {
|
|
382
|
-
from:
|
|
383
|
-
localField: "
|
|
535
|
+
from: "roles",
|
|
536
|
+
localField: "_memberDoc.role",
|
|
384
537
|
foreignField: "_id",
|
|
385
|
-
as: "
|
|
386
|
-
pipeline: [
|
|
387
|
-
{
|
|
388
|
-
$match: {
|
|
389
|
-
site,
|
|
390
|
-
createdAt: todayQueries.toiletArea.createdAt
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
]
|
|
538
|
+
as: "_roleDoc"
|
|
394
539
|
}
|
|
395
540
|
},
|
|
396
541
|
{
|
|
397
542
|
$unwind: {
|
|
398
|
-
path: "$
|
|
399
|
-
preserveNullAndEmptyArrays:
|
|
543
|
+
path: "$_roleDoc",
|
|
544
|
+
preserveNullAndEmptyArrays: true
|
|
400
545
|
}
|
|
401
546
|
},
|
|
402
|
-
{ $
|
|
547
|
+
{ $sort: { createdAt: -1, _id: -1 } },
|
|
548
|
+
{
|
|
549
|
+
$project: {
|
|
550
|
+
checkIn: 1,
|
|
551
|
+
checkOut: 1,
|
|
552
|
+
createdAt: 1,
|
|
553
|
+
userName: { $arrayElemAt: ["$_userDoc.name", 0] },
|
|
554
|
+
userRole: { $ifNull: ["$_roleDoc.name", ""] },
|
|
555
|
+
totalHours: {
|
|
556
|
+
$round: [
|
|
557
|
+
{
|
|
558
|
+
$divide: [
|
|
559
|
+
{
|
|
560
|
+
$subtract: [
|
|
561
|
+
{
|
|
562
|
+
$toDate: {
|
|
563
|
+
$ifNull: ["$checkOut.timestamp", "$$NOW"]
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
{ $toDate: "$checkIn.timestamp" }
|
|
567
|
+
]
|
|
568
|
+
},
|
|
569
|
+
36e5
|
|
570
|
+
]
|
|
571
|
+
},
|
|
572
|
+
2
|
|
573
|
+
]
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
{ $skip: page * limit },
|
|
578
|
+
{ $limit: limit }
|
|
403
579
|
]).toArray(),
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
580
|
+
attendanceCollection.countDocuments({
|
|
581
|
+
site,
|
|
582
|
+
serviceType,
|
|
583
|
+
$or: [
|
|
584
|
+
{ createdAt: { $gte: todayStart, $lte: todayEnd } },
|
|
585
|
+
{ createdAt: { $gte: todayStartStr, $lte: todayEndStr } }
|
|
586
|
+
]
|
|
587
|
+
})
|
|
588
|
+
]);
|
|
589
|
+
const data = paginate(items, page, limit, length);
|
|
590
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
591
|
+
logger.info(`Cache set for staffAttendance: ${cacheKey}`);
|
|
592
|
+
}).catch((err) => {
|
|
593
|
+
logger.error(
|
|
594
|
+
`Failed to set cache for staffAttendance: ${cacheKey}`,
|
|
595
|
+
err
|
|
596
|
+
);
|
|
597
|
+
});
|
|
598
|
+
return data;
|
|
599
|
+
} catch (error) {
|
|
600
|
+
throw error;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
async function getRecentFeedbacks({
|
|
604
|
+
site,
|
|
605
|
+
serviceType,
|
|
606
|
+
page = 1,
|
|
607
|
+
limit = 10
|
|
608
|
+
}) {
|
|
609
|
+
page = page > 0 ? page - 1 : 0;
|
|
610
|
+
const cacheOptions = { serviceType, page, limit };
|
|
611
|
+
try {
|
|
612
|
+
site = new ObjectId(site);
|
|
613
|
+
cacheOptions.site = site.toString();
|
|
614
|
+
} catch {
|
|
615
|
+
throw new BadRequestError("Invalid site ID format.");
|
|
616
|
+
}
|
|
617
|
+
const cacheKey = makeCacheKey(
|
|
618
|
+
`${dashboard_namespace_collection}:recentFeedbacks`,
|
|
619
|
+
cacheOptions
|
|
620
|
+
);
|
|
621
|
+
const cachedData = await getCache(cacheKey);
|
|
622
|
+
if (cachedData) {
|
|
623
|
+
logger.info(`Cache hit for recentFeedbacks: ${cacheKey}`);
|
|
624
|
+
return cachedData;
|
|
625
|
+
}
|
|
626
|
+
const workOrderService = workOrderServiceMap[serviceType] ?? serviceType;
|
|
627
|
+
try {
|
|
628
|
+
const [items, length] = await Promise.all([
|
|
629
|
+
feedbackCollection.aggregate([
|
|
630
|
+
{ $match: { site, service: workOrderService } },
|
|
631
|
+
{ $sort: { createdAt: -1, _id: -1 } },
|
|
632
|
+
{
|
|
633
|
+
$lookup: {
|
|
634
|
+
from: "users",
|
|
635
|
+
localField: "createdBy",
|
|
636
|
+
foreignField: "_id",
|
|
637
|
+
as: "_createdByDoc"
|
|
638
|
+
}
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
$project: {
|
|
642
|
+
description: 1,
|
|
643
|
+
subject: 1,
|
|
644
|
+
app: 1,
|
|
645
|
+
status: 1,
|
|
646
|
+
createdAt: 1,
|
|
647
|
+
createdByName: { $arrayElemAt: ["$_createdByDoc.name", 0] }
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
{ $skip: page * limit },
|
|
651
|
+
{ $limit: limit }
|
|
407
652
|
]).toArray(),
|
|
408
|
-
|
|
409
|
-
requestItemCollection.aggregate([
|
|
410
|
-
{ $match: todayQueries.requestItem },
|
|
411
|
-
{ $count: "count" }
|
|
412
|
-
]).toArray()
|
|
653
|
+
feedbackCollection.countDocuments({ site, service: workOrderService })
|
|
413
654
|
]);
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
toiletAreaChecklistCount: yesterdayToiletAreaChecklistCount[0]?.count || 0,
|
|
418
|
-
scheduleTaskCount: yesterdayScheduledTaskCount[0]?.count || 0,
|
|
419
|
-
supplyCount: yesterdaySupplyCount[0]?.count || 0,
|
|
420
|
-
requestItemCount: yesterdayRequestItemCount[0]?.count || 0
|
|
421
|
-
};
|
|
422
|
-
const resultToday = {
|
|
423
|
-
feedbackCount: todayFeedbackCount[0]?.count || 0,
|
|
424
|
-
commonAreaChecklistCount: todayCommonAreaChecklistCount[0]?.count || 0,
|
|
425
|
-
toiletAreaChecklistCount: todayToiletAreaChecklistCount[0]?.count || 0,
|
|
426
|
-
scheduleTaskCount: todayScheduledTaskCount[0]?.count || 0,
|
|
427
|
-
supplyCount: todaySupplyCount[0]?.count || 0,
|
|
428
|
-
requestItemCount: todayRequestItemCount[0]?.count || 0
|
|
429
|
-
};
|
|
430
|
-
const result = {
|
|
431
|
-
feedback: {
|
|
432
|
-
count: feedbackReport[0]?.count || 0,
|
|
433
|
-
percentage: calculatePercentageChange(
|
|
434
|
-
resultToday.feedbackCount,
|
|
435
|
-
resultYesterday.feedbackCount
|
|
436
|
-
)
|
|
437
|
-
},
|
|
438
|
-
commonAreaChecklist: {
|
|
439
|
-
count: commonAreaChecklistReport[0]?.count || 0,
|
|
440
|
-
percentage: calculatePercentageChange(
|
|
441
|
-
resultToday.commonAreaChecklistCount,
|
|
442
|
-
resultYesterday.commonAreaChecklistCount
|
|
443
|
-
)
|
|
444
|
-
},
|
|
445
|
-
toiletAreaChecklist: {
|
|
446
|
-
count: toiletAreaChecklistReport[0]?.count || 0,
|
|
447
|
-
percentage: calculatePercentageChange(
|
|
448
|
-
resultToday.toiletAreaChecklistCount,
|
|
449
|
-
resultYesterday.toiletAreaChecklistCount
|
|
450
|
-
)
|
|
451
|
-
},
|
|
452
|
-
scheduleTask: {
|
|
453
|
-
count: scheduleTaskReport[0]?.count || 0,
|
|
454
|
-
percentage: calculatePercentageChange(
|
|
455
|
-
resultToday.scheduleTaskCount,
|
|
456
|
-
resultYesterday.scheduleTaskCount
|
|
457
|
-
)
|
|
458
|
-
},
|
|
459
|
-
supply: {
|
|
460
|
-
count: supplyReport[0]?.count || 0,
|
|
461
|
-
percentage: calculatePercentageChange(
|
|
462
|
-
resultToday.supplyCount,
|
|
463
|
-
resultYesterday.supplyCount
|
|
464
|
-
)
|
|
465
|
-
},
|
|
466
|
-
requestItem: {
|
|
467
|
-
count: requestItemReport[0]?.count || 0,
|
|
468
|
-
percentage: calculatePercentageChange(
|
|
469
|
-
resultToday.requestItemCount,
|
|
470
|
-
resultYesterday.requestItemCount
|
|
471
|
-
)
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
setCache(dashboardCacheKey, result, 15 * 60).then(() => {
|
|
475
|
-
logger.info(`Cache set for dashboard: ${dashboardCacheKey}`);
|
|
655
|
+
const data = paginate(items, page, limit, length);
|
|
656
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
657
|
+
logger.info(`Cache set for recentFeedbacks: ${cacheKey}`);
|
|
476
658
|
}).catch((err) => {
|
|
477
659
|
logger.error(
|
|
478
|
-
`Failed to set cache for
|
|
660
|
+
`Failed to set cache for recentFeedbacks: ${cacheKey}`,
|
|
479
661
|
err
|
|
480
662
|
);
|
|
481
663
|
});
|
|
482
|
-
return
|
|
664
|
+
return data;
|
|
483
665
|
} catch (error) {
|
|
484
666
|
throw error;
|
|
485
667
|
}
|
|
486
668
|
}
|
|
487
669
|
return {
|
|
488
|
-
getHygieneDashboard
|
|
670
|
+
getHygieneDashboard,
|
|
671
|
+
getWeeklyActivity,
|
|
672
|
+
getTodayTaskSchedule,
|
|
673
|
+
getStaffAttendance,
|
|
674
|
+
getRecentFeedbacks
|
|
489
675
|
};
|
|
490
676
|
}
|
|
491
677
|
|
|
492
678
|
// src/controllers/hygiene-dashboard.controller.ts
|
|
493
679
|
import Joi from "joi";
|
|
494
680
|
import { BadRequestError as BadRequestError2, logger as logger2 } from "@7365admin1/node-server-utils";
|
|
681
|
+
import { AppServiceType } from "@7365admin1/core";
|
|
495
682
|
function useHygieneDashboardController() {
|
|
496
|
-
const {
|
|
683
|
+
const {
|
|
684
|
+
getHygieneDashboard: _getHygieneDashboard,
|
|
685
|
+
getWeeklyActivity: _getWeeklyActivity,
|
|
686
|
+
getTodayTaskSchedule: _getTodayTaskSchedule,
|
|
687
|
+
getStaffAttendance: _getStaffAttendance,
|
|
688
|
+
getRecentFeedbacks: _getRecentFeedbacks
|
|
689
|
+
} = useHygieneDashboardRepository();
|
|
497
690
|
async function getHygieneDashboard(req, res, next) {
|
|
498
691
|
const query = { ...req.query, ...req.params };
|
|
499
692
|
const validation = Joi.object({
|
|
500
693
|
site: Joi.string().hex().required(),
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
toiletAreaPeriod: Joi.string().valid(...allowedPeriods).optional(),
|
|
504
|
-
scheduleTaskPeriod: Joi.string().valid(...allowedPeriods).optional(),
|
|
505
|
-
supplyPeriod: Joi.string().valid(...allowedPeriods).optional(),
|
|
506
|
-
requestItemPeriod: Joi.string().valid(...allowedPeriods).optional()
|
|
694
|
+
serviceType: Joi.string().valid(...Object.values(AppServiceType)).required(),
|
|
695
|
+
period: Joi.string().valid(...allowedPeriods).optional()
|
|
507
696
|
});
|
|
508
697
|
const { error } = validation.validate(query);
|
|
509
698
|
if (error) {
|
|
@@ -512,21 +701,136 @@ function useHygieneDashboardController() {
|
|
|
512
701
|
return;
|
|
513
702
|
}
|
|
514
703
|
const site = req.params.site ?? "";
|
|
515
|
-
const
|
|
516
|
-
const
|
|
517
|
-
const toiletAreaPeriod = req.query.toiletAreaPeriod || "today";
|
|
518
|
-
const scheduleTaskPeriod = req.query.scheduleTaskPeriod || "today";
|
|
519
|
-
const supplyPeriod = req.query.supplyPeriod || "today";
|
|
520
|
-
const requestItemPeriod = req.query.requestItemPeriod || "today";
|
|
704
|
+
const serviceType = req.params.serviceType;
|
|
705
|
+
const period = req.query.period || "today";
|
|
521
706
|
try {
|
|
522
707
|
const data = await _getHygieneDashboard({
|
|
523
708
|
site,
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
709
|
+
period,
|
|
710
|
+
serviceType
|
|
711
|
+
});
|
|
712
|
+
res.json(data);
|
|
713
|
+
return;
|
|
714
|
+
} catch (error2) {
|
|
715
|
+
logger2.log({ level: "error", message: error2.message });
|
|
716
|
+
next(error2);
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
async function getWeeklyActivity(req, res, next) {
|
|
721
|
+
const query = { ...req.params };
|
|
722
|
+
const validation = Joi.object({
|
|
723
|
+
site: Joi.string().hex().required(),
|
|
724
|
+
serviceType: Joi.string().valid(...Object.values(AppServiceType)).required()
|
|
725
|
+
});
|
|
726
|
+
const { error } = validation.validate(query);
|
|
727
|
+
if (error) {
|
|
728
|
+
logger2.log({ level: "error", message: error.message });
|
|
729
|
+
next(new BadRequestError2(error.message));
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
const site = req.params.site;
|
|
733
|
+
const serviceType = req.params.serviceType;
|
|
734
|
+
try {
|
|
735
|
+
const data = await _getWeeklyActivity({ site, serviceType });
|
|
736
|
+
res.json(data);
|
|
737
|
+
return;
|
|
738
|
+
} catch (error2) {
|
|
739
|
+
logger2.log({ level: "error", message: error2.message });
|
|
740
|
+
next(error2);
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
async function getTodayTaskSchedule(req, res, next) {
|
|
745
|
+
const query = { ...req.query, ...req.params };
|
|
746
|
+
const validation = Joi.object({
|
|
747
|
+
site: Joi.string().hex().required(),
|
|
748
|
+
serviceType: Joi.string().valid(...Object.values(AppServiceType)).required(),
|
|
749
|
+
page: Joi.number().min(1).optional().allow("", null),
|
|
750
|
+
limit: Joi.number().min(1).optional().allow("", null)
|
|
751
|
+
});
|
|
752
|
+
const { error } = validation.validate(query);
|
|
753
|
+
if (error) {
|
|
754
|
+
logger2.log({ level: "error", message: error.message });
|
|
755
|
+
next(new BadRequestError2(error.message));
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
const site = req.params.site;
|
|
759
|
+
const serviceType = req.params.serviceType;
|
|
760
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
761
|
+
const limit = parseInt(req.query.limit) ?? 10;
|
|
762
|
+
try {
|
|
763
|
+
const data = await _getTodayTaskSchedule({
|
|
764
|
+
site,
|
|
765
|
+
serviceType,
|
|
766
|
+
page,
|
|
767
|
+
limit
|
|
768
|
+
});
|
|
769
|
+
res.json(data);
|
|
770
|
+
return;
|
|
771
|
+
} catch (error2) {
|
|
772
|
+
logger2.log({ level: "error", message: error2.message });
|
|
773
|
+
next(error2);
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
async function getStaffAttendance(req, res, next) {
|
|
778
|
+
const query = { ...req.query, ...req.params };
|
|
779
|
+
const validation = Joi.object({
|
|
780
|
+
site: Joi.string().hex().required(),
|
|
781
|
+
serviceType: Joi.string().valid(...Object.values(AppServiceType)).required(),
|
|
782
|
+
page: Joi.number().min(1).optional().allow("", null),
|
|
783
|
+
limit: Joi.number().min(1).optional().allow("", null)
|
|
784
|
+
});
|
|
785
|
+
const { error } = validation.validate(query);
|
|
786
|
+
if (error) {
|
|
787
|
+
logger2.log({ level: "error", message: error.message });
|
|
788
|
+
next(new BadRequestError2(error.message));
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
const site = req.params.site;
|
|
792
|
+
const serviceType = req.params.serviceType;
|
|
793
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
794
|
+
const limit = parseInt(req.query.limit) ?? 10;
|
|
795
|
+
try {
|
|
796
|
+
const data = await _getStaffAttendance({
|
|
797
|
+
site,
|
|
798
|
+
serviceType,
|
|
799
|
+
page,
|
|
800
|
+
limit
|
|
801
|
+
});
|
|
802
|
+
res.json(data);
|
|
803
|
+
return;
|
|
804
|
+
} catch (error2) {
|
|
805
|
+
logger2.log({ level: "error", message: error2.message });
|
|
806
|
+
next(error2);
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
async function getRecentFeedbacks(req, res, next) {
|
|
811
|
+
const query = { ...req.query, ...req.params };
|
|
812
|
+
const validation = Joi.object({
|
|
813
|
+
site: Joi.string().hex().required(),
|
|
814
|
+
serviceType: Joi.string().valid(...Object.values(AppServiceType)).required(),
|
|
815
|
+
page: Joi.number().min(1).optional().allow("", null),
|
|
816
|
+
limit: Joi.number().min(1).optional().allow("", null)
|
|
817
|
+
});
|
|
818
|
+
const { error } = validation.validate(query);
|
|
819
|
+
if (error) {
|
|
820
|
+
logger2.log({ level: "error", message: error.message });
|
|
821
|
+
next(new BadRequestError2(error.message));
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
const site = req.params.site;
|
|
825
|
+
const serviceType = req.params.serviceType;
|
|
826
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
827
|
+
const limit = parseInt(req.query.limit) ?? 10;
|
|
828
|
+
try {
|
|
829
|
+
const data = await _getRecentFeedbacks({
|
|
830
|
+
site,
|
|
831
|
+
serviceType,
|
|
832
|
+
page,
|
|
833
|
+
limit
|
|
530
834
|
});
|
|
531
835
|
res.json(data);
|
|
532
836
|
return;
|
|
@@ -537,7 +841,11 @@ function useHygieneDashboardController() {
|
|
|
537
841
|
}
|
|
538
842
|
}
|
|
539
843
|
return {
|
|
540
|
-
getHygieneDashboard
|
|
844
|
+
getHygieneDashboard,
|
|
845
|
+
getWeeklyActivity,
|
|
846
|
+
getTodayTaskSchedule,
|
|
847
|
+
getStaffAttendance,
|
|
848
|
+
getRecentFeedbacks
|
|
541
849
|
};
|
|
542
850
|
}
|
|
543
851
|
|
|
@@ -545,10 +853,10 @@ function useHygieneDashboardController() {
|
|
|
545
853
|
import Joi2 from "joi";
|
|
546
854
|
import { ObjectId as ObjectId2 } from "mongodb";
|
|
547
855
|
import { BadRequestError as BadRequestError3, logger as logger3 } from "@7365admin1/node-server-utils";
|
|
548
|
-
import { AppServiceType } from "@7365admin1/core";
|
|
856
|
+
import { AppServiceType as AppServiceType2 } from "@7365admin1/core";
|
|
549
857
|
var areaSchema = Joi2.object({
|
|
550
858
|
site: Joi2.string().hex().required(),
|
|
551
|
-
serviceType: Joi2.string().valid(...Object.values(
|
|
859
|
+
serviceType: Joi2.string().valid(...Object.values(AppServiceType2)).required(),
|
|
552
860
|
name: Joi2.string().required(),
|
|
553
861
|
type: Joi2.string().valid(...allowedTypes).required(),
|
|
554
862
|
set: Joi2.number().min(0).optional(),
|
|
@@ -605,7 +913,7 @@ import { ObjectId as ObjectId3 } from "mongodb";
|
|
|
605
913
|
import {
|
|
606
914
|
useAtlas as useAtlas2,
|
|
607
915
|
InternalServerError as InternalServerError2,
|
|
608
|
-
paginate,
|
|
916
|
+
paginate as paginate2,
|
|
609
917
|
BadRequestError as BadRequestError4,
|
|
610
918
|
useCache as useCache2,
|
|
611
919
|
logger as logger4,
|
|
@@ -740,7 +1048,7 @@ function useAreaRepo() {
|
|
|
740
1048
|
{ $limit: limit }
|
|
741
1049
|
]).toArray();
|
|
742
1050
|
const length = await collection.countDocuments(query);
|
|
743
|
-
const data =
|
|
1051
|
+
const data = paginate2(items, page, limit, length);
|
|
744
1052
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
745
1053
|
logger4.info(`Cache set for key: ${cacheKey}`);
|
|
746
1054
|
}).catch((err) => {
|
|
@@ -1062,7 +1370,7 @@ import { ObjectId as ObjectId5 } from "mongodb";
|
|
|
1062
1370
|
import {
|
|
1063
1371
|
useAtlas as useAtlas3,
|
|
1064
1372
|
InternalServerError as InternalServerError3,
|
|
1065
|
-
paginate as
|
|
1373
|
+
paginate as paginate3,
|
|
1066
1374
|
BadRequestError as BadRequestError6,
|
|
1067
1375
|
useCache as useCache3,
|
|
1068
1376
|
logger as logger7,
|
|
@@ -1073,10 +1381,10 @@ import {
|
|
|
1073
1381
|
import Joi3 from "joi";
|
|
1074
1382
|
import { ObjectId as ObjectId4 } from "mongodb";
|
|
1075
1383
|
import { BadRequestError as BadRequestError5, logger as logger6 } from "@7365admin1/node-server-utils";
|
|
1076
|
-
import { AppServiceType as
|
|
1384
|
+
import { AppServiceType as AppServiceType3 } from "@7365admin1/core";
|
|
1077
1385
|
var unitSchema = Joi3.object({
|
|
1078
1386
|
site: Joi3.string().hex().required(),
|
|
1079
|
-
serviceType: Joi3.string().valid(...Object.values(
|
|
1387
|
+
serviceType: Joi3.string().valid(...Object.values(AppServiceType3)).required(),
|
|
1080
1388
|
name: Joi3.string().required()
|
|
1081
1389
|
});
|
|
1082
1390
|
function MUnit(value) {
|
|
@@ -1208,7 +1516,7 @@ function useUnitRepository() {
|
|
|
1208
1516
|
{ $limit: limit }
|
|
1209
1517
|
]).toArray();
|
|
1210
1518
|
const length = await collection.countDocuments(query);
|
|
1211
|
-
const data =
|
|
1519
|
+
const data = paginate3(items, page, limit, length);
|
|
1212
1520
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
1213
1521
|
logger7.info(`Cache set for key: ${cacheKey}`);
|
|
1214
1522
|
}).catch((err) => {
|
|
@@ -1497,7 +1805,7 @@ function useAreaService() {
|
|
|
1497
1805
|
// src/controllers/hygiene-area.controller.ts
|
|
1498
1806
|
import Joi4 from "joi";
|
|
1499
1807
|
import { BadRequestError as BadRequestError8, logger as logger9 } from "@7365admin1/node-server-utils";
|
|
1500
|
-
import { AppServiceType as
|
|
1808
|
+
import { AppServiceType as AppServiceType4 } from "@7365admin1/core";
|
|
1501
1809
|
|
|
1502
1810
|
// src/utils/convert-excel.util.ts
|
|
1503
1811
|
import { Readable } from "stream";
|
|
@@ -1562,7 +1870,7 @@ function useAreaController() {
|
|
|
1562
1870
|
search: Joi4.string().optional().allow("", null),
|
|
1563
1871
|
type: Joi4.string().valid("all", ...allowedTypes).optional().allow("", null),
|
|
1564
1872
|
site: Joi4.string().hex().required(),
|
|
1565
|
-
serviceType: Joi4.string().valid(...Object.values(
|
|
1873
|
+
serviceType: Joi4.string().valid(...Object.values(AppServiceType4)).required()
|
|
1566
1874
|
});
|
|
1567
1875
|
const { error } = validation.validate(query);
|
|
1568
1876
|
if (error) {
|
|
@@ -1671,7 +1979,7 @@ function useAreaController() {
|
|
|
1671
1979
|
const query = { ...req.query, ...req.params };
|
|
1672
1980
|
const validation = Joi4.object({
|
|
1673
1981
|
site: Joi4.string().hex().required(),
|
|
1674
|
-
serviceType: Joi4.string().valid(...Object.values(
|
|
1982
|
+
serviceType: Joi4.string().valid(...Object.values(AppServiceType4)).required()
|
|
1675
1983
|
});
|
|
1676
1984
|
const { error, value } = validation.validate(query);
|
|
1677
1985
|
if (error) {
|
|
@@ -1694,7 +2002,7 @@ function useAreaController() {
|
|
|
1694
2002
|
const query = { ...req.query, ...req.params };
|
|
1695
2003
|
const validation = Joi4.object({
|
|
1696
2004
|
site: Joi4.string().hex().required(),
|
|
1697
|
-
serviceType: Joi4.string().valid(...Object.values(
|
|
2005
|
+
serviceType: Joi4.string().valid(...Object.values(AppServiceType4)).required()
|
|
1698
2006
|
});
|
|
1699
2007
|
const { error, value } = validation.validate(query);
|
|
1700
2008
|
if (error) {
|
|
@@ -1977,7 +2285,7 @@ function useUnitService() {
|
|
|
1977
2285
|
// src/controllers/hygiene-unit.controller.ts
|
|
1978
2286
|
import Joi5 from "joi";
|
|
1979
2287
|
import { BadRequestError as BadRequestError10, logger as logger12 } from "@7365admin1/node-server-utils";
|
|
1980
|
-
import { AppServiceType as
|
|
2288
|
+
import { AppServiceType as AppServiceType5 } from "@7365admin1/core";
|
|
1981
2289
|
function useUnitController() {
|
|
1982
2290
|
const { createUnit: _createUnit, getUnits: _getUnits } = useUnitRepository();
|
|
1983
2291
|
const {
|
|
@@ -2011,7 +2319,7 @@ function useUnitController() {
|
|
|
2011
2319
|
limit: Joi5.number().min(1).optional().allow("", null),
|
|
2012
2320
|
search: Joi5.string().optional().allow("", null),
|
|
2013
2321
|
site: Joi5.string().hex().required(),
|
|
2014
|
-
serviceType: Joi5.string().valid(...Object.values(
|
|
2322
|
+
serviceType: Joi5.string().valid(...Object.values(AppServiceType5)).required()
|
|
2015
2323
|
});
|
|
2016
2324
|
const { error } = validation.validate(query);
|
|
2017
2325
|
if (error) {
|
|
@@ -2092,7 +2400,7 @@ function useUnitController() {
|
|
|
2092
2400
|
const query = { ...req.query, ...req.params };
|
|
2093
2401
|
const validation = Joi5.object({
|
|
2094
2402
|
site: Joi5.string().hex().required(),
|
|
2095
|
-
serviceType: Joi5.string().valid(...Object.values(
|
|
2403
|
+
serviceType: Joi5.string().valid(...Object.values(AppServiceType5)).required()
|
|
2096
2404
|
});
|
|
2097
2405
|
const { error, value } = validation.validate(query);
|
|
2098
2406
|
if (error) {
|
|
@@ -2115,7 +2423,7 @@ function useUnitController() {
|
|
|
2115
2423
|
const query = { ...req.query, ...req.params };
|
|
2116
2424
|
const validation = Joi5.object({
|
|
2117
2425
|
site: Joi5.string().hex().required(),
|
|
2118
|
-
serviceType: Joi5.string().valid(...Object.values(
|
|
2426
|
+
serviceType: Joi5.string().valid(...Object.values(AppServiceType5)).required()
|
|
2119
2427
|
});
|
|
2120
2428
|
const { error, value } = validation.validate(query);
|
|
2121
2429
|
if (error) {
|
|
@@ -2161,11 +2469,11 @@ function useUnitController() {
|
|
|
2161
2469
|
import Joi6 from "joi";
|
|
2162
2470
|
import { ObjectId as ObjectId6 } from "mongodb";
|
|
2163
2471
|
import { BadRequestError as BadRequestError11, logger as logger13 } from "@7365admin1/node-server-utils";
|
|
2164
|
-
import { AppServiceType as
|
|
2472
|
+
import { AppServiceType as AppServiceType6 } from "@7365admin1/core";
|
|
2165
2473
|
var parentChecklistSchema = Joi6.object({
|
|
2166
2474
|
createdAt: Joi6.alternatives().try(Joi6.date(), Joi6.string()).optional().allow("", null),
|
|
2167
2475
|
site: Joi6.string().hex().required(),
|
|
2168
|
-
serviceType: Joi6.string().valid(...Object.values(
|
|
2476
|
+
serviceType: Joi6.string().valid(...Object.values(AppServiceType6)).required()
|
|
2169
2477
|
});
|
|
2170
2478
|
function MParentChecklist(value) {
|
|
2171
2479
|
const { error } = parentChecklistSchema.validate(value);
|
|
@@ -2194,13 +2502,13 @@ import { ObjectId as ObjectId7 } from "mongodb";
|
|
|
2194
2502
|
import {
|
|
2195
2503
|
useAtlas as useAtlas5,
|
|
2196
2504
|
InternalServerError as InternalServerError4,
|
|
2197
|
-
paginate as
|
|
2505
|
+
paginate as paginate4,
|
|
2198
2506
|
useCache as useCache4,
|
|
2199
2507
|
logger as logger14,
|
|
2200
2508
|
makeCacheKey as makeCacheKey4,
|
|
2201
2509
|
BadRequestError as BadRequestError12
|
|
2202
2510
|
} from "@7365admin1/node-server-utils";
|
|
2203
|
-
import { AppServiceType as
|
|
2511
|
+
import { AppServiceType as AppServiceType7 } from "@7365admin1/core";
|
|
2204
2512
|
function useParentChecklistRepo() {
|
|
2205
2513
|
const db = useAtlas5.getDb();
|
|
2206
2514
|
if (!db) {
|
|
@@ -2232,7 +2540,7 @@ function useParentChecklistRepo() {
|
|
|
2232
2540
|
startOfDay.setUTCHours(0, 0, 0, 0);
|
|
2233
2541
|
const endOfDay = new Date(currentDate);
|
|
2234
2542
|
endOfDay.setUTCHours(23, 59, 59, 999);
|
|
2235
|
-
const allServiceTypes = Object.values(
|
|
2543
|
+
const allServiceTypes = Object.values(AppServiceType7);
|
|
2236
2544
|
const dateStr = currentDate.toISOString().split("T")[0];
|
|
2237
2545
|
if (value.site) {
|
|
2238
2546
|
let siteObjectId;
|
|
@@ -2456,7 +2764,7 @@ function useParentChecklistRepo() {
|
|
|
2456
2764
|
);
|
|
2457
2765
|
const items = await collection.aggregate(pipeline).toArray();
|
|
2458
2766
|
const length = await collection.countDocuments(query);
|
|
2459
|
-
const data =
|
|
2767
|
+
const data = paginate4(items, page, limit, length);
|
|
2460
2768
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
2461
2769
|
logger14.info(`Cache set for key: ${cacheKey}`);
|
|
2462
2770
|
}).catch((err) => {
|
|
@@ -2637,7 +2945,7 @@ function useParentChecklistRepo() {
|
|
|
2637
2945
|
// src/controllers/hygiene-parent-checklist.controller.ts
|
|
2638
2946
|
import Joi7 from "joi";
|
|
2639
2947
|
import { BadRequestError as BadRequestError13, logger as logger15 } from "@7365admin1/node-server-utils";
|
|
2640
|
-
import { AppServiceType as
|
|
2948
|
+
import { AppServiceType as AppServiceType8 } from "@7365admin1/core";
|
|
2641
2949
|
function useParentChecklistController() {
|
|
2642
2950
|
const {
|
|
2643
2951
|
createParentChecklist: _createParentChecklist,
|
|
@@ -2648,7 +2956,7 @@ function useParentChecklistController() {
|
|
|
2648
2956
|
const validation = Joi7.object({
|
|
2649
2957
|
createdAt: Joi7.alternatives().try(Joi7.date(), Joi7.string()).optional().allow("", null),
|
|
2650
2958
|
site: Joi7.string().hex().required(),
|
|
2651
|
-
serviceType: Joi7.string().valid(...Object.values(
|
|
2959
|
+
serviceType: Joi7.string().valid(...Object.values(AppServiceType8)).optional().allow("", null)
|
|
2652
2960
|
});
|
|
2653
2961
|
const { error } = validation.validate(payload);
|
|
2654
2962
|
if (error) {
|
|
@@ -2673,7 +2981,7 @@ function useParentChecklistController() {
|
|
|
2673
2981
|
limit: Joi7.number().min(1).optional().allow("", null),
|
|
2674
2982
|
search: Joi7.string().optional().allow("", null),
|
|
2675
2983
|
site: Joi7.string().hex().required(),
|
|
2676
|
-
serviceType: Joi7.string().valid(...Object.values(
|
|
2984
|
+
serviceType: Joi7.string().valid(...Object.values(AppServiceType8)).required(),
|
|
2677
2985
|
startDate: Joi7.alternatives().try(Joi7.date(), Joi7.string()).optional().allow("", null),
|
|
2678
2986
|
endDate: Joi7.alternatives().try(Joi7.date(), Joi7.string()).optional().allow("", null),
|
|
2679
2987
|
status: Joi7.string().valid(...allowedStatus, "all").optional().allow("", null)
|
|
@@ -2721,11 +3029,11 @@ function useParentChecklistController() {
|
|
|
2721
3029
|
import Joi8 from "joi";
|
|
2722
3030
|
import { ObjectId as ObjectId8 } from "mongodb";
|
|
2723
3031
|
import { BadRequestError as BadRequestError14, logger as logger16 } from "@7365admin1/node-server-utils";
|
|
2724
|
-
import { AppServiceType as
|
|
3032
|
+
import { AppServiceType as AppServiceType9 } from "@7365admin1/core";
|
|
2725
3033
|
var allowedChecklistStatus = ["open", "completed", "closed"];
|
|
2726
3034
|
var areaChecklistSchema = Joi8.object({
|
|
2727
3035
|
schedule: Joi8.string().hex().required(),
|
|
2728
|
-
serviceType: Joi8.string().valid(...Object.values(
|
|
3036
|
+
serviceType: Joi8.string().valid(...Object.values(AppServiceType9)).required(),
|
|
2729
3037
|
area: Joi8.string().hex().required(),
|
|
2730
3038
|
name: Joi8.string().required(),
|
|
2731
3039
|
type: Joi8.string().valid(...allowedTypes).required(),
|
|
@@ -2812,7 +3120,7 @@ import {
|
|
|
2812
3120
|
InternalServerError as InternalServerError5,
|
|
2813
3121
|
logger as logger17,
|
|
2814
3122
|
makeCacheKey as makeCacheKey5,
|
|
2815
|
-
paginate as
|
|
3123
|
+
paginate as paginate5,
|
|
2816
3124
|
useAtlas as useAtlas6,
|
|
2817
3125
|
useCache as useCache5
|
|
2818
3126
|
} from "@7365admin1/node-server-utils";
|
|
@@ -3003,7 +3311,7 @@ function useAreaChecklistRepo() {
|
|
|
3003
3311
|
];
|
|
3004
3312
|
const items = await collection.aggregate(pipeline, { session }).toArray();
|
|
3005
3313
|
const length = await collection.countDocuments(query, { session });
|
|
3006
|
-
const data =
|
|
3314
|
+
const data = paginate5(items, page, limit, length);
|
|
3007
3315
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
3008
3316
|
logger17.info(`Cache set for key: ${cacheKey}`);
|
|
3009
3317
|
}).catch((err) => {
|
|
@@ -3111,7 +3419,7 @@ function useAreaChecklistRepo() {
|
|
|
3111
3419
|
];
|
|
3112
3420
|
const items = await collection.aggregate(pipeline).toArray();
|
|
3113
3421
|
const length = await collection.countDocuments(query);
|
|
3114
|
-
const data =
|
|
3422
|
+
const data = paginate5(items, page, limit, length);
|
|
3115
3423
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
3116
3424
|
logger17.info(`Cache set for key: ${cacheKey}`);
|
|
3117
3425
|
}).catch((err) => {
|
|
@@ -3498,7 +3806,7 @@ function useAreaChecklistRepo() {
|
|
|
3498
3806
|
collection.aggregate(countPipeline, { session }).toArray()
|
|
3499
3807
|
]);
|
|
3500
3808
|
const length = countResult.length > 0 ? countResult[0].total : 0;
|
|
3501
|
-
const data =
|
|
3809
|
+
const data = paginate5(items, page, limit, length);
|
|
3502
3810
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
3503
3811
|
logger17.info(`Cache set for key: ${cacheKey}`);
|
|
3504
3812
|
}).catch((err) => {
|
|
@@ -4177,7 +4485,7 @@ import {
|
|
|
4177
4485
|
InternalServerError as InternalServerError7,
|
|
4178
4486
|
logger as logger20
|
|
4179
4487
|
} from "@7365admin1/node-server-utils";
|
|
4180
|
-
import { AppServiceType as
|
|
4488
|
+
import { AppServiceType as AppServiceType10 } from "@7365admin1/core";
|
|
4181
4489
|
|
|
4182
4490
|
// src/services/hygiene-checklist-pdf.service.ts
|
|
4183
4491
|
import { launch } from "puppeteer";
|
|
@@ -4444,7 +4752,7 @@ function useAreaChecklistController() {
|
|
|
4444
4752
|
type: Joi9.string().valid(...allowedTypes, "all").optional().allow("", null),
|
|
4445
4753
|
status: Joi9.string().valid(...allowedStatus, "all").optional().allow("", null),
|
|
4446
4754
|
schedule: Joi9.string().hex().required(),
|
|
4447
|
-
serviceType: Joi9.string().valid(...Object.values(
|
|
4755
|
+
serviceType: Joi9.string().valid(...Object.values(AppServiceType10)).required()
|
|
4448
4756
|
});
|
|
4449
4757
|
const { error } = validation.validate(query);
|
|
4450
4758
|
if (error) {
|
|
@@ -4544,7 +4852,7 @@ function useAreaChecklistController() {
|
|
|
4544
4852
|
page: Joi9.number().min(1).optional().allow("", null),
|
|
4545
4853
|
limit: Joi9.number().min(1).optional().allow("", null),
|
|
4546
4854
|
search: Joi9.string().optional().allow("", null),
|
|
4547
|
-
serviceType: Joi9.string().valid(...Object.values(
|
|
4855
|
+
serviceType: Joi9.string().valid(...Object.values(AppServiceType10)).required(),
|
|
4548
4856
|
id: Joi9.string().hex().required()
|
|
4549
4857
|
});
|
|
4550
4858
|
const { error } = validation.validate(query);
|
|
@@ -4673,10 +4981,10 @@ function useAreaChecklistController() {
|
|
|
4673
4981
|
import Joi10 from "joi";
|
|
4674
4982
|
import { ObjectId as ObjectId12 } from "mongodb";
|
|
4675
4983
|
import { BadRequestError as BadRequestError17, logger as logger21 } from "@7365admin1/node-server-utils";
|
|
4676
|
-
import { AppServiceType as
|
|
4984
|
+
import { AppServiceType as AppServiceType11 } from "@7365admin1/core";
|
|
4677
4985
|
var supplySchema = Joi10.object({
|
|
4678
4986
|
site: Joi10.string().hex().required(),
|
|
4679
|
-
serviceType: Joi10.string().valid(...Object.values(
|
|
4987
|
+
serviceType: Joi10.string().valid(...Object.values(AppServiceType11)).required(),
|
|
4680
4988
|
name: Joi10.string().required(),
|
|
4681
4989
|
unitOfMeasurement: Joi10.string().required()
|
|
4682
4990
|
});
|
|
@@ -4711,7 +5019,7 @@ import { ObjectId as ObjectId13 } from "mongodb";
|
|
|
4711
5019
|
import {
|
|
4712
5020
|
useAtlas as useAtlas9,
|
|
4713
5021
|
InternalServerError as InternalServerError8,
|
|
4714
|
-
paginate as
|
|
5022
|
+
paginate as paginate6,
|
|
4715
5023
|
BadRequestError as BadRequestError18,
|
|
4716
5024
|
useCache as useCache6,
|
|
4717
5025
|
logger as logger22,
|
|
@@ -4829,7 +5137,7 @@ function useSupplyRepository() {
|
|
|
4829
5137
|
{ $limit: limit }
|
|
4830
5138
|
]).toArray();
|
|
4831
5139
|
const length = await collection.countDocuments(query);
|
|
4832
|
-
const data =
|
|
5140
|
+
const data = paginate6(items, page, limit, length);
|
|
4833
5141
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
4834
5142
|
logger22.info(`Cache set for key: ${cacheKey}`);
|
|
4835
5143
|
}).catch((err) => {
|
|
@@ -4967,7 +5275,7 @@ function useSupplyRepository() {
|
|
|
4967
5275
|
// src/controllers/hygiene-supply.controller.ts
|
|
4968
5276
|
import Joi11 from "joi";
|
|
4969
5277
|
import { BadRequestError as BadRequestError19, logger as logger23 } from "@7365admin1/node-server-utils";
|
|
4970
|
-
import { AppServiceType as
|
|
5278
|
+
import { AppServiceType as AppServiceType12 } from "@7365admin1/core";
|
|
4971
5279
|
function useSupplyController() {
|
|
4972
5280
|
const {
|
|
4973
5281
|
createSupply: _createSupply,
|
|
@@ -5001,7 +5309,7 @@ function useSupplyController() {
|
|
|
5001
5309
|
limit: Joi11.number().min(1).optional().allow("", null),
|
|
5002
5310
|
search: Joi11.string().optional().allow("", null),
|
|
5003
5311
|
site: Joi11.string().hex().required(),
|
|
5004
|
-
serviceType: Joi11.string().valid(...Object.values(
|
|
5312
|
+
serviceType: Joi11.string().valid(...Object.values(AppServiceType12)).required()
|
|
5005
5313
|
});
|
|
5006
5314
|
const { error } = validation.validate(query);
|
|
5007
5315
|
if (error) {
|
|
@@ -5106,10 +5414,10 @@ function useSupplyController() {
|
|
|
5106
5414
|
import Joi12 from "joi";
|
|
5107
5415
|
import { ObjectId as ObjectId14 } from "mongodb";
|
|
5108
5416
|
import { BadRequestError as BadRequestError20, logger as logger24 } from "@7365admin1/node-server-utils";
|
|
5109
|
-
import { AppServiceType as
|
|
5417
|
+
import { AppServiceType as AppServiceType13 } from "@7365admin1/core";
|
|
5110
5418
|
var stockSchema = Joi12.object({
|
|
5111
5419
|
site: Joi12.string().hex().required(),
|
|
5112
|
-
serviceType: Joi12.string().valid(...Object.values(
|
|
5420
|
+
serviceType: Joi12.string().valid(...Object.values(AppServiceType13)).required(),
|
|
5113
5421
|
supply: Joi12.string().hex().required(),
|
|
5114
5422
|
in: Joi12.number().min(0).optional(),
|
|
5115
5423
|
out: Joi12.number().min(0).optional(),
|
|
@@ -5160,7 +5468,7 @@ import {
|
|
|
5160
5468
|
useCache as useCache7,
|
|
5161
5469
|
logger as logger25,
|
|
5162
5470
|
makeCacheKey as makeCacheKey7,
|
|
5163
|
-
paginate as
|
|
5471
|
+
paginate as paginate7
|
|
5164
5472
|
} from "@7365admin1/node-server-utils";
|
|
5165
5473
|
function useStockRepository() {
|
|
5166
5474
|
const db = useAtlas10.getDb();
|
|
@@ -5268,7 +5576,7 @@ function useStockRepository() {
|
|
|
5268
5576
|
{ $limit: limit }
|
|
5269
5577
|
]).toArray();
|
|
5270
5578
|
const length = await collection.countDocuments(query);
|
|
5271
|
-
const data =
|
|
5579
|
+
const data = paginate7(items, page, limit, length);
|
|
5272
5580
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
5273
5581
|
logger25.info(`Cache set for key: ${cacheKey}`);
|
|
5274
5582
|
}).catch((err) => {
|
|
@@ -5343,7 +5651,7 @@ function useStockService() {
|
|
|
5343
5651
|
// src/controllers/hygiene-stock.controller.ts
|
|
5344
5652
|
import Joi13 from "joi";
|
|
5345
5653
|
import { BadRequestError as BadRequestError23, logger as logger26 } from "@7365admin1/node-server-utils";
|
|
5346
|
-
import { AppServiceType as
|
|
5654
|
+
import { AppServiceType as AppServiceType14 } from "@7365admin1/core";
|
|
5347
5655
|
function useStockController() {
|
|
5348
5656
|
const { getStocksBySupplyId: _getStocksBySupplyId } = useStockRepository();
|
|
5349
5657
|
const { createStock: _createStock } = useStockService();
|
|
@@ -5351,7 +5659,7 @@ function useStockController() {
|
|
|
5351
5659
|
const payload = { ...req.body, ...req.params };
|
|
5352
5660
|
const validation = Joi13.object({
|
|
5353
5661
|
site: Joi13.string().hex().required(),
|
|
5354
|
-
serviceType: Joi13.string().valid(...Object.values(
|
|
5662
|
+
serviceType: Joi13.string().valid(...Object.values(AppServiceType14)).required(),
|
|
5355
5663
|
supply: Joi13.string().hex().required(),
|
|
5356
5664
|
qty: Joi13.number().min(0).required(),
|
|
5357
5665
|
remarks: Joi13.string().optional().allow("", null)
|
|
@@ -5379,7 +5687,7 @@ function useStockController() {
|
|
|
5379
5687
|
limit: Joi13.number().min(1).optional().allow("", null),
|
|
5380
5688
|
search: Joi13.string().optional().allow("", null),
|
|
5381
5689
|
site: Joi13.string().hex().required(),
|
|
5382
|
-
serviceType: Joi13.string().valid(...Object.values(
|
|
5690
|
+
serviceType: Joi13.string().valid(...Object.values(AppServiceType14)).required(),
|
|
5383
5691
|
supply: Joi13.string().hex().required()
|
|
5384
5692
|
});
|
|
5385
5693
|
const { error } = validation.validate(query);
|
|
@@ -5421,11 +5729,11 @@ function useStockController() {
|
|
|
5421
5729
|
import Joi14 from "joi";
|
|
5422
5730
|
import { ObjectId as ObjectId16 } from "mongodb";
|
|
5423
5731
|
import { BadRequestError as BadRequestError24, logger as logger27 } from "@7365admin1/node-server-utils";
|
|
5424
|
-
import { AppServiceType as
|
|
5732
|
+
import { AppServiceType as AppServiceType15 } from "@7365admin1/core";
|
|
5425
5733
|
var allowedCheckOutItemStatus = ["pending", "completed"];
|
|
5426
5734
|
var checkOutItemSchema = Joi14.object({
|
|
5427
5735
|
site: Joi14.string().hex().required(),
|
|
5428
|
-
serviceType: Joi14.string().valid(...Object.values(
|
|
5736
|
+
serviceType: Joi14.string().valid(...Object.values(AppServiceType15)).required(),
|
|
5429
5737
|
supply: Joi14.string().hex().required(),
|
|
5430
5738
|
supplyName: Joi14.string().required(),
|
|
5431
5739
|
qty: Joi14.number().min(0).required(),
|
|
@@ -5477,7 +5785,7 @@ import {
|
|
|
5477
5785
|
useCache as useCache8,
|
|
5478
5786
|
logger as logger28,
|
|
5479
5787
|
makeCacheKey as makeCacheKey8,
|
|
5480
|
-
paginate as
|
|
5788
|
+
paginate as paginate8,
|
|
5481
5789
|
BadRequestError as BadRequestError25,
|
|
5482
5790
|
NotFoundError as NotFoundError6
|
|
5483
5791
|
} from "@7365admin1/node-server-utils";
|
|
@@ -5636,7 +5944,7 @@ function useCheckOutItemRepository() {
|
|
|
5636
5944
|
{ $limit: limit }
|
|
5637
5945
|
]).toArray();
|
|
5638
5946
|
const length = await collection.countDocuments(query);
|
|
5639
|
-
const data =
|
|
5947
|
+
const data = paginate8(items, page, limit, length);
|
|
5640
5948
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
5641
5949
|
logger28.info(`Cache set for key: ${cacheKey}`);
|
|
5642
5950
|
}).catch((err) => {
|
|
@@ -5859,7 +6167,7 @@ function useCheckOutItemService() {
|
|
|
5859
6167
|
// src/controllers/hygiene-checkout-item.controller.ts
|
|
5860
6168
|
import Joi15 from "joi";
|
|
5861
6169
|
import { BadRequestError as BadRequestError27, logger as logger29 } from "@7365admin1/node-server-utils";
|
|
5862
|
-
import { AppServiceType as
|
|
6170
|
+
import { AppServiceType as AppServiceType16 } from "@7365admin1/core";
|
|
5863
6171
|
function useCheckOutItemController() {
|
|
5864
6172
|
const {
|
|
5865
6173
|
getCheckOutItems: _getCheckOutItems,
|
|
@@ -5882,7 +6190,7 @@ function useCheckOutItemController() {
|
|
|
5882
6190
|
};
|
|
5883
6191
|
const validation = Joi15.object({
|
|
5884
6192
|
site: Joi15.string().hex().required(),
|
|
5885
|
-
serviceType: Joi15.string().valid(...Object.values(
|
|
6193
|
+
serviceType: Joi15.string().valid(...Object.values(AppServiceType16)).required(),
|
|
5886
6194
|
supply: Joi15.string().hex().required(),
|
|
5887
6195
|
qty: Joi15.number().min(0).required(),
|
|
5888
6196
|
attachment: Joi15.array().items(Joi15.string()).optional().allow(null),
|
|
@@ -5917,7 +6225,7 @@ function useCheckOutItemController() {
|
|
|
5917
6225
|
};
|
|
5918
6226
|
const validation = Joi15.object({
|
|
5919
6227
|
site: Joi15.string().hex().required(),
|
|
5920
|
-
serviceType: Joi15.string().valid(...Object.values(
|
|
6228
|
+
serviceType: Joi15.string().valid(...Object.values(AppServiceType16)).required(),
|
|
5921
6229
|
createdBy: Joi15.string().hex().required(),
|
|
5922
6230
|
items: Joi15.array().items(
|
|
5923
6231
|
Joi15.object({
|
|
@@ -5950,7 +6258,7 @@ function useCheckOutItemController() {
|
|
|
5950
6258
|
limit: Joi15.number().min(1).optional().allow("", null),
|
|
5951
6259
|
search: Joi15.string().optional().allow("", null),
|
|
5952
6260
|
site: Joi15.string().hex().required(),
|
|
5953
|
-
serviceType: Joi15.string().valid(...Object.values(
|
|
6261
|
+
serviceType: Joi15.string().valid(...Object.values(AppServiceType16)).required()
|
|
5954
6262
|
});
|
|
5955
6263
|
const { error } = validation.validate(query);
|
|
5956
6264
|
if (error) {
|
|
@@ -6008,12 +6316,12 @@ function useCheckOutItemController() {
|
|
|
6008
6316
|
|
|
6009
6317
|
// src/models/hygiene-schedule-task.model.ts
|
|
6010
6318
|
import { BadRequestError as BadRequestError28, logger as logger30 } from "@7365admin1/node-server-utils";
|
|
6011
|
-
import { AppServiceType as
|
|
6319
|
+
import { AppServiceType as AppServiceType17 } from "@7365admin1/core";
|
|
6012
6320
|
import Joi16 from "joi";
|
|
6013
6321
|
import { ObjectId as ObjectId18 } from "mongodb";
|
|
6014
6322
|
var scheduleTaskSchema = Joi16.object({
|
|
6015
6323
|
site: Joi16.string().hex().required(),
|
|
6016
|
-
serviceType: Joi16.string().valid(...Object.values(
|
|
6324
|
+
serviceType: Joi16.string().valid(...Object.values(AppServiceType17)).required(),
|
|
6017
6325
|
title: Joi16.string().required(),
|
|
6018
6326
|
time: Joi16.string().pattern(/^([0-1]\d|2[0-3]):([0-5]\d)$/).required(),
|
|
6019
6327
|
dates: Joi16.array().min(1).items(
|
|
@@ -6072,7 +6380,7 @@ import { ObjectId as ObjectId19 } from "mongodb";
|
|
|
6072
6380
|
import {
|
|
6073
6381
|
useAtlas as useAtlas14,
|
|
6074
6382
|
InternalServerError as InternalServerError11,
|
|
6075
|
-
paginate as
|
|
6383
|
+
paginate as paginate9,
|
|
6076
6384
|
BadRequestError as BadRequestError29,
|
|
6077
6385
|
useCache as useCache9,
|
|
6078
6386
|
logger as logger31,
|
|
@@ -6175,7 +6483,7 @@ function useScheduleTaskRepository() {
|
|
|
6175
6483
|
{ $limit: limit }
|
|
6176
6484
|
]).toArray();
|
|
6177
6485
|
const length = await collection.countDocuments(query);
|
|
6178
|
-
const data =
|
|
6486
|
+
const data = paginate9(items, page, limit, length);
|
|
6179
6487
|
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
6180
6488
|
logger31.info(`Cache set for key: ${cacheKey}`);
|
|
6181
6489
|
}).catch((err) => {
|
|
@@ -6628,7 +6936,7 @@ function useScheduleTaskService() {
|
|
|
6628
6936
|
// src/controllers/hygiene-schedule-task.controller.ts
|
|
6629
6937
|
import Joi17 from "joi";
|
|
6630
6938
|
import { BadRequestError as BadRequestError30, logger as logger33 } from "@7365admin1/node-server-utils";
|
|
6631
|
-
import { AppServiceType as
|
|
6939
|
+
import { AppServiceType as AppServiceType18 } from "@7365admin1/core";
|
|
6632
6940
|
function useScheduleTaskController() {
|
|
6633
6941
|
const {
|
|
6634
6942
|
createScheduleTask: _createScheduleTask,
|
|
@@ -6662,7 +6970,7 @@ function useScheduleTaskController() {
|
|
|
6662
6970
|
limit: Joi17.number().min(1).optional().allow("", null),
|
|
6663
6971
|
search: Joi17.string().optional().allow("", null),
|
|
6664
6972
|
site: Joi17.string().hex().required(),
|
|
6665
|
-
serviceType: Joi17.string().valid(...Object.values(
|
|
6973
|
+
serviceType: Joi17.string().valid(...Object.values(AppServiceType18)).required()
|
|
6666
6974
|
});
|
|
6667
6975
|
const { error } = validation.validate(query);
|
|
6668
6976
|
if (error) {
|