@eeplatform/basic-edu 1.5.2 → 1.6.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/dist/index.js CHANGED
@@ -1344,10 +1344,13 @@ var require_papaparse = __commonJS({
1344
1344
  var src_exports = {};
1345
1345
  __export(src_exports, {
1346
1346
  MAsset: () => MAsset,
1347
+ MBuilding: () => MBuilding,
1348
+ MBuildingUnit: () => MBuildingUnit,
1347
1349
  MCurriculum: () => MCurriculum,
1348
1350
  MCurriculumSubject: () => MCurriculumSubject,
1349
1351
  MGradeLevel: () => MGradeLevel,
1350
1352
  MLearner: () => MLearner,
1353
+ MPersonnel: () => MPersonnel,
1351
1354
  MPlantilla: () => MPlantilla,
1352
1355
  MStockCard: () => MStockCard,
1353
1356
  allowedSectionStudentStatuses: () => allowedSectionStudentStatuses,
@@ -1358,9 +1361,12 @@ __export(src_exports, {
1358
1361
  modelSection: () => modelSection,
1359
1362
  modelSectionPreset: () => modelSectionPreset,
1360
1363
  modelSectionStudent: () => modelSectionStudent,
1364
+ modelSectionSubject: () => modelSectionSubject,
1361
1365
  schemaAsset: () => schemaAsset,
1362
1366
  schemaAssetUpdateOption: () => schemaAssetUpdateOption,
1363
1367
  schemaBasicEduCount: () => schemaBasicEduCount,
1368
+ schemaBuilding: () => schemaBuilding,
1369
+ schemaBuildingUnit: () => schemaBuildingUnit,
1364
1370
  schemaCurriculum: () => schemaCurriculum,
1365
1371
  schemaCurriculumSubject: () => schemaCurriculumSubject,
1366
1372
  schemaCurriculumSubjectAdd: () => schemaCurriculumSubjectAdd,
@@ -1369,6 +1375,7 @@ __export(src_exports, {
1369
1375
  schemaEnrollment: () => schemaEnrollment,
1370
1376
  schemaGenerateSections: () => schemaGenerateSections,
1371
1377
  schemaGradeLevel: () => schemaGradeLevel,
1378
+ schemaPersonnel: () => schemaPersonnel,
1372
1379
  schemaPlantilla: () => schemaPlantilla,
1373
1380
  schemaRegion: () => schemaRegion,
1374
1381
  schemaSchool: () => schemaSchool,
@@ -1376,11 +1383,20 @@ __export(src_exports, {
1376
1383
  schemaSection: () => schemaSection,
1377
1384
  schemaSectionPreset: () => schemaSectionPreset,
1378
1385
  schemaSectionStudent: () => schemaSectionStudent,
1386
+ schemaSectionSubject: () => schemaSectionSubject,
1387
+ schemaSectionSubjectSetup: () => schemaSectionSubjectSetup,
1379
1388
  schemaStockCard: () => schemaStockCard,
1389
+ schemaUpdateOptions: () => schemaUpdateOptions,
1380
1390
  schemaUpdateStatus: () => schemaUpdateStatus,
1381
1391
  useAssetController: () => useAssetController,
1382
1392
  useAssetRepo: () => useAssetRepo,
1383
1393
  useBasicEduCountRepo: () => useBasicEduCountRepo,
1394
+ useBuildingController: () => useBuildingController,
1395
+ useBuildingRepo: () => useBuildingRepo,
1396
+ useBuildingService: () => useBuildingService,
1397
+ useBuildingUnitController: () => useBuildingUnitController,
1398
+ useBuildingUnitRepo: () => useBuildingUnitRepo,
1399
+ useBuildingUnitService: () => useBuildingUnitService,
1384
1400
  useCurriculumController: () => useCurriculumController,
1385
1401
  useCurriculumRepo: () => useCurriculumRepo,
1386
1402
  useCurriculumSubjectController: () => useCurriculumSubjectController,
@@ -1396,6 +1412,8 @@ __export(src_exports, {
1396
1412
  useGradeLevelRepo: () => useGradeLevelRepo,
1397
1413
  useLearnerController: () => useLearnerController,
1398
1414
  useLearnerRepo: () => useLearnerRepo,
1415
+ usePersonnelController: () => usePersonnelController,
1416
+ usePersonnelRepo: () => usePersonnelRepo,
1399
1417
  usePlantillaController: () => usePlantillaController,
1400
1418
  usePlantillaRepo: () => usePlantillaRepo,
1401
1419
  usePlantillaService: () => usePlantillaService,
@@ -1409,6 +1427,9 @@ __export(src_exports, {
1409
1427
  useSectionPresetRepo: () => useSectionPresetRepo,
1410
1428
  useSectionRepo: () => useSectionRepo,
1411
1429
  useSectionStudentRepo: () => useSectionStudentRepo,
1430
+ useSectionSubjectController: () => useSectionSubjectController,
1431
+ useSectionSubjectRepo: () => useSectionSubjectRepo,
1432
+ useSectionSubjectService: () => useSectionSubjectService,
1412
1433
  useStockCardController: () => useStockCardController,
1413
1434
  useStockCardRepository: () => useStockCardRepository,
1414
1435
  useStockCardService: () => useStockCardService
@@ -3587,8 +3608,11 @@ function useLearnerRepo() {
3587
3608
  }
3588
3609
  }
3589
3610
  async function getByGradeLevel(value, session) {
3611
+ value.limit = value.limit && value.limit > 0 ? value.limit : 50;
3612
+ value.skip = value.skip && value.skip > 0 ? value.skip - 1 : 0;
3590
3613
  const validation = import_joi7.default.object({
3591
3614
  school: import_joi7.default.string().hex().required(),
3615
+ schoolYear: import_joi7.default.string().optional(),
3592
3616
  gradeLevel: import_joi7.default.string().required(),
3593
3617
  status: import_joi7.default.string().optional().allow("", null),
3594
3618
  limit: import_joi7.default.number().integer().required(),
@@ -3605,8 +3629,14 @@ function useLearnerRepo() {
3605
3629
  };
3606
3630
  const cacheKeyOptions = {
3607
3631
  ...query,
3608
- tag: "byGradeLevel"
3632
+ tag: "byGradeLevel",
3633
+ limit: value.limit,
3634
+ skip: value.skip
3609
3635
  };
3636
+ if (value.schoolYear) {
3637
+ query.schoolYear = value.schoolYear;
3638
+ cacheKeyOptions.schoolYear = value.schoolYear;
3639
+ }
3610
3640
  if (value.school && typeof value.school === "string") {
3611
3641
  try {
3612
3642
  query.school = new import_mongodb7.ObjectId(value.school);
@@ -3626,11 +3656,7 @@ function useLearnerRepo() {
3626
3656
  }
3627
3657
  try {
3628
3658
  const data = await collection.aggregate(
3629
- [
3630
- { $match: query },
3631
- { $skip: value.skip ?? 0 },
3632
- { $limit: value.limit ?? 100 }
3633
- ],
3659
+ [{ $match: query }, { $skip: value.skip }, { $limit: value.limit }],
3634
3660
  { session }
3635
3661
  ).toArray();
3636
3662
  setCache(cacheKey, data, 600).then(() => {
@@ -37820,11 +37846,11 @@ function useSectionRepo() {
37820
37846
  }
37821
37847
 
37822
37848
  // src/resources/section/section.controller.ts
37823
- var import_nodejs_utils49 = require("@eeplatform/nodejs-utils");
37824
- var import_joi29 = __toESM(require("joi"));
37849
+ var import_nodejs_utils53 = require("@eeplatform/nodejs-utils");
37850
+ var import_joi31 = __toESM(require("joi"));
37825
37851
 
37826
37852
  // src/resources/section/section.service.ts
37827
- var import_nodejs_utils48 = require("@eeplatform/nodejs-utils");
37853
+ var import_nodejs_utils52 = require("@eeplatform/nodejs-utils");
37828
37854
 
37829
37855
  // src/resources/section-student/section.student.repository.ts
37830
37856
  var import_nodejs_utils47 = require("@eeplatform/nodejs-utils");
@@ -37949,196 +37975,614 @@ function useSectionStudentRepo() {
37949
37975
  };
37950
37976
  }
37951
37977
 
37952
- // src/resources/section/section.service.ts
37953
- function useSectionService() {
37954
- const { getCountByGradeLevel, getByGradeLevel: getLeanerByGradeLevel } = useLearnerRepo();
37955
- const { getByGradeLevel } = useGradeLevelRepo();
37956
- const { add: createSection } = useSectionRepo();
37957
- const { add: assignStudent } = useSectionStudentRepo();
37958
- function distributeStudents(total, minPer, maxPer) {
37959
- if (total <= 0)
37960
- return [];
37961
- if (minPer <= 0 || maxPer <= 0)
37962
- return [];
37963
- if (minPer > maxPer) {
37964
- throw new import_nodejs_utils48.BadRequestError(
37965
- "Minimum students per section cannot be greater than maximum."
37966
- );
37978
+ // src/resources/section-subject/section.subject.model.ts
37979
+ var import_nodejs_utils48 = require("@eeplatform/nodejs-utils");
37980
+ var import_joi29 = __toESM(require("joi"));
37981
+ var import_mongodb28 = require("mongodb");
37982
+ var schemaSectionSubject = import_joi29.default.object({
37983
+ _id: import_joi29.default.string().hex().optional().allow(null, ""),
37984
+ school: import_joi29.default.string().hex().required(),
37985
+ schoolName: import_joi29.default.string().optional().allow(null, ""),
37986
+ section: import_joi29.default.string().hex().required(),
37987
+ sectionName: import_joi29.default.string().required(),
37988
+ gradeLevel: import_joi29.default.string().required(),
37989
+ educationLevel: import_joi29.default.string().required(),
37990
+ schoolYear: import_joi29.default.string().required(),
37991
+ subjectCode: import_joi29.default.string().required(),
37992
+ subjectName: import_joi29.default.string().required(),
37993
+ teacher: import_joi29.default.string().hex().optional().allow(null, ""),
37994
+ teacherName: import_joi29.default.string().optional().allow(null, ""),
37995
+ classroom: import_joi29.default.string().optional().allow(null, ""),
37996
+ classroomName: import_joi29.default.string().optional().allow(null, ""),
37997
+ daysOfWeek: import_joi29.default.array().items(import_joi29.default.string()).optional().allow(null),
37998
+ schedule: import_joi29.default.string().optional().allow(null, ""),
37999
+ sessionDuration: import_joi29.default.number().optional().allow(null, 0),
38000
+ sessionFrequency: import_joi29.default.number().optional().allow(null, 0),
38001
+ status: import_joi29.default.string().valid("active", "draft").optional(),
38002
+ createdAt: import_joi29.default.string().isoDate().optional().allow(null, ""),
38003
+ updatedAt: import_joi29.default.string().isoDate().optional().allow(null, ""),
38004
+ deletedAt: import_joi29.default.string().isoDate().optional().allow(null, "")
38005
+ });
38006
+ var schemaSectionSubjectSetup = import_joi29.default.object({
38007
+ teacher: import_joi29.default.string().hex().optional().allow(null, ""),
38008
+ teacherName: import_joi29.default.string().optional().allow(null, ""),
38009
+ classroom: import_joi29.default.string().optional().allow(null, ""),
38010
+ classroomName: import_joi29.default.string().optional().allow(null, ""),
38011
+ daysOfWeek: import_joi29.default.array().items(import_joi29.default.string()).optional().allow(null),
38012
+ schedule: import_joi29.default.string().optional().allow(null, "")
38013
+ });
38014
+ function modelSectionSubject(value) {
38015
+ const { error } = schemaSectionSubject.validate(value);
38016
+ if (error) {
38017
+ throw new import_nodejs_utils48.BadRequestError(`Invalid section subject data: ${error.message}`);
38018
+ }
38019
+ if (value._id && typeof value._id === "string") {
38020
+ try {
38021
+ value._id = new import_mongodb28.ObjectId(value._id);
38022
+ } catch (error2) {
38023
+ throw new Error("Invalid _id.");
37967
38024
  }
37968
- const minSections = Math.ceil(total / maxPer);
37969
- const maxSections = Math.floor(total / minPer);
37970
- let sectionCount;
37971
- if (minSections <= maxSections) {
37972
- sectionCount = minSections;
37973
- } else {
37974
- sectionCount = minSections;
38025
+ }
38026
+ if (value.school && typeof value.school === "string") {
38027
+ try {
38028
+ value.school = new import_mongodb28.ObjectId(value.school);
38029
+ } catch (error2) {
38030
+ throw new Error("Invalid school ID.");
37975
38031
  }
37976
- const base = Math.floor(total / sectionCount);
37977
- const extra = total % sectionCount;
37978
- const sizes = new Array(sectionCount).fill(base);
37979
- for (let i = 0; i < extra; i++) {
37980
- sizes[i] += 1;
38032
+ }
38033
+ if (value.section && typeof value.section === "string") {
38034
+ try {
38035
+ value.section = new import_mongodb28.ObjectId(value.section);
38036
+ } catch (error2) {
38037
+ throw new Error("Invalid section ID.");
37981
38038
  }
37982
- for (const size of sizes) {
37983
- if (size > maxPer) {
37984
- throw new import_nodejs_utils48.BadRequestError(
37985
- `Generated section exceeds max limit of ${maxPer}.`
37986
- );
38039
+ }
38040
+ if (value.teacher && typeof value.teacher === "string") {
38041
+ try {
38042
+ value.teacher = new import_mongodb28.ObjectId(value.teacher);
38043
+ } catch (error2) {
38044
+ throw new Error("Invalid teacher ID.");
38045
+ }
38046
+ }
38047
+ return {
38048
+ _id: value._id,
38049
+ school: value.school,
38050
+ schoolName: value.schoolName,
38051
+ section: value.section,
38052
+ sectionName: value.sectionName,
38053
+ gradeLevel: value.gradeLevel,
38054
+ educationLevel: value.educationLevel,
38055
+ schoolYear: value.schoolYear,
38056
+ subjectCode: value.subjectCode,
38057
+ subjectName: value.subjectName,
38058
+ teacher: value.teacher,
38059
+ teacherName: value.teacherName,
38060
+ classroom: value.classroom ?? "",
38061
+ classroomName: value.classroomName ?? "",
38062
+ daysOfWeek: value.daysOfWeek ?? [],
38063
+ schedule: value.schedule ?? "",
38064
+ sessionDuration: value.sessionDuration ?? 0,
38065
+ sessionFrequency: value.sessionFrequency ?? 0,
38066
+ status: value.status ?? "draft",
38067
+ createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
38068
+ updatedAt: value.updatedAt ?? "",
38069
+ deletedAt: value.deletedAt ?? ""
38070
+ };
38071
+ }
38072
+
38073
+ // src/resources/section-subject/section.subject.repository.ts
38074
+ var import_nodejs_utils49 = require("@eeplatform/nodejs-utils");
38075
+ var import_mongodb29 = require("mongodb");
38076
+ function useSectionSubjectRepo() {
38077
+ const db = import_nodejs_utils49.useAtlas.getDb();
38078
+ if (!db) {
38079
+ throw new Error("Unable to connect to server.");
38080
+ }
38081
+ const namespace_collection = "deped.section.subjects";
38082
+ const collection = db.collection(namespace_collection);
38083
+ const { getCache, setCache, delNamespace } = (0, import_nodejs_utils49.useCache)(namespace_collection);
38084
+ async function createIndexes() {
38085
+ try {
38086
+ await collection.createIndexes([
38087
+ { key: { school: 1 } },
38088
+ { key: { section: 1 } },
38089
+ { key: { teacher: 1 } },
38090
+ { key: { subjectCode: 1 } },
38091
+ { key: { schoolYear: 1 } },
38092
+ { key: { gradeLevel: 1 } },
38093
+ { key: { createdAt: 1 } },
38094
+ {
38095
+ key: {
38096
+ subjectName: "text",
38097
+ subjectCode: "text",
38098
+ teacherName: "text"
38099
+ }
38100
+ },
38101
+ {
38102
+ key: {
38103
+ school: 1,
38104
+ section: 1,
38105
+ subjectCode: 1,
38106
+ schoolYear: 1,
38107
+ status: 1
38108
+ },
38109
+ unique: true,
38110
+ name: "unique_section_subject"
38111
+ }
38112
+ ]);
38113
+ } catch (error) {
38114
+ throw new Error("Failed to create index on section subjects.");
38115
+ }
38116
+ }
38117
+ function delCachedData() {
38118
+ delNamespace().then(() => {
38119
+ import_nodejs_utils49.logger.log({
38120
+ level: "info",
38121
+ message: `Cache namespace cleared for ${namespace_collection}`
38122
+ });
38123
+ }).catch((err) => {
38124
+ import_nodejs_utils49.logger.log({
38125
+ level: "error",
38126
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
38127
+ });
38128
+ });
38129
+ }
38130
+ async function add(value, session) {
38131
+ try {
38132
+ value = modelSectionSubject(value);
38133
+ const res = await collection.insertOne(value, { session });
38134
+ delCachedData();
38135
+ return res.insertedId;
38136
+ } catch (error) {
38137
+ import_nodejs_utils49.logger.log({
38138
+ level: "error",
38139
+ message: error.message
38140
+ });
38141
+ if (error instanceof import_nodejs_utils49.AppError) {
38142
+ throw error;
38143
+ } else {
38144
+ const isDuplicated = error.message.includes("duplicate");
38145
+ if (isDuplicated) {
38146
+ throw new import_nodejs_utils49.BadRequestError("Section subject already exists.");
38147
+ }
38148
+ throw new Error("Failed to create section subject.");
37987
38149
  }
37988
38150
  }
37989
- return sizes;
37990
38151
  }
37991
- async function generateSections(value) {
37992
- const { error } = schemaGenerateSections.validate(value);
37993
- if (error) {
37994
- throw new import_nodejs_utils48.BadRequestError(
37995
- `Invalid section generation data: ${error.message}`
37996
- );
38152
+ async function getAll({
38153
+ search = "",
38154
+ page = 1,
38155
+ limit = 10,
38156
+ sort = {},
38157
+ status = "active",
38158
+ school = "",
38159
+ section = "",
38160
+ teacher = "",
38161
+ schoolYear = "",
38162
+ gradeLevel = "",
38163
+ subjectCode = ""
38164
+ } = {}) {
38165
+ page = page > 0 ? page - 1 : 0;
38166
+ const query = { status: { $ne: "deleted" } };
38167
+ const cacheKeyOptions = {
38168
+ page,
38169
+ limit,
38170
+ sort: JSON.stringify(sort)
38171
+ };
38172
+ if (status) {
38173
+ query.status = status;
38174
+ cacheKeyOptions.status = status;
37997
38175
  }
37998
- const session = import_nodejs_utils48.useAtlas.getClient()?.startSession();
37999
- if (!session) {
38000
- throw new Error("Unable to start database session.");
38176
+ if (school) {
38177
+ try {
38178
+ query.school = new import_mongodb29.ObjectId(school);
38179
+ } catch (error) {
38180
+ throw new import_nodejs_utils49.BadRequestError("Invalid school ID.");
38181
+ }
38182
+ cacheKeyOptions.school = school;
38183
+ }
38184
+ if (section) {
38185
+ try {
38186
+ query.section = new import_mongodb29.ObjectId(section);
38187
+ } catch (error) {
38188
+ throw new import_nodejs_utils49.BadRequestError("Invalid section ID.");
38189
+ }
38190
+ cacheKeyOptions.section = section;
38191
+ }
38192
+ if (teacher) {
38193
+ try {
38194
+ query.teacher = new import_mongodb29.ObjectId(teacher);
38195
+ } catch (error) {
38196
+ throw new import_nodejs_utils49.BadRequestError("Invalid teacher ID.");
38197
+ }
38198
+ cacheKeyOptions.teacher = teacher;
38199
+ }
38200
+ if (schoolYear) {
38201
+ query.schoolYear = schoolYear;
38202
+ cacheKeyOptions.schoolYear = schoolYear;
38001
38203
  }
38204
+ if (gradeLevel) {
38205
+ query.gradeLevel = gradeLevel;
38206
+ cacheKeyOptions.gradeLevel = gradeLevel;
38207
+ }
38208
+ if (subjectCode) {
38209
+ query.subjectCode = subjectCode;
38210
+ cacheKeyOptions.subjectCode = subjectCode;
38211
+ }
38212
+ sort = Object.keys(sort).length > 0 ? sort : { _id: 1 };
38213
+ if (search) {
38214
+ query.$text = { $search: search };
38215
+ cacheKeyOptions.search = search;
38216
+ }
38217
+ const cacheKey = (0, import_nodejs_utils49.makeCacheKey)(namespace_collection, cacheKeyOptions);
38218
+ import_nodejs_utils49.logger.log({
38219
+ level: "info",
38220
+ message: `Cache key for getAll section subjects: ${cacheKey}`
38221
+ });
38002
38222
  try {
38003
- await session.startTransaction();
38004
- const studentCount = await getCountByGradeLevel(
38005
- {
38006
- school: value.school,
38007
- schoolYear: value.schoolYear,
38008
- gradeLevel: value.gradeLevel
38009
- },
38010
- session
38011
- );
38012
- if (studentCount === 0) {
38013
- throw new import_nodejs_utils48.BadRequestError("No learners found for this grade level.");
38223
+ const cached = await getCache(cacheKey);
38224
+ if (cached) {
38225
+ import_nodejs_utils49.logger.log({
38226
+ level: "info",
38227
+ message: `Cache hit for getAll section subjects: ${cacheKey}`
38228
+ });
38229
+ return cached;
38014
38230
  }
38015
- const gradeLevelData = await getByGradeLevel(
38016
- {
38017
- school: value.school,
38018
- gradeLevel: value.gradeLevel
38019
- },
38020
- session
38021
- );
38022
- if (!gradeLevelData) {
38023
- throw new import_nodejs_utils48.BadRequestError("Grade level not found.");
38231
+ const items = await collection.aggregate([
38232
+ { $match: query },
38233
+ { $sort: sort },
38234
+ { $skip: page * limit },
38235
+ { $limit: limit }
38236
+ ]).toArray();
38237
+ const length = await collection.countDocuments(query);
38238
+ const data = (0, import_nodejs_utils49.paginate)(items, page, limit, length);
38239
+ setCache(cacheKey, data, 600).then(() => {
38240
+ import_nodejs_utils49.logger.log({
38241
+ level: "info",
38242
+ message: `Cache set for getAll section subjects: ${cacheKey}`
38243
+ });
38244
+ }).catch((err) => {
38245
+ import_nodejs_utils49.logger.log({
38246
+ level: "error",
38247
+ message: `Failed to set cache for getAll section subjects: ${err.message}`
38248
+ });
38249
+ });
38250
+ return data;
38251
+ } catch (error) {
38252
+ import_nodejs_utils49.logger.log({ level: "error", message: `${error}` });
38253
+ throw error;
38254
+ }
38255
+ }
38256
+ async function getById(_id) {
38257
+ try {
38258
+ _id = new import_mongodb29.ObjectId(_id);
38259
+ } catch (error) {
38260
+ throw new import_nodejs_utils49.BadRequestError("Invalid ID.");
38261
+ }
38262
+ const cacheKey = (0, import_nodejs_utils49.makeCacheKey)(namespace_collection, { _id: String(_id) });
38263
+ try {
38264
+ const cached = await getCache(cacheKey);
38265
+ if (cached) {
38266
+ import_nodejs_utils49.logger.log({
38267
+ level: "info",
38268
+ message: `Cache hit for getById section subject: ${cacheKey}`
38269
+ });
38270
+ return cached;
38024
38271
  }
38025
- const minPerSection = gradeLevelData.minNumberOfLearners;
38026
- const maxPerSection = gradeLevelData.maxNumberOfLearners;
38027
- const sectionsNeeded = Math.ceil(studentCount / minPerSection);
38028
- if (sectionsNeeded > value.set.length) {
38029
- throw new import_nodejs_utils48.BadRequestError(
38030
- "Insufficient number of section names in set[]."
38272
+ const result = await collection.findOne({
38273
+ _id,
38274
+ deletedAt: { $in: ["", null] }
38275
+ });
38276
+ if (!result) {
38277
+ throw new import_nodejs_utils49.BadRequestError("Section subject not found.");
38278
+ }
38279
+ setCache(cacheKey, result, 300).then(() => {
38280
+ import_nodejs_utils49.logger.log({
38281
+ level: "info",
38282
+ message: `Cache set for section subject by id: ${cacheKey}`
38283
+ });
38284
+ }).catch((err) => {
38285
+ import_nodejs_utils49.logger.log({
38286
+ level: "error",
38287
+ message: `Failed to set cache for section subject by id: ${err.message}`
38288
+ });
38289
+ });
38290
+ return result;
38291
+ } catch (error) {
38292
+ if (error instanceof import_nodejs_utils49.AppError) {
38293
+ throw error;
38294
+ } else {
38295
+ throw new import_nodejs_utils49.InternalServerError("Failed to get section subject.");
38296
+ }
38297
+ }
38298
+ }
38299
+ async function getBySection(section) {
38300
+ try {
38301
+ section = new import_mongodb29.ObjectId(section);
38302
+ } catch (error) {
38303
+ throw new import_nodejs_utils49.BadRequestError("Invalid section ID.");
38304
+ }
38305
+ const cacheKey = (0, import_nodejs_utils49.makeCacheKey)(namespace_collection, {
38306
+ section: String(section)
38307
+ });
38308
+ try {
38309
+ const cached = await getCache(cacheKey);
38310
+ if (cached) {
38311
+ import_nodejs_utils49.logger.log({
38312
+ level: "info",
38313
+ message: `Cache hit for getBySection section subjects: ${cacheKey}`
38314
+ });
38315
+ return cached;
38316
+ }
38317
+ const result = await collection.find({
38318
+ section,
38319
+ deletedAt: { $in: ["", null] }
38320
+ }).toArray();
38321
+ setCache(cacheKey, result, 300).then(() => {
38322
+ import_nodejs_utils49.logger.log({
38323
+ level: "info",
38324
+ message: `Cache set for section subjects by section: ${cacheKey}`
38325
+ });
38326
+ }).catch((err) => {
38327
+ import_nodejs_utils49.logger.log({
38328
+ level: "error",
38329
+ message: `Failed to set cache for section subjects by section: ${err.message}`
38330
+ });
38331
+ });
38332
+ return result;
38333
+ } catch (error) {
38334
+ if (error instanceof import_nodejs_utils49.AppError) {
38335
+ throw error;
38336
+ } else {
38337
+ throw new import_nodejs_utils49.InternalServerError(
38338
+ "Failed to get section subjects by section."
38031
38339
  );
38032
38340
  }
38033
- const sectionSizes = distributeStudents(
38034
- studentCount,
38035
- minPerSection,
38036
- maxPerSection
38037
- );
38038
- if (sectionSizes.length === 0) {
38039
- throw new import_nodejs_utils48.BadRequestError("Unable to compute section sizes.");
38341
+ }
38342
+ }
38343
+ async function getByTeacher(teacher) {
38344
+ try {
38345
+ teacher = new import_mongodb29.ObjectId(teacher);
38346
+ } catch (error) {
38347
+ throw new import_nodejs_utils49.BadRequestError("Invalid teacher ID.");
38348
+ }
38349
+ const cacheKey = (0, import_nodejs_utils49.makeCacheKey)(namespace_collection, {
38350
+ teacher: String(teacher)
38351
+ });
38352
+ try {
38353
+ const cached = await getCache(cacheKey);
38354
+ if (cached) {
38355
+ import_nodejs_utils49.logger.log({
38356
+ level: "info",
38357
+ message: `Cache hit for getByTeacher section subjects: ${cacheKey}`
38358
+ });
38359
+ return cached;
38040
38360
  }
38041
- let pointer = 0;
38042
- for (let i = 0; i < sectionSizes.length; i++) {
38043
- const size = sectionSizes[i];
38044
- const sectionName = value.set[i];
38045
- const section = await createSection(
38046
- {
38047
- school: value.school,
38048
- schoolYear: value.schoolYear,
38049
- gradeLevel: value.gradeLevel,
38050
- name: sectionName,
38051
- students: size
38052
- },
38053
- session
38361
+ const result = await collection.find({
38362
+ teacher,
38363
+ deletedAt: { $in: ["", null] }
38364
+ }).toArray();
38365
+ setCache(cacheKey, result, 300).then(() => {
38366
+ import_nodejs_utils49.logger.log({
38367
+ level: "info",
38368
+ message: `Cache set for section subjects by teacher: ${cacheKey}`
38369
+ });
38370
+ }).catch((err) => {
38371
+ import_nodejs_utils49.logger.log({
38372
+ level: "error",
38373
+ message: `Failed to set cache for section subjects by teacher: ${err.message}`
38374
+ });
38375
+ });
38376
+ return result;
38377
+ } catch (error) {
38378
+ if (error instanceof import_nodejs_utils49.AppError) {
38379
+ throw error;
38380
+ } else {
38381
+ throw new import_nodejs_utils49.InternalServerError(
38382
+ "Failed to get section subjects by teacher."
38054
38383
  );
38055
- const learners = await getLeanerByGradeLevel(
38056
- {
38057
- school: value.school,
38058
- gradeLevel: value.gradeLevel,
38059
- skip: pointer,
38060
- limit: size
38061
- },
38062
- session
38384
+ }
38385
+ }
38386
+ }
38387
+ async function getBySchool(school) {
38388
+ try {
38389
+ school = new import_mongodb29.ObjectId(school);
38390
+ } catch (error) {
38391
+ throw new import_nodejs_utils49.BadRequestError("Invalid school ID.");
38392
+ }
38393
+ const cacheKey = (0, import_nodejs_utils49.makeCacheKey)(namespace_collection, {
38394
+ school: String(school)
38395
+ });
38396
+ try {
38397
+ const cached = await getCache(cacheKey);
38398
+ if (cached) {
38399
+ import_nodejs_utils49.logger.log({
38400
+ level: "info",
38401
+ message: `Cache hit for getBySchool section subjects: ${cacheKey}`
38402
+ });
38403
+ return cached;
38404
+ }
38405
+ const result = await collection.find({
38406
+ school,
38407
+ deletedAt: { $in: ["", null] }
38408
+ }).toArray();
38409
+ setCache(cacheKey, result, 300).then(() => {
38410
+ import_nodejs_utils49.logger.log({
38411
+ level: "info",
38412
+ message: `Cache set for section subjects by school: ${cacheKey}`
38413
+ });
38414
+ }).catch((err) => {
38415
+ import_nodejs_utils49.logger.log({
38416
+ level: "error",
38417
+ message: `Failed to set cache for section subjects by school: ${err.message}`
38418
+ });
38419
+ });
38420
+ return result;
38421
+ } catch (error) {
38422
+ if (error instanceof import_nodejs_utils49.AppError) {
38423
+ throw error;
38424
+ } else {
38425
+ throw new import_nodejs_utils49.InternalServerError(
38426
+ "Failed to get section subjects by school."
38063
38427
  );
38064
- if (!learners.length) {
38065
- throw new import_nodejs_utils48.BadRequestError(`No learners found for section #${i + 1}.`);
38066
- }
38067
- pointer += size;
38068
- for (const student of learners) {
38069
- if (!student._id) {
38070
- throw new import_nodejs_utils48.BadRequestError("Learner ID is missing.");
38071
- }
38072
- await assignStudent(
38073
- {
38074
- section: section.toString(),
38075
- student: student._id?.toString(),
38076
- studentName: `${student.learnerInfo.firstName} ${student.learnerInfo.lastName}`,
38077
- status: "active"
38078
- },
38079
- session
38080
- );
38081
- }
38082
38428
  }
38083
- await session.commitTransaction();
38084
- return "Sections generated successfully.";
38429
+ }
38430
+ }
38431
+ async function updateFieldById({ _id, field, value } = {}, session) {
38432
+ const allowedFields = [
38433
+ "teacher",
38434
+ "teacherName",
38435
+ "classroom",
38436
+ "schedule",
38437
+ "daysOfWeek"
38438
+ ];
38439
+ if (!allowedFields.includes(field)) {
38440
+ throw new import_nodejs_utils49.BadRequestError(
38441
+ `Field "${field}" is not allowed to be updated.`
38442
+ );
38443
+ }
38444
+ try {
38445
+ _id = new import_mongodb29.ObjectId(_id);
38446
+ } catch (error) {
38447
+ throw new import_nodejs_utils49.BadRequestError("Invalid ID.");
38448
+ }
38449
+ if (field === "teacher" && value) {
38450
+ try {
38451
+ value = new import_mongodb29.ObjectId(value).toString();
38452
+ } catch (error) {
38453
+ throw new import_nodejs_utils49.BadRequestError("Invalid teacher ID.");
38454
+ }
38455
+ }
38456
+ try {
38457
+ const updateValue = field === "teacher" ? new import_mongodb29.ObjectId(value) : value;
38458
+ await collection.updateOne(
38459
+ { _id, deletedAt: { $in: ["", null] } },
38460
+ { $set: { [field]: updateValue, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } },
38461
+ { session }
38462
+ );
38463
+ delCachedData();
38464
+ return `Successfully updated section subject ${field}.`;
38465
+ } catch (error) {
38466
+ throw new import_nodejs_utils49.InternalServerError(
38467
+ `Failed to update section subject ${field}.`
38468
+ );
38469
+ }
38470
+ }
38471
+ async function setupById(_id, value, session) {
38472
+ const { error } = schemaSectionSubjectSetup.validate(value);
38473
+ if (error) {
38474
+ throw new import_nodejs_utils49.BadRequestError(
38475
+ `Invalid section subject data: ${error.message}`
38476
+ );
38477
+ }
38478
+ try {
38479
+ _id = new import_mongodb29.ObjectId(_id);
38085
38480
  } catch (error2) {
38086
- await session.abortTransaction();
38087
- if (error2 instanceof import_nodejs_utils48.AppError) {
38481
+ throw new import_nodejs_utils49.BadRequestError("Invalid ID.");
38482
+ }
38483
+ try {
38484
+ await collection.updateOne(
38485
+ { _id, deletedAt: { $in: ["", null] } },
38486
+ { $set: { ...value, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } },
38487
+ { session }
38488
+ );
38489
+ delCachedData();
38490
+ return `Successfully updated section subject.`;
38491
+ } catch (error2) {
38492
+ throw new import_nodejs_utils49.InternalServerError(`Failed to update section subject.`);
38493
+ }
38494
+ }
38495
+ async function deleteById(_id) {
38496
+ try {
38497
+ _id = new import_mongodb29.ObjectId(_id);
38498
+ } catch (error) {
38499
+ throw new import_nodejs_utils49.BadRequestError("Invalid ID.");
38500
+ }
38501
+ try {
38502
+ await collection.updateOne(
38503
+ { _id },
38504
+ { $set: { status: "deleted", deletedAt: (/* @__PURE__ */ new Date()).toISOString() } }
38505
+ );
38506
+ delCachedData();
38507
+ return "Successfully deleted section subject.";
38508
+ } catch (error) {
38509
+ throw new import_nodejs_utils49.InternalServerError("Failed to delete section subject.");
38510
+ }
38511
+ }
38512
+ return {
38513
+ createIndexes,
38514
+ add,
38515
+ getAll,
38516
+ getById,
38517
+ getBySection,
38518
+ getByTeacher,
38519
+ getBySchool,
38520
+ updateFieldById,
38521
+ setupById,
38522
+ deleteById
38523
+ };
38524
+ }
38525
+
38526
+ // src/resources/section-subject/section.subject.service.ts
38527
+ var import_nodejs_utils50 = require("@eeplatform/nodejs-utils");
38528
+ function useSectionSubjectService() {
38529
+ const { getById: getSchoolById } = useSchoolRepo();
38530
+ const { add: _add } = useSectionSubjectRepo();
38531
+ async function add(value) {
38532
+ const { error } = schemaSectionSubject.validate(value);
38533
+ if (error) {
38534
+ throw new Error(`Invalid section subject data: ${error.message}`);
38535
+ }
38536
+ try {
38537
+ const school = await getSchoolById(value.school);
38538
+ if (!school) {
38539
+ throw new Error("School not found.");
38540
+ }
38541
+ if (!school.name) {
38542
+ throw new Error("School name is missing.");
38543
+ }
38544
+ value.schoolName = school.name;
38545
+ await _add(value);
38546
+ return "Successfully created section subject.";
38547
+ } catch (error2) {
38548
+ if (error2 instanceof import_nodejs_utils50.AppError) {
38088
38549
  throw error2;
38089
38550
  } else {
38090
- throw new import_nodejs_utils48.InternalServerError("Failed to generate sections.");
38551
+ throw new import_nodejs_utils50.InternalServerError("Failed to create section subject.");
38091
38552
  }
38092
- } finally {
38093
- await session?.endSession();
38094
38553
  }
38095
38554
  }
38096
- return { generateSections };
38555
+ return {
38556
+ add
38557
+ };
38097
38558
  }
38098
38559
 
38099
- // src/resources/section/section.controller.ts
38100
- function useSectionController() {
38560
+ // src/resources/section-subject/section.subject.controller.ts
38561
+ var import_nodejs_utils51 = require("@eeplatform/nodejs-utils");
38562
+ var import_joi30 = __toESM(require("joi"));
38563
+ function useSectionSubjectController() {
38101
38564
  const {
38102
- add: _add,
38103
38565
  getAll: _getAll,
38104
38566
  getById: _getById,
38105
- getByName: _getByName,
38567
+ getBySection: _getBySection,
38568
+ getByTeacher: _getByTeacher,
38106
38569
  getBySchool: _getBySchool,
38107
38570
  updateFieldById: _updateFieldById,
38108
- addStudentToSection: _addStudentToSection,
38109
- removeStudentFromSection: _removeStudentFromSection,
38110
- deleteById: _deleteById
38111
- } = useSectionRepo();
38112
- const { generateSections: _generateSections } = useSectionService();
38571
+ deleteById: _deleteById,
38572
+ setupById: _setupById
38573
+ } = useSectionSubjectRepo();
38574
+ const { add: _add } = useSectionSubjectService();
38113
38575
  async function add(req, res, next) {
38114
38576
  const value = req.body;
38115
- const { error } = schemaSection.validate(value);
38577
+ const { error } = schemaSectionSubject.validate(value);
38116
38578
  if (error) {
38117
- next(new import_nodejs_utils49.BadRequestError(error.message));
38579
+ next(new import_nodejs_utils51.BadRequestError(error.message));
38118
38580
  return;
38119
38581
  }
38120
38582
  try {
38121
38583
  const data = await _add(value);
38122
38584
  res.json({
38123
- message: "Successfully created section.",
38124
- data
38125
- });
38126
- return;
38127
- } catch (error2) {
38128
- next(error2);
38129
- }
38130
- }
38131
- async function generateSections(req, res, next) {
38132
- const value = req.body;
38133
- const { error } = schemaGenerateSections.validate(value);
38134
- if (error) {
38135
- next(new import_nodejs_utils49.BadRequestError(error.message));
38136
- return;
38137
- }
38138
- try {
38139
- const data = await _generateSections(value);
38140
- res.json({
38141
- message: "Successfully created section.",
38585
+ message: "Successfully created section subject.",
38142
38586
  data
38143
38587
  });
38144
38588
  return;
@@ -38148,35 +38592,41 @@ function useSectionController() {
38148
38592
  }
38149
38593
  async function getAll(req, res, next) {
38150
38594
  const query = req.query;
38151
- const validation = import_joi29.default.object({
38152
- page: import_joi29.default.number().min(1).optional().allow("", null),
38153
- limit: import_joi29.default.number().min(1).optional().allow("", null),
38154
- search: import_joi29.default.string().optional().allow("", null),
38155
- status: import_joi29.default.string().optional().allow("", null),
38156
- school: import_joi29.default.string().hex().optional().allow("", null),
38157
- schoolYear: import_joi29.default.string().optional().allow("", null),
38158
- gradeLevel: import_joi29.default.string().optional().allow("", null)
38595
+ const validation = import_joi30.default.object({
38596
+ page: import_joi30.default.number().min(1).optional().allow("", null),
38597
+ limit: import_joi30.default.number().min(1).optional().allow("", null),
38598
+ search: import_joi30.default.string().optional().allow("", null),
38599
+ status: import_joi30.default.string().optional().allow("", null),
38600
+ school: import_joi30.default.string().hex().optional().allow("", null),
38601
+ section: import_joi30.default.string().hex().optional().allow("", null),
38602
+ teacher: import_joi30.default.string().hex().optional().allow("", null),
38603
+ schoolYear: import_joi30.default.string().optional().allow("", null),
38604
+ gradeLevel: import_joi30.default.string().optional().allow("", null),
38605
+ subjectCode: import_joi30.default.string().optional().allow("", null)
38159
38606
  });
38160
38607
  const { error } = validation.validate(query);
38161
38608
  const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
38162
38609
  const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
38163
38610
  const search = req.query.search ?? "";
38164
- const status = req.query.status ?? "active";
38611
+ const status = req.query.status ?? "";
38165
38612
  const school = req.query.school ?? "";
38613
+ const section = req.query.section ?? "";
38614
+ const teacher = req.query.teacher ?? "";
38166
38615
  const schoolYear = req.query.schoolYear ?? "";
38167
38616
  const gradeLevel = req.query.gradeLevel ?? "";
38617
+ const subjectCode = req.query.subjectCode ?? "";
38168
38618
  const isPageNumber = isFinite(page);
38169
38619
  if (!isPageNumber) {
38170
- next(new import_nodejs_utils49.BadRequestError("Invalid page number."));
38620
+ next(new import_nodejs_utils51.BadRequestError("Invalid page number."));
38171
38621
  return;
38172
38622
  }
38173
38623
  const isLimitNumber = isFinite(limit);
38174
38624
  if (!isLimitNumber) {
38175
- next(new import_nodejs_utils49.BadRequestError("Invalid limit number."));
38625
+ next(new import_nodejs_utils51.BadRequestError("Invalid limit number."));
38176
38626
  return;
38177
38627
  }
38178
38628
  if (error) {
38179
- next(new import_nodejs_utils49.BadRequestError(error.message));
38629
+ next(new import_nodejs_utils51.BadRequestError(error.message));
38180
38630
  return;
38181
38631
  }
38182
38632
  try {
@@ -38186,8 +38636,11 @@ function useSectionController() {
38186
38636
  search,
38187
38637
  status,
38188
38638
  school,
38639
+ section,
38640
+ teacher,
38189
38641
  schoolYear,
38190
- gradeLevel
38642
+ gradeLevel,
38643
+ subjectCode
38191
38644
  });
38192
38645
  res.json(data);
38193
38646
  return;
@@ -38197,18 +38650,386 @@ function useSectionController() {
38197
38650
  }
38198
38651
  async function getById(req, res, next) {
38199
38652
  const id = req.params.id;
38200
- const validation = import_joi29.default.object({
38201
- id: import_joi29.default.string().hex().required()
38653
+ const validation = import_joi30.default.object({
38654
+ id: import_joi30.default.string().hex().required()
38202
38655
  });
38203
38656
  const { error } = validation.validate({ id });
38204
38657
  if (error) {
38205
- next(new import_nodejs_utils49.BadRequestError(error.message));
38658
+ next(new import_nodejs_utils51.BadRequestError(error.message));
38206
38659
  return;
38207
38660
  }
38208
38661
  try {
38209
38662
  const data = await _getById(id);
38210
38663
  res.json({
38211
- message: "Successfully retrieved section.",
38664
+ message: "Successfully retrieved section subject.",
38665
+ data
38666
+ });
38667
+ return;
38668
+ } catch (error2) {
38669
+ next(error2);
38670
+ }
38671
+ }
38672
+ async function getBySection(req, res, next) {
38673
+ const section = req.params.section;
38674
+ const validation = import_joi30.default.object({
38675
+ section: import_joi30.default.string().hex().required()
38676
+ });
38677
+ const { error } = validation.validate({ section });
38678
+ if (error) {
38679
+ next(new import_nodejs_utils51.BadRequestError(error.message));
38680
+ return;
38681
+ }
38682
+ try {
38683
+ const data = await _getBySection(section);
38684
+ res.json({
38685
+ message: "Successfully retrieved section subjects.",
38686
+ data
38687
+ });
38688
+ return;
38689
+ } catch (error2) {
38690
+ next(error2);
38691
+ }
38692
+ }
38693
+ async function getByTeacher(req, res, next) {
38694
+ const teacher = req.params.teacher;
38695
+ const validation = import_joi30.default.object({
38696
+ teacher: import_joi30.default.string().hex().required()
38697
+ });
38698
+ const { error } = validation.validate({ teacher });
38699
+ if (error) {
38700
+ next(new import_nodejs_utils51.BadRequestError(error.message));
38701
+ return;
38702
+ }
38703
+ try {
38704
+ const data = await _getByTeacher(teacher);
38705
+ res.json({
38706
+ message: "Successfully retrieved section subjects.",
38707
+ data
38708
+ });
38709
+ return;
38710
+ } catch (error2) {
38711
+ next(error2);
38712
+ }
38713
+ }
38714
+ async function getBySchool(req, res, next) {
38715
+ const school = req.params.school;
38716
+ const validation = import_joi30.default.object({
38717
+ school: import_joi30.default.string().hex().required()
38718
+ });
38719
+ const { error } = validation.validate({ school });
38720
+ if (error) {
38721
+ next(new import_nodejs_utils51.BadRequestError(error.message));
38722
+ return;
38723
+ }
38724
+ try {
38725
+ const data = await _getBySchool(school);
38726
+ res.json({
38727
+ message: "Successfully retrieved section subjects.",
38728
+ data
38729
+ });
38730
+ return;
38731
+ } catch (error2) {
38732
+ next(error2);
38733
+ }
38734
+ }
38735
+ async function updateField(req, res, next) {
38736
+ const _id = req.params.id;
38737
+ const { field, value } = req.body;
38738
+ const validation = import_joi30.default.object({
38739
+ _id: import_joi30.default.string().hex().required(),
38740
+ field: import_joi30.default.string().valid(
38741
+ "subjectCode",
38742
+ "subjectName",
38743
+ "teacher",
38744
+ "teacherName",
38745
+ "classroom",
38746
+ "schedule"
38747
+ ).required(),
38748
+ value: import_joi30.default.string().required()
38749
+ });
38750
+ const { error } = validation.validate({ _id, field, value });
38751
+ if (error) {
38752
+ next(new import_nodejs_utils51.BadRequestError(error.message));
38753
+ return;
38754
+ }
38755
+ try {
38756
+ const message = await _updateFieldById({ _id, field, value });
38757
+ res.json({ message });
38758
+ return;
38759
+ } catch (error2) {
38760
+ next(error2);
38761
+ }
38762
+ }
38763
+ async function setupById(req, res, next) {
38764
+ const _id = req.params.id;
38765
+ const data = req.body;
38766
+ const { error } = schemaSectionSubjectSetup.validate(data);
38767
+ if (error) {
38768
+ next(new import_nodejs_utils51.BadRequestError(error.message));
38769
+ return;
38770
+ }
38771
+ try {
38772
+ const message = await _setupById(_id, data);
38773
+ res.json({ message });
38774
+ return;
38775
+ } catch (error2) {
38776
+ next(error2);
38777
+ }
38778
+ }
38779
+ async function deleteById(req, res, next) {
38780
+ const _id = req.params.id;
38781
+ const validation = import_joi30.default.object({
38782
+ _id: import_joi30.default.string().hex().required()
38783
+ });
38784
+ const { error } = validation.validate({ _id });
38785
+ if (error) {
38786
+ next(new import_nodejs_utils51.BadRequestError(error.message));
38787
+ return;
38788
+ }
38789
+ try {
38790
+ const message = await _deleteById(_id);
38791
+ res.json({ message });
38792
+ return;
38793
+ } catch (error2) {
38794
+ next(error2);
38795
+ }
38796
+ }
38797
+ return {
38798
+ add,
38799
+ getAll,
38800
+ getById,
38801
+ getBySection,
38802
+ getByTeacher,
38803
+ getBySchool,
38804
+ updateField,
38805
+ setupById,
38806
+ deleteById
38807
+ };
38808
+ }
38809
+
38810
+ // src/resources/section/section.service.ts
38811
+ function useSectionService() {
38812
+ const { getCountByGradeLevel, getByGradeLevel: getLeanerByGradeLevel } = useLearnerRepo();
38813
+ const { getByGradeLevel } = useGradeLevelRepo();
38814
+ const { add: createSection } = useSectionRepo();
38815
+ const { add: assignStudent } = useSectionStudentRepo();
38816
+ const { getAll: getAllCurriculumSubjects } = useCurriculumSubjectRepo();
38817
+ const { add: addSectionSubject } = useSectionSubjectRepo();
38818
+ function distributeStudents(total, minPer, maxPer) {
38819
+ if (total <= 0)
38820
+ return [];
38821
+ if (minPer <= 0 || maxPer <= 0)
38822
+ return [];
38823
+ if (minPer > maxPer) {
38824
+ throw new import_nodejs_utils52.BadRequestError(
38825
+ "Minimum students per section cannot be greater than maximum."
38826
+ );
38827
+ }
38828
+ const minSections = Math.ceil(total / maxPer);
38829
+ const maxSections = Math.floor(total / minPer);
38830
+ let sectionCount;
38831
+ if (minSections <= maxSections) {
38832
+ sectionCount = minSections;
38833
+ } else {
38834
+ sectionCount = minSections;
38835
+ }
38836
+ const base = Math.floor(total / sectionCount);
38837
+ const extra = total % sectionCount;
38838
+ const sizes = new Array(sectionCount).fill(base);
38839
+ for (let i = 0; i < extra; i++) {
38840
+ sizes[i] += 1;
38841
+ }
38842
+ for (const size of sizes) {
38843
+ if (size > maxPer) {
38844
+ throw new import_nodejs_utils52.BadRequestError(
38845
+ `Generated section exceeds max limit of ${maxPer}.`
38846
+ );
38847
+ }
38848
+ }
38849
+ return sizes;
38850
+ }
38851
+ async function generateSections(value) {
38852
+ const { error } = schemaGenerateSections.validate(value);
38853
+ if (error) {
38854
+ throw new import_nodejs_utils52.BadRequestError(
38855
+ `Invalid section generation data: ${error.message}`
38856
+ );
38857
+ }
38858
+ const session = import_nodejs_utils52.useAtlas.getClient()?.startSession();
38859
+ if (!session) {
38860
+ throw new Error("Unable to start database session.");
38861
+ }
38862
+ try {
38863
+ await session.startTransaction();
38864
+ const studentCount = await getCountByGradeLevel(
38865
+ {
38866
+ school: value.school,
38867
+ schoolYear: value.schoolYear,
38868
+ gradeLevel: value.gradeLevel
38869
+ },
38870
+ session
38871
+ );
38872
+ if (studentCount === 0) {
38873
+ throw new import_nodejs_utils52.BadRequestError("No learners found for this grade level.");
38874
+ }
38875
+ const gradeLevelData = await getByGradeLevel(
38876
+ {
38877
+ school: value.school,
38878
+ gradeLevel: value.gradeLevel
38879
+ },
38880
+ session
38881
+ );
38882
+ if (!gradeLevelData) {
38883
+ throw new import_nodejs_utils52.BadRequestError("Grade level not found.");
38884
+ }
38885
+ const minPerSection = gradeLevelData.minNumberOfLearners;
38886
+ const maxPerSection = gradeLevelData.maxNumberOfLearners;
38887
+ const sectionsNeeded = Math.ceil(studentCount / minPerSection);
38888
+ if (sectionsNeeded > value.set.length) {
38889
+ throw new import_nodejs_utils52.BadRequestError(
38890
+ "Insufficient number of section names in set[]."
38891
+ );
38892
+ }
38893
+ const sectionSizes = distributeStudents(
38894
+ studentCount,
38895
+ minPerSection,
38896
+ maxPerSection
38897
+ );
38898
+ if (sectionSizes.length === 0) {
38899
+ throw new import_nodejs_utils52.BadRequestError("Unable to compute section sizes.");
38900
+ }
38901
+ let totalStudentsProcessed = 0;
38902
+ for (let i = 0; i < sectionSizes.length; i++) {
38903
+ const size = sectionSizes[i];
38904
+ const sectionName = value.set[i];
38905
+ const section = await createSection(
38906
+ {
38907
+ school: value.school,
38908
+ schoolYear: value.schoolYear,
38909
+ gradeLevel: value.gradeLevel,
38910
+ name: sectionName,
38911
+ students: size
38912
+ },
38913
+ session
38914
+ );
38915
+ const skip = totalStudentsProcessed;
38916
+ const learners = await getLeanerByGradeLevel(
38917
+ {
38918
+ school: value.school,
38919
+ gradeLevel: value.gradeLevel,
38920
+ skip,
38921
+ limit: size
38922
+ },
38923
+ session
38924
+ );
38925
+ if (!learners.length) {
38926
+ throw new import_nodejs_utils52.BadRequestError(`No learners found for section #${i + 1}.`);
38927
+ }
38928
+ totalStudentsProcessed += learners.length;
38929
+ for (const student of learners) {
38930
+ if (!student._id) {
38931
+ throw new import_nodejs_utils52.BadRequestError("Learner ID is missing.");
38932
+ }
38933
+ await assignStudent(
38934
+ {
38935
+ section: section.toString(),
38936
+ student: student._id?.toString(),
38937
+ studentName: `${student.learnerInfo.firstName} ${student.learnerInfo.lastName}`,
38938
+ status: "active"
38939
+ },
38940
+ session
38941
+ );
38942
+ }
38943
+ const curriculumSubjects = await getAllCurriculumSubjects({
38944
+ schoolYear: Number(value.schoolYear),
38945
+ gradeLevel: value.gradeLevel,
38946
+ limit: 20
38947
+ });
38948
+ for (const curriculumSubject of curriculumSubjects.items) {
38949
+ await addSectionSubject(
38950
+ {
38951
+ school: value.school,
38952
+ schoolName: "",
38953
+ gradeLevel: value.gradeLevel,
38954
+ educationLevel: gradeLevelData.educationLevel,
38955
+ schoolYear: value.schoolYear,
38956
+ section: section.toString(),
38957
+ sectionName,
38958
+ subjectCode: curriculumSubject.subjectCode,
38959
+ subjectName: curriculumSubject.subjectName,
38960
+ teacher: "",
38961
+ teacherName: "",
38962
+ schedule: "",
38963
+ daysOfWeek: [],
38964
+ classroom: "",
38965
+ classroomName: "",
38966
+ sessionDuration: curriculumSubject.sessionDuration,
38967
+ sessionFrequency: curriculumSubject.sessionFrequency,
38968
+ status: "draft"
38969
+ },
38970
+ session
38971
+ );
38972
+ }
38973
+ }
38974
+ await session.commitTransaction();
38975
+ return "Sections generated successfully.";
38976
+ } catch (error2) {
38977
+ await session.abortTransaction();
38978
+ if (error2 instanceof import_nodejs_utils52.AppError) {
38979
+ throw error2;
38980
+ } else {
38981
+ throw new import_nodejs_utils52.InternalServerError("Failed to generate sections.");
38982
+ }
38983
+ } finally {
38984
+ await session?.endSession();
38985
+ }
38986
+ }
38987
+ return { generateSections };
38988
+ }
38989
+
38990
+ // src/resources/section/section.controller.ts
38991
+ function useSectionController() {
38992
+ const {
38993
+ add: _add,
38994
+ getAll: _getAll,
38995
+ getById: _getById,
38996
+ getByName: _getByName,
38997
+ getBySchool: _getBySchool,
38998
+ updateFieldById: _updateFieldById,
38999
+ addStudentToSection: _addStudentToSection,
39000
+ removeStudentFromSection: _removeStudentFromSection,
39001
+ deleteById: _deleteById
39002
+ } = useSectionRepo();
39003
+ const { generateSections: _generateSections } = useSectionService();
39004
+ async function add(req, res, next) {
39005
+ const value = req.body;
39006
+ const { error } = schemaSection.validate(value);
39007
+ if (error) {
39008
+ next(new import_nodejs_utils53.BadRequestError(error.message));
39009
+ return;
39010
+ }
39011
+ try {
39012
+ const data = await _add(value);
39013
+ res.json({
39014
+ message: "Successfully created section.",
39015
+ data
39016
+ });
39017
+ return;
39018
+ } catch (error2) {
39019
+ next(error2);
39020
+ }
39021
+ }
39022
+ async function generateSections(req, res, next) {
39023
+ const value = req.body;
39024
+ const { error } = schemaGenerateSections.validate(value);
39025
+ if (error) {
39026
+ next(new import_nodejs_utils53.BadRequestError(error.message));
39027
+ return;
39028
+ }
39029
+ try {
39030
+ const data = await _generateSections(value);
39031
+ res.json({
39032
+ message: "Successfully created section.",
38212
39033
  data
38213
39034
  });
38214
39035
  return;
@@ -38216,14 +39037,81 @@ function useSectionController() {
38216
39037
  next(error2);
38217
39038
  }
38218
39039
  }
39040
+ async function getAll(req, res, next) {
39041
+ const query = req.query;
39042
+ const validation = import_joi31.default.object({
39043
+ page: import_joi31.default.number().min(1).optional().allow("", null),
39044
+ limit: import_joi31.default.number().min(1).optional().allow("", null),
39045
+ search: import_joi31.default.string().optional().allow("", null),
39046
+ status: import_joi31.default.string().optional().allow("", null),
39047
+ school: import_joi31.default.string().hex().optional().allow("", null),
39048
+ schoolYear: import_joi31.default.string().optional().allow("", null),
39049
+ gradeLevel: import_joi31.default.string().optional().allow("", null)
39050
+ });
39051
+ const { error } = validation.validate(query);
39052
+ const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
39053
+ const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
39054
+ const search = req.query.search ?? "";
39055
+ const status = req.query.status ?? "active";
39056
+ const school = req.query.school ?? "";
39057
+ const schoolYear = req.query.schoolYear ?? "";
39058
+ const gradeLevel = req.query.gradeLevel ?? "";
39059
+ const isPageNumber = isFinite(page);
39060
+ if (!isPageNumber) {
39061
+ next(new import_nodejs_utils53.BadRequestError("Invalid page number."));
39062
+ return;
39063
+ }
39064
+ const isLimitNumber = isFinite(limit);
39065
+ if (!isLimitNumber) {
39066
+ next(new import_nodejs_utils53.BadRequestError("Invalid limit number."));
39067
+ return;
39068
+ }
39069
+ if (error) {
39070
+ next(new import_nodejs_utils53.BadRequestError(error.message));
39071
+ return;
39072
+ }
39073
+ try {
39074
+ const data = await _getAll({
39075
+ page,
39076
+ limit,
39077
+ search,
39078
+ status,
39079
+ school,
39080
+ schoolYear,
39081
+ gradeLevel
39082
+ });
39083
+ res.json(data);
39084
+ return;
39085
+ } catch (error2) {
39086
+ next(error2);
39087
+ }
39088
+ }
39089
+ async function getById(req, res, next) {
39090
+ const id = req.params.id;
39091
+ const validation = import_joi31.default.object({
39092
+ id: import_joi31.default.string().hex().required()
39093
+ });
39094
+ const { error } = validation.validate({ id });
39095
+ if (error) {
39096
+ next(new import_nodejs_utils53.BadRequestError(error.message));
39097
+ return;
39098
+ }
39099
+ try {
39100
+ const data = await _getById(id);
39101
+ res.json(data);
39102
+ return;
39103
+ } catch (error2) {
39104
+ next(error2);
39105
+ }
39106
+ }
38219
39107
  async function getByName(req, res, next) {
38220
39108
  const name = req.params.name;
38221
- const validation = import_joi29.default.object({
38222
- name: import_joi29.default.string().required()
39109
+ const validation = import_joi31.default.object({
39110
+ name: import_joi31.default.string().required()
38223
39111
  });
38224
39112
  const { error } = validation.validate({ name });
38225
39113
  if (error) {
38226
- next(new import_nodejs_utils49.BadRequestError(error.message));
39114
+ next(new import_nodejs_utils53.BadRequestError(error.message));
38227
39115
  return;
38228
39116
  }
38229
39117
  try {
@@ -38239,12 +39127,12 @@ function useSectionController() {
38239
39127
  }
38240
39128
  async function getBySchool(req, res, next) {
38241
39129
  const school = req.params.school;
38242
- const validation = import_joi29.default.object({
38243
- school: import_joi29.default.string().hex().required()
39130
+ const validation = import_joi31.default.object({
39131
+ school: import_joi31.default.string().hex().required()
38244
39132
  });
38245
39133
  const { error } = validation.validate({ school });
38246
39134
  if (error) {
38247
- next(new import_nodejs_utils49.BadRequestError(error.message));
39135
+ next(new import_nodejs_utils53.BadRequestError(error.message));
38248
39136
  return;
38249
39137
  }
38250
39138
  try {
@@ -38261,14 +39149,14 @@ function useSectionController() {
38261
39149
  async function updateField(req, res, next) {
38262
39150
  const _id = req.params.id;
38263
39151
  const { field, value } = req.body;
38264
- const validation = import_joi29.default.object({
38265
- _id: import_joi29.default.string().hex().required(),
38266
- field: import_joi29.default.string().valid("name", "schoolYear", "gradeLevel", "adviser", "adviserName").required(),
38267
- value: import_joi29.default.string().required()
39152
+ const validation = import_joi31.default.object({
39153
+ _id: import_joi31.default.string().hex().required(),
39154
+ field: import_joi31.default.string().valid("name", "schoolYear", "gradeLevel", "adviser", "adviserName").required(),
39155
+ value: import_joi31.default.string().required()
38268
39156
  });
38269
39157
  const { error } = validation.validate({ _id, field, value });
38270
39158
  if (error) {
38271
- next(new import_nodejs_utils49.BadRequestError(error.message));
39159
+ next(new import_nodejs_utils53.BadRequestError(error.message));
38272
39160
  return;
38273
39161
  }
38274
39162
  try {
@@ -38282,13 +39170,13 @@ function useSectionController() {
38282
39170
  async function addStudent(req, res, next) {
38283
39171
  const _id = req.params.id;
38284
39172
  const { studentId } = req.body;
38285
- const validation = import_joi29.default.object({
38286
- _id: import_joi29.default.string().hex().required(),
38287
- studentId: import_joi29.default.string().required()
39173
+ const validation = import_joi31.default.object({
39174
+ _id: import_joi31.default.string().hex().required(),
39175
+ studentId: import_joi31.default.string().required()
38288
39176
  });
38289
39177
  const { error } = validation.validate({ _id, studentId });
38290
39178
  if (error) {
38291
- next(new import_nodejs_utils49.BadRequestError(error.message));
39179
+ next(new import_nodejs_utils53.BadRequestError(error.message));
38292
39180
  return;
38293
39181
  }
38294
39182
  try {
@@ -38302,13 +39190,13 @@ function useSectionController() {
38302
39190
  async function removeStudent(req, res, next) {
38303
39191
  const _id = req.params.id;
38304
39192
  const { studentId } = req.body;
38305
- const validation = import_joi29.default.object({
38306
- _id: import_joi29.default.string().hex().required(),
38307
- studentId: import_joi29.default.string().required()
39193
+ const validation = import_joi31.default.object({
39194
+ _id: import_joi31.default.string().hex().required(),
39195
+ studentId: import_joi31.default.string().required()
38308
39196
  });
38309
39197
  const { error } = validation.validate({ _id, studentId });
38310
39198
  if (error) {
38311
- next(new import_nodejs_utils49.BadRequestError(error.message));
39199
+ next(new import_nodejs_utils53.BadRequestError(error.message));
38312
39200
  return;
38313
39201
  }
38314
39202
  try {
@@ -38321,12 +39209,12 @@ function useSectionController() {
38321
39209
  }
38322
39210
  async function deleteById(req, res, next) {
38323
39211
  const _id = req.params.id;
38324
- const validation = import_joi29.default.object({
38325
- _id: import_joi29.default.string().hex().required()
39212
+ const validation = import_joi31.default.object({
39213
+ _id: import_joi31.default.string().hex().required()
38326
39214
  });
38327
39215
  const { error } = validation.validate({ _id });
38328
39216
  if (error) {
38329
- next(new import_nodejs_utils49.BadRequestError(error.message));
39217
+ next(new import_nodejs_utils53.BadRequestError(error.message));
38330
39218
  return;
38331
39219
  }
38332
39220
  try {
@@ -38351,16 +39239,1692 @@ function useSectionController() {
38351
39239
  };
38352
39240
  }
38353
39241
 
39242
+ // src/resources/building/building.model.ts
39243
+ var import_nodejs_utils54 = require("@eeplatform/nodejs-utils");
39244
+ var import_joi32 = __toESM(require("joi"));
39245
+ var import_mongodb30 = require("mongodb");
39246
+ var schemaBuilding = import_joi32.default.object({
39247
+ _id: import_joi32.default.string().hex().optional(),
39248
+ school: import_joi32.default.string().hex().required(),
39249
+ serial: import_joi32.default.string().optional().allow("", null),
39250
+ name: import_joi32.default.string().required(),
39251
+ levels: import_joi32.default.number().integer().min(1).required(),
39252
+ createdAt: import_joi32.default.date().optional().allow("", null),
39253
+ updatedAt: import_joi32.default.date().optional().allow("", null),
39254
+ deletedAt: import_joi32.default.date().optional().allow("", null),
39255
+ status: import_joi32.default.string().optional().allow("", null)
39256
+ });
39257
+ var schemaBuildingUnit = import_joi32.default.object({
39258
+ _id: import_joi32.default.string().hex().optional(),
39259
+ school: import_joi32.default.string().hex().required(),
39260
+ name: import_joi32.default.string().optional().allow("", null),
39261
+ building: import_joi32.default.string().hex().required(),
39262
+ buildingName: import_joi32.default.string().optional().allow("", null),
39263
+ level: import_joi32.default.number().integer().min(1).required(),
39264
+ category: import_joi32.default.string().required(),
39265
+ type: import_joi32.default.string().required(),
39266
+ seating_capacity: import_joi32.default.number().integer().min(0).required(),
39267
+ standing_capacity: import_joi32.default.number().integer().min(0).required(),
39268
+ description: import_joi32.default.string().optional().allow("", null),
39269
+ unit_of_measurement: import_joi32.default.string().valid("sqm").required(),
39270
+ area: import_joi32.default.number().positive().required(),
39271
+ status: import_joi32.default.string().optional().allow("", null)
39272
+ });
39273
+ var schemaUpdateOptions = import_joi32.default.object({
39274
+ name: import_joi32.default.string().optional().allow("", null),
39275
+ building: import_joi32.default.string().hex().optional().allow("", null),
39276
+ buildingName: import_joi32.default.string().optional().allow("", null),
39277
+ level: import_joi32.default.number().integer().min(1).optional().allow("", null),
39278
+ category: import_joi32.default.string().optional().allow("", null),
39279
+ type: import_joi32.default.string().optional().allow("", null),
39280
+ seating_capacity: import_joi32.default.number().integer().min(0).optional().allow("", null),
39281
+ standing_capacity: import_joi32.default.number().integer().min(0).optional().allow("", null),
39282
+ area: import_joi32.default.number().positive().optional().allow("", null)
39283
+ });
39284
+ function MBuilding(value) {
39285
+ const { error } = schemaBuilding.validate(value);
39286
+ if (error) {
39287
+ import_nodejs_utils54.logger.info(`Building Model: ${error.message}`);
39288
+ throw new import_nodejs_utils54.BadRequestError(error.message);
39289
+ }
39290
+ if (value._id && typeof value._id === "string") {
39291
+ try {
39292
+ value._id = new import_mongodb30.ObjectId(value._id);
39293
+ } catch (error2) {
39294
+ throw new import_nodejs_utils54.BadRequestError("Invalid _id format");
39295
+ }
39296
+ }
39297
+ try {
39298
+ value.school = new import_mongodb30.ObjectId(value.school);
39299
+ } catch (error2) {
39300
+ throw new import_nodejs_utils54.BadRequestError("Invalid school format");
39301
+ }
39302
+ return {
39303
+ _id: value._id ?? void 0,
39304
+ school: value.school,
39305
+ serial: value.serial ?? "",
39306
+ name: value.name ?? "",
39307
+ levels: value.levels ?? 0,
39308
+ status: value.status ?? "active",
39309
+ createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
39310
+ updatedAt: value.updatedAt ?? "",
39311
+ deletedAt: value.deletedAt ?? ""
39312
+ };
39313
+ }
39314
+ function MBuildingUnit(value) {
39315
+ const { error } = schemaBuildingUnit.validate(value);
39316
+ if (error) {
39317
+ import_nodejs_utils54.logger.info(`Building Unit Model: ${error.message}`);
39318
+ throw new import_nodejs_utils54.BadRequestError(error.message);
39319
+ }
39320
+ if (value._id && typeof value._id === "string") {
39321
+ try {
39322
+ value._id = new import_mongodb30.ObjectId(value._id);
39323
+ } catch (error2) {
39324
+ throw new import_nodejs_utils54.BadRequestError("Invalid ID");
39325
+ }
39326
+ }
39327
+ try {
39328
+ value.school = new import_mongodb30.ObjectId(value.school);
39329
+ } catch (error2) {
39330
+ throw new import_nodejs_utils54.BadRequestError("Invalid school ID");
39331
+ }
39332
+ try {
39333
+ value.building = new import_mongodb30.ObjectId(value.building);
39334
+ } catch (error2) {
39335
+ throw new import_nodejs_utils54.BadRequestError("Invalid building ID");
39336
+ }
39337
+ return {
39338
+ _id: value._id ?? void 0,
39339
+ school: value.school,
39340
+ name: value.name ?? "",
39341
+ building: value.building,
39342
+ buildingName: value.buildingName ?? "",
39343
+ level: value.level ?? 0,
39344
+ category: value.category ?? "",
39345
+ type: value.type ?? "",
39346
+ seating_capacity: value.seating_capacity ?? 0,
39347
+ standing_capacity: value.standing_capacity ?? 0,
39348
+ description: value.description ?? "",
39349
+ unit_of_measurement: value.unit_of_measurement ?? "sqm",
39350
+ area: value.area ?? 0,
39351
+ status: value.status ?? "active",
39352
+ createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
39353
+ updatedAt: value.updatedAt ?? "",
39354
+ deletedAt: value.deletedAt ?? ""
39355
+ };
39356
+ }
39357
+
39358
+ // src/resources/building/building.repository.ts
39359
+ var import_nodejs_utils55 = require("@eeplatform/nodejs-utils");
39360
+ var import_mongodb31 = require("mongodb");
39361
+ function useBuildingRepo() {
39362
+ const db = import_nodejs_utils55.useAtlas.getDb();
39363
+ if (!db) {
39364
+ throw new Error("Unable to connect to server.");
39365
+ }
39366
+ const namespace_collection = "school.buildings";
39367
+ const collection = db.collection(namespace_collection);
39368
+ const { getCache, setCache, delNamespace } = (0, import_nodejs_utils55.useCache)(namespace_collection);
39369
+ async function createIndexes() {
39370
+ try {
39371
+ await collection.createIndexes([
39372
+ { key: { name: 1 }, unique: true, name: "unique_name_index" },
39373
+ { key: { school: 1 } },
39374
+ { key: { status: 1 } }
39375
+ ]);
39376
+ } catch (error) {
39377
+ throw new Error("Failed to create index on buildings.");
39378
+ }
39379
+ }
39380
+ async function add(value, session) {
39381
+ try {
39382
+ value = MBuilding(value);
39383
+ const res = await collection.insertOne(value, { session });
39384
+ delCachedData();
39385
+ return res.insertedId;
39386
+ } catch (error) {
39387
+ import_nodejs_utils55.logger.log({
39388
+ level: "error",
39389
+ message: error.message
39390
+ });
39391
+ if (error instanceof import_nodejs_utils55.AppError) {
39392
+ throw error;
39393
+ } else {
39394
+ const isDuplicated = error.message.includes("duplicate");
39395
+ if (isDuplicated) {
39396
+ throw new import_nodejs_utils55.BadRequestError("Building already exists.");
39397
+ }
39398
+ throw new Error("Failed to create building.");
39399
+ }
39400
+ }
39401
+ }
39402
+ async function updateById(_id, value, session) {
39403
+ try {
39404
+ _id = new import_mongodb31.ObjectId(_id);
39405
+ } catch (error) {
39406
+ throw new import_nodejs_utils55.BadRequestError("Invalid ID.");
39407
+ }
39408
+ try {
39409
+ const res = await collection.updateOne(
39410
+ { _id },
39411
+ { $set: value },
39412
+ { session }
39413
+ );
39414
+ delCachedData();
39415
+ return res;
39416
+ } catch (error) {
39417
+ import_nodejs_utils55.logger.log({
39418
+ level: "error",
39419
+ message: error.message
39420
+ });
39421
+ if (error instanceof import_nodejs_utils55.AppError) {
39422
+ throw error;
39423
+ } else {
39424
+ throw new Error("Failed to update building.");
39425
+ }
39426
+ }
39427
+ }
39428
+ async function getAll({
39429
+ search = "",
39430
+ page = 1,
39431
+ limit = 10,
39432
+ sort = {},
39433
+ school = "",
39434
+ status = "active"
39435
+ } = {}) {
39436
+ page = page > 0 ? page - 1 : 0;
39437
+ const query = {
39438
+ status
39439
+ };
39440
+ sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
39441
+ if (search) {
39442
+ query.$text = { $search: search };
39443
+ }
39444
+ if (school) {
39445
+ try {
39446
+ query.school = new import_mongodb31.ObjectId(school);
39447
+ } catch (error) {
39448
+ throw new import_nodejs_utils55.BadRequestError("Invalid school ID.");
39449
+ }
39450
+ }
39451
+ const cacheParams = {
39452
+ page,
39453
+ limit,
39454
+ sort: JSON.stringify(sort)
39455
+ };
39456
+ if (search)
39457
+ cacheParams.search = search;
39458
+ if (school)
39459
+ cacheParams.school = school;
39460
+ if (status !== "active")
39461
+ cacheParams.status = status;
39462
+ const cacheKey = (0, import_nodejs_utils55.makeCacheKey)(namespace_collection, cacheParams);
39463
+ import_nodejs_utils55.logger.log({
39464
+ level: "info",
39465
+ message: `Cache key for getAll buildings: ${cacheKey}`
39466
+ });
39467
+ try {
39468
+ const cached = await getCache(cacheKey);
39469
+ if (cached) {
39470
+ import_nodejs_utils55.logger.log({
39471
+ level: "info",
39472
+ message: `Cache hit for getAll buildings: ${cacheKey}`
39473
+ });
39474
+ return cached;
39475
+ }
39476
+ const items = await collection.aggregate([
39477
+ { $match: query },
39478
+ { $sort: sort },
39479
+ { $skip: page * limit },
39480
+ { $limit: limit }
39481
+ ]).toArray();
39482
+ const length = await collection.countDocuments(query);
39483
+ const data = (0, import_nodejs_utils55.paginate)(items, page, limit, length);
39484
+ setCache(cacheKey, data, 600).then(() => {
39485
+ import_nodejs_utils55.logger.log({
39486
+ level: "info",
39487
+ message: `Cache set for getAll buildings: ${cacheKey}`
39488
+ });
39489
+ }).catch((err) => {
39490
+ import_nodejs_utils55.logger.log({
39491
+ level: "error",
39492
+ message: `Failed to set cache for getAll buildings: ${err.message}`
39493
+ });
39494
+ });
39495
+ return data;
39496
+ } catch (error) {
39497
+ import_nodejs_utils55.logger.log({ level: "error", message: `${error}` });
39498
+ throw error;
39499
+ }
39500
+ }
39501
+ async function getById(_id) {
39502
+ try {
39503
+ _id = new import_mongodb31.ObjectId(_id);
39504
+ } catch (error) {
39505
+ throw new import_nodejs_utils55.BadRequestError("Invalid ID.");
39506
+ }
39507
+ const cacheKey = (0, import_nodejs_utils55.makeCacheKey)(namespace_collection, { _id: String(_id) });
39508
+ try {
39509
+ const cached = await getCache(cacheKey);
39510
+ if (cached) {
39511
+ import_nodejs_utils55.logger.log({
39512
+ level: "info",
39513
+ message: `Cache hit for getById building: ${cacheKey}`
39514
+ });
39515
+ return cached;
39516
+ }
39517
+ const result = await collection.findOne({
39518
+ _id
39519
+ });
39520
+ setCache(cacheKey, result, 300).then(() => {
39521
+ import_nodejs_utils55.logger.log({
39522
+ level: "info",
39523
+ message: `Cache set for building by id: ${cacheKey}`
39524
+ });
39525
+ }).catch((err) => {
39526
+ import_nodejs_utils55.logger.log({
39527
+ level: "error",
39528
+ message: `Failed to set cache for building by id: ${err.message}`
39529
+ });
39530
+ });
39531
+ return result;
39532
+ } catch (error) {
39533
+ if (error instanceof import_nodejs_utils55.AppError) {
39534
+ throw error;
39535
+ } else {
39536
+ throw new import_nodejs_utils55.InternalServerError("Failed to get building.");
39537
+ }
39538
+ }
39539
+ }
39540
+ async function deleteById(_id, session) {
39541
+ try {
39542
+ _id = new import_mongodb31.ObjectId(_id);
39543
+ } catch (error) {
39544
+ throw new import_nodejs_utils55.BadRequestError("Invalid ID.");
39545
+ }
39546
+ try {
39547
+ const res = await collection.updateOne(
39548
+ { _id },
39549
+ { $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
39550
+ );
39551
+ delCachedData();
39552
+ return res;
39553
+ } catch (error) {
39554
+ import_nodejs_utils55.logger.log({
39555
+ level: "error",
39556
+ message: error.message
39557
+ });
39558
+ if (error instanceof import_nodejs_utils55.AppError) {
39559
+ throw error;
39560
+ } else {
39561
+ throw new import_nodejs_utils55.InternalServerError("Failed to delete building.");
39562
+ }
39563
+ }
39564
+ }
39565
+ function delCachedData() {
39566
+ delNamespace().then(() => {
39567
+ import_nodejs_utils55.logger.log({
39568
+ level: "info",
39569
+ message: `Cache namespace cleared for ${namespace_collection}`
39570
+ });
39571
+ }).catch((err) => {
39572
+ import_nodejs_utils55.logger.log({
39573
+ level: "error",
39574
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
39575
+ });
39576
+ });
39577
+ }
39578
+ return {
39579
+ createIndexes,
39580
+ add,
39581
+ getAll,
39582
+ getById,
39583
+ updateById,
39584
+ deleteById
39585
+ };
39586
+ }
39587
+
39588
+ // src/resources/building/building.service.ts
39589
+ var import_nodejs_utils57 = require("@eeplatform/nodejs-utils");
39590
+
39591
+ // src/resources/building/building-unit.repository.ts
39592
+ var import_nodejs_utils56 = require("@eeplatform/nodejs-utils");
39593
+ var import_mongodb32 = require("mongodb");
39594
+ function useBuildingUnitRepo() {
39595
+ const db = import_nodejs_utils56.useAtlas.getDb();
39596
+ if (!db) {
39597
+ throw new Error("Unable to connect to server.");
39598
+ }
39599
+ const namespace_collection = "school.building-units";
39600
+ const collection = db.collection(namespace_collection);
39601
+ const { getCache, setCache, delNamespace } = (0, import_nodejs_utils56.useCache)(namespace_collection);
39602
+ async function createIndexes() {
39603
+ try {
39604
+ await collection.createIndexes([
39605
+ {
39606
+ key: { name: 1, building: 1, level: 1 },
39607
+ unique: true,
39608
+ name: "unique_name_index"
39609
+ },
39610
+ { key: { school: 1 } },
39611
+ { key: { building: 1 } },
39612
+ { key: { status: 1 } },
39613
+ { key: { createdAt: 1 } },
39614
+ {
39615
+ key: {
39616
+ name: "text",
39617
+ buildingName: "text",
39618
+ category: "text",
39619
+ type: "text"
39620
+ }
39621
+ }
39622
+ ]);
39623
+ } catch (error) {
39624
+ throw new Error("Failed to create index on building units.");
39625
+ }
39626
+ }
39627
+ function delCachedData() {
39628
+ delNamespace().then(() => {
39629
+ import_nodejs_utils56.logger.log({
39630
+ level: "info",
39631
+ message: `Cache namespace cleared for ${namespace_collection}`
39632
+ });
39633
+ }).catch((err) => {
39634
+ import_nodejs_utils56.logger.log({
39635
+ level: "error",
39636
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
39637
+ });
39638
+ });
39639
+ }
39640
+ async function add(value, session) {
39641
+ try {
39642
+ value = MBuildingUnit(value);
39643
+ const res = await collection.insertOne(value, { session });
39644
+ delCachedData();
39645
+ return res.insertedId;
39646
+ } catch (error) {
39647
+ import_nodejs_utils56.logger.log({
39648
+ level: "error",
39649
+ message: error.message
39650
+ });
39651
+ if (error instanceof import_nodejs_utils56.AppError) {
39652
+ throw error;
39653
+ } else {
39654
+ throw new Error("Failed to create building unit.");
39655
+ }
39656
+ }
39657
+ }
39658
+ async function updateById(_id, value, session) {
39659
+ const { error } = schemaUpdateOptions.validate(value);
39660
+ if (error) {
39661
+ throw new import_nodejs_utils56.BadRequestError(error.message);
39662
+ }
39663
+ try {
39664
+ _id = new import_mongodb32.ObjectId(_id);
39665
+ } catch (error2) {
39666
+ throw new import_nodejs_utils56.BadRequestError("Invalid ID.");
39667
+ }
39668
+ try {
39669
+ const res = await collection.updateOne(
39670
+ { _id },
39671
+ { $set: value },
39672
+ { session }
39673
+ );
39674
+ delCachedData();
39675
+ return res;
39676
+ } catch (error2) {
39677
+ import_nodejs_utils56.logger.log({
39678
+ level: "error",
39679
+ message: error2.message
39680
+ });
39681
+ if (error2 instanceof import_nodejs_utils56.AppError) {
39682
+ throw error2;
39683
+ } else {
39684
+ throw new Error("Failed to create building unit.");
39685
+ }
39686
+ }
39687
+ }
39688
+ async function updateByBuildingId(building, value, session) {
39689
+ const { error } = schemaUpdateOptions.validate(value);
39690
+ if (error) {
39691
+ throw new import_nodejs_utils56.BadRequestError(error.message);
39692
+ }
39693
+ try {
39694
+ building = new import_mongodb32.ObjectId(building);
39695
+ } catch (error2) {
39696
+ throw new import_nodejs_utils56.BadRequestError("Invalid building ID.");
39697
+ }
39698
+ try {
39699
+ const res = await collection.updateMany(
39700
+ { building },
39701
+ { $set: value },
39702
+ { session }
39703
+ );
39704
+ delCachedData();
39705
+ return res;
39706
+ } catch (error2) {
39707
+ import_nodejs_utils56.logger.log({
39708
+ level: "error",
39709
+ message: error2.message
39710
+ });
39711
+ if (error2 instanceof import_nodejs_utils56.AppError) {
39712
+ throw error2;
39713
+ } else {
39714
+ throw new Error("Failed to update building unit.");
39715
+ }
39716
+ }
39717
+ }
39718
+ async function getAll({
39719
+ search = "",
39720
+ page = 1,
39721
+ limit = 10,
39722
+ sort = {},
39723
+ school = "",
39724
+ building = "",
39725
+ status = "active"
39726
+ } = {}) {
39727
+ page = page > 0 ? page - 1 : 0;
39728
+ const query = {
39729
+ deletedAt: { $in: ["", null] },
39730
+ status: { $in: [status, "", null] }
39731
+ };
39732
+ sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
39733
+ if (search) {
39734
+ query.$text = { $search: search };
39735
+ }
39736
+ if (school) {
39737
+ try {
39738
+ query.school = new import_mongodb32.ObjectId(school);
39739
+ } catch (error) {
39740
+ throw new import_nodejs_utils56.BadRequestError("Invalid school ID.");
39741
+ }
39742
+ }
39743
+ if (building) {
39744
+ try {
39745
+ query.building = new import_mongodb32.ObjectId(building);
39746
+ } catch (error) {
39747
+ throw new import_nodejs_utils56.BadRequestError("Invalid building ID.");
39748
+ }
39749
+ }
39750
+ const cacheParams = {
39751
+ page,
39752
+ limit,
39753
+ sort: JSON.stringify(sort)
39754
+ };
39755
+ if (search)
39756
+ cacheParams.search = search;
39757
+ if (school)
39758
+ cacheParams.school = school;
39759
+ if (building)
39760
+ cacheParams.building = building;
39761
+ if (status !== "active")
39762
+ cacheParams.status = status;
39763
+ const cacheKey = (0, import_nodejs_utils56.makeCacheKey)(namespace_collection, cacheParams);
39764
+ import_nodejs_utils56.logger.log({
39765
+ level: "info",
39766
+ message: `Cache key for getAll building units: ${cacheKey}`
39767
+ });
39768
+ try {
39769
+ const cached = await getCache(cacheKey);
39770
+ if (cached) {
39771
+ import_nodejs_utils56.logger.log({
39772
+ level: "info",
39773
+ message: `Cache hit for getAll building units: ${cacheKey}`
39774
+ });
39775
+ return cached;
39776
+ }
39777
+ const items = await collection.aggregate([
39778
+ { $match: query },
39779
+ { $sort: sort },
39780
+ { $skip: page * limit },
39781
+ { $limit: limit }
39782
+ ]).toArray();
39783
+ const length = await collection.countDocuments(query);
39784
+ const data = (0, import_nodejs_utils56.paginate)(items, page, limit, length);
39785
+ setCache(cacheKey, data, 600).then(() => {
39786
+ import_nodejs_utils56.logger.log({
39787
+ level: "info",
39788
+ message: `Cache set for getAll building units: ${cacheKey}`
39789
+ });
39790
+ }).catch((err) => {
39791
+ import_nodejs_utils56.logger.log({
39792
+ level: "error",
39793
+ message: `Failed to set cache for getAll building units: ${err.message}`
39794
+ });
39795
+ });
39796
+ return data;
39797
+ } catch (error) {
39798
+ import_nodejs_utils56.logger.log({ level: "error", message: `${error}` });
39799
+ throw error;
39800
+ }
39801
+ }
39802
+ async function getById(_id) {
39803
+ try {
39804
+ _id = new import_mongodb32.ObjectId(_id);
39805
+ } catch (error) {
39806
+ throw new import_nodejs_utils56.BadRequestError("Invalid ID.");
39807
+ }
39808
+ const cacheKey = (0, import_nodejs_utils56.makeCacheKey)(namespace_collection, { _id: String(_id) });
39809
+ try {
39810
+ const cached = await getCache(cacheKey);
39811
+ if (cached) {
39812
+ import_nodejs_utils56.logger.log({
39813
+ level: "info",
39814
+ message: `Cache hit for getById building unit: ${cacheKey}`
39815
+ });
39816
+ return cached;
39817
+ }
39818
+ const result = await collection.findOne({
39819
+ _id,
39820
+ deletedAt: { $in: ["", null] }
39821
+ });
39822
+ if (!result) {
39823
+ throw new import_nodejs_utils56.BadRequestError("Building unit not found.");
39824
+ }
39825
+ setCache(cacheKey, result, 300).then(() => {
39826
+ import_nodejs_utils56.logger.log({
39827
+ level: "info",
39828
+ message: `Cache set for building unit by id: ${cacheKey}`
39829
+ });
39830
+ }).catch((err) => {
39831
+ import_nodejs_utils56.logger.log({
39832
+ level: "error",
39833
+ message: `Failed to set cache for building unit by id: ${err.message}`
39834
+ });
39835
+ });
39836
+ return result;
39837
+ } catch (error) {
39838
+ if (error instanceof import_nodejs_utils56.AppError) {
39839
+ throw error;
39840
+ } else {
39841
+ throw new import_nodejs_utils56.InternalServerError("Failed to get building unit.");
39842
+ }
39843
+ }
39844
+ }
39845
+ async function getByBuildingLevel(building, level) {
39846
+ try {
39847
+ building = new import_mongodb32.ObjectId(building);
39848
+ } catch (error) {
39849
+ throw new import_nodejs_utils56.BadRequestError("Invalid building ID.");
39850
+ }
39851
+ const cacheKey = (0, import_nodejs_utils56.makeCacheKey)(namespace_collection, {
39852
+ building: String(building),
39853
+ level
39854
+ });
39855
+ try {
39856
+ const cached = await getCache(cacheKey);
39857
+ if (cached) {
39858
+ import_nodejs_utils56.logger.log({
39859
+ level: "info",
39860
+ message: `Cache hit for getById building unit: ${cacheKey}`
39861
+ });
39862
+ return cached;
39863
+ }
39864
+ const result = await collection.findOne({
39865
+ building,
39866
+ level,
39867
+ status: "active"
39868
+ });
39869
+ setCache(cacheKey, result, 300).then(() => {
39870
+ import_nodejs_utils56.logger.log({
39871
+ level: "info",
39872
+ message: `Cache set for building unit by id: ${cacheKey}`
39873
+ });
39874
+ }).catch((err) => {
39875
+ import_nodejs_utils56.logger.log({
39876
+ level: "error",
39877
+ message: `Failed to set cache for building unit by id: ${err.message}`
39878
+ });
39879
+ });
39880
+ return result;
39881
+ } catch (error) {
39882
+ if (error instanceof import_nodejs_utils56.AppError) {
39883
+ throw error;
39884
+ } else {
39885
+ throw new import_nodejs_utils56.InternalServerError("Failed to get building unit.");
39886
+ }
39887
+ }
39888
+ }
39889
+ async function getByBuilding(building) {
39890
+ try {
39891
+ building = new import_mongodb32.ObjectId(building);
39892
+ } catch (error) {
39893
+ throw new import_nodejs_utils56.BadRequestError("Invalid building ID.");
39894
+ }
39895
+ const cacheKey = (0, import_nodejs_utils56.makeCacheKey)(namespace_collection, {
39896
+ building: String(building)
39897
+ });
39898
+ try {
39899
+ const cached = await getCache(cacheKey);
39900
+ if (cached) {
39901
+ import_nodejs_utils56.logger.log({
39902
+ level: "info",
39903
+ message: `Cache hit for getById building unit: ${cacheKey}`
39904
+ });
39905
+ return cached;
39906
+ }
39907
+ const result = await collection.findOne({
39908
+ building,
39909
+ status: "active"
39910
+ });
39911
+ setCache(cacheKey, result, 300).then(() => {
39912
+ import_nodejs_utils56.logger.log({
39913
+ level: "info",
39914
+ message: `Cache set for building unit by id: ${cacheKey}`
39915
+ });
39916
+ }).catch((err) => {
39917
+ import_nodejs_utils56.logger.log({
39918
+ level: "error",
39919
+ message: `Failed to set cache for building unit by id: ${err.message}`
39920
+ });
39921
+ });
39922
+ return result;
39923
+ } catch (error) {
39924
+ if (error instanceof import_nodejs_utils56.AppError) {
39925
+ throw error;
39926
+ } else {
39927
+ throw new import_nodejs_utils56.InternalServerError("Failed to get building unit.");
39928
+ }
39929
+ }
39930
+ }
39931
+ async function deleteById(_id, session) {
39932
+ try {
39933
+ _id = new import_mongodb32.ObjectId(_id);
39934
+ } catch (error) {
39935
+ throw new import_nodejs_utils56.BadRequestError("Invalid ID.");
39936
+ }
39937
+ try {
39938
+ const res = await collection.updateOne(
39939
+ { _id },
39940
+ { $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } },
39941
+ { session }
39942
+ );
39943
+ delCachedData();
39944
+ return "Room/Facility deleted successfully.";
39945
+ } catch (error) {
39946
+ import_nodejs_utils56.logger.log({
39947
+ level: "error",
39948
+ message: error.message
39949
+ });
39950
+ if (error instanceof import_nodejs_utils56.AppError) {
39951
+ throw error;
39952
+ } else {
39953
+ throw new Error("Failed to deleted room/facility.");
39954
+ }
39955
+ }
39956
+ }
39957
+ return {
39958
+ createIndexes,
39959
+ add,
39960
+ getAll,
39961
+ getById,
39962
+ getByBuildingLevel,
39963
+ updateById,
39964
+ getByBuilding,
39965
+ deleteById,
39966
+ updateByBuildingId
39967
+ };
39968
+ }
39969
+
39970
+ // src/resources/building/building.service.ts
39971
+ function useBuildingService() {
39972
+ const {
39973
+ updateById: _updateById,
39974
+ getById: _getById,
39975
+ deleteById: _deleteById
39976
+ } = useBuildingRepo();
39977
+ const { getByBuildingLevel, getByBuilding, updateByBuildingId } = useBuildingUnitRepo();
39978
+ async function updateById(id, data) {
39979
+ data.levels = Number(data.levels);
39980
+ const session = import_nodejs_utils57.useAtlas.getClient()?.startSession();
39981
+ try {
39982
+ const building = await _getById(id);
39983
+ if (!building) {
39984
+ throw new import_nodejs_utils57.NotFoundError("Building not found.");
39985
+ }
39986
+ if (data.levels < building.levels) {
39987
+ const unit = await getByBuildingLevel(id, building.levels);
39988
+ if (unit) {
39989
+ throw new import_nodejs_utils57.BadRequestError(
39990
+ "Cannot reduce floors, there are existing building units at higher floors."
39991
+ );
39992
+ }
39993
+ }
39994
+ session?.startTransaction();
39995
+ if (building.name !== data.name) {
39996
+ await updateByBuildingId(id, { buildingName: data.name }, session);
39997
+ }
39998
+ const result = await _updateById(id, data, session);
39999
+ await session?.commitTransaction();
40000
+ return result;
40001
+ } catch (error) {
40002
+ await session?.abortTransaction();
40003
+ throw error;
40004
+ } finally {
40005
+ session?.endSession();
40006
+ }
40007
+ }
40008
+ async function deleteById(id) {
40009
+ const building = await getByBuilding(id);
40010
+ if (building) {
40011
+ throw new import_nodejs_utils57.BadRequestError(
40012
+ "Cannot delete building with existing room/facility. Please delete room/facility first."
40013
+ );
40014
+ }
40015
+ try {
40016
+ await _deleteById(id);
40017
+ return "Building deleted successfully.";
40018
+ } catch (error) {
40019
+ throw error;
40020
+ }
40021
+ }
40022
+ return {
40023
+ updateById,
40024
+ deleteById
40025
+ };
40026
+ }
40027
+
40028
+ // src/resources/building/building.controller.ts
40029
+ var import_nodejs_utils58 = require("@eeplatform/nodejs-utils");
40030
+ var import_joi33 = __toESM(require("joi"));
40031
+ function useBuildingController() {
40032
+ const { getAll: _getAll, getById: _getById, add: _add } = useBuildingRepo();
40033
+ const { updateById: _updateById, deleteById: _deleteById } = useBuildingService();
40034
+ async function createBuilding(req, res, next) {
40035
+ const value = req.body;
40036
+ const validation = import_joi33.default.object({
40037
+ name: import_joi33.default.string().required(),
40038
+ school: import_joi33.default.string().hex().required(),
40039
+ levels: import_joi33.default.number().integer().min(1).required(),
40040
+ serial: import_joi33.default.string().optional().allow("", null),
40041
+ status: import_joi33.default.string().optional().allow("", null)
40042
+ });
40043
+ const { error } = validation.validate(value);
40044
+ if (error) {
40045
+ next(new import_nodejs_utils58.BadRequestError(error.message));
40046
+ import_nodejs_utils58.logger.info(`Controller: ${error.message}`);
40047
+ return;
40048
+ }
40049
+ try {
40050
+ const result = await _add(value);
40051
+ res.json(result);
40052
+ return;
40053
+ } catch (error2) {
40054
+ next(error2);
40055
+ }
40056
+ }
40057
+ async function updateById(req, res, next) {
40058
+ const value = req.body;
40059
+ const id = req.params.id ?? "";
40060
+ const validation = import_joi33.default.object({
40061
+ id: import_joi33.default.string().hex().required(),
40062
+ value: import_joi33.default.object({
40063
+ name: import_joi33.default.string().required(),
40064
+ serial: import_joi33.default.string().optional().allow("", null),
40065
+ levels: import_joi33.default.number().integer().min(1).required()
40066
+ })
40067
+ });
40068
+ const { error } = validation.validate({ id, value });
40069
+ if (error) {
40070
+ next(new import_nodejs_utils58.BadRequestError(error.message));
40071
+ import_nodejs_utils58.logger.info(`Controller: ${error.message}`);
40072
+ return;
40073
+ }
40074
+ try {
40075
+ const result = await _updateById(id, value);
40076
+ res.json(result);
40077
+ return;
40078
+ } catch (error2) {
40079
+ next(error2);
40080
+ }
40081
+ }
40082
+ async function getAll(req, res, next) {
40083
+ const query = req.query;
40084
+ const validation = import_joi33.default.object({
40085
+ page: import_joi33.default.number().min(1).optional().allow("", null),
40086
+ limit: import_joi33.default.number().min(1).optional().allow("", null),
40087
+ search: import_joi33.default.string().optional().allow("", null),
40088
+ school: import_joi33.default.string().hex().optional().allow("", null),
40089
+ status: import_joi33.default.string().optional().allow("", null)
40090
+ });
40091
+ const { error } = validation.validate(query);
40092
+ if (error) {
40093
+ next(new import_nodejs_utils58.BadRequestError(error.message));
40094
+ return;
40095
+ }
40096
+ const page = parseInt(req.query.page) ?? 1;
40097
+ let limit = parseInt(req.query.limit) ?? 20;
40098
+ limit = isNaN(limit) ? 20 : limit;
40099
+ const sort = req.query.sort ? String(req.query.sort).split(",") : "";
40100
+ const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
40101
+ const sortObj = {};
40102
+ if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
40103
+ sort.forEach((field, index) => {
40104
+ sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
40105
+ });
40106
+ }
40107
+ const status = req.query.status ?? "active";
40108
+ const school = req.query.school ?? "";
40109
+ const search = req.query.search ?? "";
40110
+ try {
40111
+ const buildings = await _getAll({
40112
+ page,
40113
+ limit,
40114
+ sort: sortObj,
40115
+ status,
40116
+ school,
40117
+ search
40118
+ });
40119
+ res.json(buildings);
40120
+ return;
40121
+ } catch (error2) {
40122
+ next(error2);
40123
+ }
40124
+ }
40125
+ async function getById(req, res, next) {
40126
+ const id = req.params.id;
40127
+ const validation = import_joi33.default.object({
40128
+ id: import_joi33.default.string().hex().required()
40129
+ });
40130
+ const { error } = validation.validate({ id });
40131
+ if (error) {
40132
+ next(new import_nodejs_utils58.BadRequestError(error.message));
40133
+ return;
40134
+ }
40135
+ try {
40136
+ const building = await _getById(id);
40137
+ res.json({
40138
+ message: "Successfully retrieved building.",
40139
+ data: { building }
40140
+ });
40141
+ return;
40142
+ } catch (error2) {
40143
+ next(error2);
40144
+ }
40145
+ }
40146
+ async function deleteById(req, res, next) {
40147
+ const id = req.params.id;
40148
+ const validation = import_joi33.default.object({
40149
+ id: import_joi33.default.string().hex().required()
40150
+ });
40151
+ const { error } = validation.validate({ id });
40152
+ if (error) {
40153
+ next(new import_nodejs_utils58.BadRequestError(error.message));
40154
+ return;
40155
+ }
40156
+ try {
40157
+ const message = await _deleteById(id);
40158
+ res.json(message);
40159
+ return;
40160
+ } catch (error2) {
40161
+ next(error2);
40162
+ }
40163
+ }
40164
+ return {
40165
+ createBuilding,
40166
+ getAll,
40167
+ getById,
40168
+ updateById,
40169
+ deleteById
40170
+ };
40171
+ }
40172
+
40173
+ // src/resources/building/building-unit.service.ts
40174
+ var import_nodejs_utils59 = require("@eeplatform/nodejs-utils");
40175
+ function useBuildingUnitService() {
40176
+ const { add: _add } = useBuildingUnitRepo();
40177
+ async function add(value) {
40178
+ const session = import_nodejs_utils59.useAtlas.getClient()?.startSession();
40179
+ if (!session) {
40180
+ throw new Error("Unable to start session for building unit service.");
40181
+ }
40182
+ try {
40183
+ await session.startTransaction();
40184
+ for (let index = 0; index < value.qty; index++) {
40185
+ await _add(
40186
+ { ...value.building, name: `${value.building.name} ${index + 1}` },
40187
+ session
40188
+ );
40189
+ }
40190
+ await session.commitTransaction();
40191
+ return "Building unit added successfully.";
40192
+ } catch (error) {
40193
+ await session.abortTransaction();
40194
+ throw error;
40195
+ } finally {
40196
+ session.endSession();
40197
+ }
40198
+ }
40199
+ return {
40200
+ add
40201
+ };
40202
+ }
40203
+
40204
+ // src/resources/building/building-unit.controller.ts
40205
+ var import_nodejs_utils60 = require("@eeplatform/nodejs-utils");
40206
+ var import_joi34 = __toESM(require("joi"));
40207
+ function useBuildingUnitController() {
40208
+ const {
40209
+ getAll: _getAll,
40210
+ getById: _getById,
40211
+ updateById: _updateById,
40212
+ deleteById: _deleteById
40213
+ } = useBuildingUnitRepo();
40214
+ const { add: _add } = useBuildingUnitService();
40215
+ async function add(req, res, next) {
40216
+ const data = req.body;
40217
+ const validation = import_joi34.default.object({
40218
+ building: import_joi34.default.object({
40219
+ school: import_joi34.default.string().hex().required(),
40220
+ name: import_joi34.default.string().optional().allow("", null),
40221
+ building: import_joi34.default.string().hex().required(),
40222
+ buildingName: import_joi34.default.string().optional().allow("", null),
40223
+ level: import_joi34.default.number().integer().min(1).required(),
40224
+ category: import_joi34.default.string().required(),
40225
+ type: import_joi34.default.string().required(),
40226
+ seating_capacity: import_joi34.default.number().integer().min(0).required(),
40227
+ standing_capacity: import_joi34.default.number().integer().min(0).required(),
40228
+ description: import_joi34.default.string().optional().allow("", null),
40229
+ unit_of_measurement: import_joi34.default.string().valid("sqm").required(),
40230
+ area: import_joi34.default.number().positive().required(),
40231
+ status: import_joi34.default.string().optional().allow("", null)
40232
+ }),
40233
+ qty: import_joi34.default.number().integer().min(1).max(20).optional().default(1)
40234
+ });
40235
+ const { error } = validation.validate(data);
40236
+ if (error) {
40237
+ next(new import_nodejs_utils60.BadRequestError(error.message));
40238
+ return;
40239
+ }
40240
+ try {
40241
+ const buildingUnit = await _add(data);
40242
+ res.json({
40243
+ message: "Building unit added successfully.",
40244
+ data: { buildingUnit }
40245
+ });
40246
+ } catch (error2) {
40247
+ next(error2);
40248
+ }
40249
+ }
40250
+ async function updateById(req, res, next) {
40251
+ const data = req.body;
40252
+ const id = req.params.id ?? "";
40253
+ const validation = import_joi34.default.object({
40254
+ id: import_joi34.default.string().hex().required(),
40255
+ value: schemaUpdateOptions
40256
+ });
40257
+ const { error } = validation.validate({ id, value: data });
40258
+ if (error) {
40259
+ next(new import_nodejs_utils60.BadRequestError(error.message));
40260
+ return;
40261
+ }
40262
+ try {
40263
+ const buildingUnit = await _updateById(id, data);
40264
+ res.json({
40265
+ message: "Building unit updated successfully.",
40266
+ data: { buildingUnit }
40267
+ });
40268
+ } catch (error2) {
40269
+ next(error2);
40270
+ }
40271
+ }
40272
+ async function getAll(req, res, next) {
40273
+ const query = req.query;
40274
+ const validation = import_joi34.default.object({
40275
+ page: import_joi34.default.number().min(1).optional().allow("", null),
40276
+ limit: import_joi34.default.number().min(1).optional().allow("", null),
40277
+ search: import_joi34.default.string().optional().allow("", null),
40278
+ school: import_joi34.default.string().hex().optional().allow("", null),
40279
+ building: import_joi34.default.string().hex().optional().allow("", null),
40280
+ status: import_joi34.default.string().optional().allow("", null)
40281
+ });
40282
+ const { error } = validation.validate(query);
40283
+ if (error) {
40284
+ next(new import_nodejs_utils60.BadRequestError(error.message));
40285
+ return;
40286
+ }
40287
+ const page = parseInt(req.query.page) ?? 1;
40288
+ let limit = parseInt(req.query.limit) ?? 20;
40289
+ limit = isNaN(limit) ? 20 : limit;
40290
+ const sort = req.query.sort ? String(req.query.sort).split(",") : "";
40291
+ const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
40292
+ const sortObj = {};
40293
+ if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
40294
+ sort.forEach((field, index) => {
40295
+ sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
40296
+ });
40297
+ }
40298
+ const status = req.query.status ?? "active";
40299
+ const school = req.query.school ?? "";
40300
+ const building = req.query.building ?? "";
40301
+ const search = req.query.search ?? "";
40302
+ try {
40303
+ const buildings = await _getAll({
40304
+ page,
40305
+ limit,
40306
+ sort: sortObj,
40307
+ status,
40308
+ school,
40309
+ search,
40310
+ building
40311
+ });
40312
+ res.json(buildings);
40313
+ return;
40314
+ } catch (error2) {
40315
+ next(error2);
40316
+ }
40317
+ }
40318
+ async function getById(req, res, next) {
40319
+ const id = req.params.id;
40320
+ const validation = import_joi34.default.object({
40321
+ id: import_joi34.default.string().hex().required()
40322
+ });
40323
+ const { error } = validation.validate({ id });
40324
+ if (error) {
40325
+ next(new import_nodejs_utils60.BadRequestError(error.message));
40326
+ return;
40327
+ }
40328
+ try {
40329
+ const buildingUnit = await _getById(id);
40330
+ res.json({
40331
+ message: "Successfully retrieved building unit.",
40332
+ data: { buildingUnit }
40333
+ });
40334
+ return;
40335
+ } catch (error2) {
40336
+ next(error2);
40337
+ }
40338
+ }
40339
+ async function deleteById(req, res, next) {
40340
+ const id = req.params.id;
40341
+ const validation = import_joi34.default.object({
40342
+ id: import_joi34.default.string().hex().required()
40343
+ });
40344
+ const { error } = validation.validate({ id });
40345
+ if (error) {
40346
+ next(new import_nodejs_utils60.BadRequestError(error.message));
40347
+ return;
40348
+ }
40349
+ try {
40350
+ const message = await _deleteById(id);
40351
+ res.json({ message });
40352
+ return;
40353
+ } catch (error2) {
40354
+ next(error2);
40355
+ }
40356
+ }
40357
+ return {
40358
+ add,
40359
+ getAll,
40360
+ getById,
40361
+ updateById,
40362
+ deleteById
40363
+ };
40364
+ }
40365
+
40366
+ // src/resources/personnel/personnel.model.ts
40367
+ var import_nodejs_utils61 = require("@eeplatform/nodejs-utils");
40368
+ var import_joi35 = __toESM(require("joi"));
40369
+ var import_mongodb33 = require("mongodb");
40370
+ var schemaPersonnel = import_joi35.default.object({
40371
+ _id: import_joi35.default.string().hex().optional().allow("", null),
40372
+ school: import_joi35.default.string().hex().required(),
40373
+ schoolName: import_joi35.default.string().optional().allow("", null),
40374
+ firstName: import_joi35.default.string().required(),
40375
+ lastName: import_joi35.default.string().required(),
40376
+ middleName: import_joi35.default.string().optional().allow("", null),
40377
+ suffix: import_joi35.default.string().optional().allow("", null),
40378
+ title: import_joi35.default.string().optional().allow("", null),
40379
+ classification: import_joi35.default.string().required(),
40380
+ status: import_joi35.default.string().optional().allow("", null),
40381
+ createdAt: import_joi35.default.date().optional().allow("", null),
40382
+ updatedAt: import_joi35.default.date().optional().allow("", null),
40383
+ deletedAt: import_joi35.default.date().optional().allow("", null)
40384
+ });
40385
+ function MPersonnel(value) {
40386
+ const { error } = schemaPersonnel.validate(value);
40387
+ if (error) {
40388
+ import_nodejs_utils61.logger.info(`Personnel Model: ${error.message}`);
40389
+ throw new import_nodejs_utils61.BadRequestError(error.message);
40390
+ }
40391
+ if (value._id && typeof value._id === "string") {
40392
+ try {
40393
+ value._id = new import_mongodb33.ObjectId(value._id);
40394
+ } catch (error2) {
40395
+ throw new import_nodejs_utils61.BadRequestError("Invalid _id format");
40396
+ }
40397
+ }
40398
+ if (value.school && typeof value.school === "string") {
40399
+ try {
40400
+ value.school = new import_mongodb33.ObjectId(value.school);
40401
+ } catch (error2) {
40402
+ throw new import_nodejs_utils61.BadRequestError("Invalid school format");
40403
+ }
40404
+ }
40405
+ if (!value.status) {
40406
+ value.status = "active";
40407
+ }
40408
+ return {
40409
+ _id: value._id,
40410
+ school: value.school,
40411
+ schoolName: value.schoolName ?? "",
40412
+ firstName: value.firstName ?? "",
40413
+ lastName: value.lastName ?? "",
40414
+ middleName: value.middleName ?? "",
40415
+ suffix: value.suffix ?? "",
40416
+ title: value.title ?? "",
40417
+ classification: value.classification ?? "",
40418
+ status: value.status,
40419
+ createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
40420
+ updatedAt: value.updatedAt ?? "",
40421
+ deletedAt: value.deletedAt ?? ""
40422
+ };
40423
+ }
40424
+
40425
+ // src/resources/personnel/personnel.repository.ts
40426
+ var import_nodejs_utils62 = require("@eeplatform/nodejs-utils");
40427
+ var import_mongodb34 = require("mongodb");
40428
+ function usePersonnelRepo() {
40429
+ const db = import_nodejs_utils62.useAtlas.getDb();
40430
+ if (!db) {
40431
+ throw new Error("Unable to connect to server.");
40432
+ }
40433
+ const namespace_collection = "deped.school.personnel";
40434
+ const collection = db.collection(namespace_collection);
40435
+ const { getCache, setCache, delNamespace } = (0, import_nodejs_utils62.useCache)(namespace_collection);
40436
+ async function createIndexes() {
40437
+ try {
40438
+ await collection.createIndexes([
40439
+ {
40440
+ key: {
40441
+ firstName: 1,
40442
+ lastName: 1,
40443
+ classification: 1,
40444
+ status: 1
40445
+ },
40446
+ name: "personnel_search_index"
40447
+ },
40448
+ { key: { status: 1 } },
40449
+ { key: { classification: 1 } },
40450
+ { key: { firstName: "text", lastName: "text", middleName: "text" } }
40451
+ ]);
40452
+ } catch (error) {
40453
+ throw new Error("Failed to create index on personnel.");
40454
+ }
40455
+ }
40456
+ async function add(value, session) {
40457
+ try {
40458
+ value = MPersonnel(value);
40459
+ await collection.insertOne(value, { session });
40460
+ delCachedData();
40461
+ return "Successfully added personnel.";
40462
+ } catch (error) {
40463
+ import_nodejs_utils62.logger.log({
40464
+ level: "error",
40465
+ message: error.message
40466
+ });
40467
+ if (error instanceof import_nodejs_utils62.AppError) {
40468
+ throw error;
40469
+ } else {
40470
+ throw new Error("Failed to create personnel.");
40471
+ }
40472
+ }
40473
+ }
40474
+ async function updateById(_id, value, session) {
40475
+ try {
40476
+ _id = new import_mongodb34.ObjectId(_id);
40477
+ } catch (error) {
40478
+ throw new import_nodejs_utils62.BadRequestError("Invalid ID.");
40479
+ }
40480
+ try {
40481
+ const res = await collection.updateOne(
40482
+ { _id },
40483
+ { $set: { ...value, updatedAt: /* @__PURE__ */ new Date() } },
40484
+ { session }
40485
+ );
40486
+ delCachedData();
40487
+ return res;
40488
+ } catch (error) {
40489
+ import_nodejs_utils62.logger.log({
40490
+ level: "error",
40491
+ message: error.message
40492
+ });
40493
+ if (error instanceof import_nodejs_utils62.AppError) {
40494
+ throw error;
40495
+ } else {
40496
+ throw new Error("Failed to update personnel.");
40497
+ }
40498
+ }
40499
+ }
40500
+ async function getAll({
40501
+ school = "",
40502
+ search = "",
40503
+ page = 1,
40504
+ limit = 10,
40505
+ sort = {},
40506
+ status = "active"
40507
+ } = {}) {
40508
+ page = page > 0 ? page - 1 : 0;
40509
+ const query = {
40510
+ status
40511
+ };
40512
+ const cacheParams = {
40513
+ page,
40514
+ limit,
40515
+ sort: JSON.stringify(sort)
40516
+ };
40517
+ sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
40518
+ if (search) {
40519
+ query.$text = { $search: search };
40520
+ cacheParams.search = search;
40521
+ }
40522
+ if (school) {
40523
+ try {
40524
+ query.school = new import_mongodb34.ObjectId(school);
40525
+ } catch (error) {
40526
+ throw new import_nodejs_utils62.BadRequestError("Invalid school ID.");
40527
+ }
40528
+ cacheParams.school = school;
40529
+ }
40530
+ const cacheKey = (0, import_nodejs_utils62.makeCacheKey)(namespace_collection, cacheParams);
40531
+ import_nodejs_utils62.logger.log({
40532
+ level: "info",
40533
+ message: `Cache key for getAll personnel: ${cacheKey}`
40534
+ });
40535
+ try {
40536
+ const cached = await getCache(cacheKey);
40537
+ if (cached) {
40538
+ import_nodejs_utils62.logger.log({
40539
+ level: "info",
40540
+ message: `Cache hit for getAll personnel: ${cacheKey}`
40541
+ });
40542
+ return cached;
40543
+ }
40544
+ const items = await collection.aggregate([
40545
+ { $match: query },
40546
+ { $sort: sort },
40547
+ { $skip: page * limit },
40548
+ { $limit: limit }
40549
+ ]).toArray();
40550
+ const length = await collection.countDocuments(query);
40551
+ const data = (0, import_nodejs_utils62.paginate)(items, page, limit, length);
40552
+ setCache(cacheKey, data, 600).then(() => {
40553
+ import_nodejs_utils62.logger.log({
40554
+ level: "info",
40555
+ message: `Cache set for getAll personnel: ${cacheKey}`
40556
+ });
40557
+ }).catch((err) => {
40558
+ import_nodejs_utils62.logger.log({
40559
+ level: "error",
40560
+ message: `Failed to set cache for getAll personnel: ${err.message}`
40561
+ });
40562
+ });
40563
+ return data;
40564
+ } catch (error) {
40565
+ import_nodejs_utils62.logger.log({ level: "error", message: `${error}` });
40566
+ throw error;
40567
+ }
40568
+ }
40569
+ async function getById(_id) {
40570
+ try {
40571
+ _id = new import_mongodb34.ObjectId(_id);
40572
+ } catch (error) {
40573
+ throw new import_nodejs_utils62.BadRequestError("Invalid ID.");
40574
+ }
40575
+ const cacheKey = (0, import_nodejs_utils62.makeCacheKey)(namespace_collection, { _id: String(_id) });
40576
+ try {
40577
+ const cached = await getCache(cacheKey);
40578
+ if (cached) {
40579
+ import_nodejs_utils62.logger.log({
40580
+ level: "info",
40581
+ message: `Cache hit for getById personnel: ${cacheKey}`
40582
+ });
40583
+ return cached;
40584
+ }
40585
+ const result = await collection.findOne({
40586
+ _id
40587
+ });
40588
+ setCache(cacheKey, result, 300).then(() => {
40589
+ import_nodejs_utils62.logger.log({
40590
+ level: "info",
40591
+ message: `Cache set for personnel by id: ${cacheKey}`
40592
+ });
40593
+ }).catch((err) => {
40594
+ import_nodejs_utils62.logger.log({
40595
+ level: "error",
40596
+ message: `Failed to set cache for personnel by id: ${err.message}`
40597
+ });
40598
+ });
40599
+ return result;
40600
+ } catch (error) {
40601
+ if (error instanceof import_nodejs_utils62.AppError) {
40602
+ throw error;
40603
+ } else {
40604
+ throw new import_nodejs_utils62.InternalServerError("Failed to get personnel.");
40605
+ }
40606
+ }
40607
+ }
40608
+ async function deleteById(_id, session) {
40609
+ try {
40610
+ _id = new import_mongodb34.ObjectId(_id);
40611
+ } catch (error) {
40612
+ throw new import_nodejs_utils62.BadRequestError("Invalid ID.");
40613
+ }
40614
+ try {
40615
+ const res = await collection.updateOne(
40616
+ { _id },
40617
+ { $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
40618
+ );
40619
+ delCachedData();
40620
+ return res;
40621
+ } catch (error) {
40622
+ import_nodejs_utils62.logger.log({
40623
+ level: "error",
40624
+ message: error.message
40625
+ });
40626
+ if (error instanceof import_nodejs_utils62.AppError) {
40627
+ throw error;
40628
+ } else {
40629
+ throw new import_nodejs_utils62.InternalServerError("Failed to delete personnel.");
40630
+ }
40631
+ }
40632
+ }
40633
+ async function getByClassification(classification) {
40634
+ const query = {
40635
+ classification,
40636
+ status: "active"
40637
+ };
40638
+ const cacheKey = (0, import_nodejs_utils62.makeCacheKey)(namespace_collection, { classification });
40639
+ try {
40640
+ const cached = await getCache(cacheKey);
40641
+ if (cached) {
40642
+ import_nodejs_utils62.logger.log({
40643
+ level: "info",
40644
+ message: `Cache hit for getByClassification personnel: ${cacheKey}`
40645
+ });
40646
+ return cached;
40647
+ }
40648
+ const result = await collection.find(query).toArray();
40649
+ setCache(cacheKey, result, 300).then(() => {
40650
+ import_nodejs_utils62.logger.log({
40651
+ level: "info",
40652
+ message: `Cache set for personnel by classification: ${cacheKey}`
40653
+ });
40654
+ }).catch((err) => {
40655
+ import_nodejs_utils62.logger.log({
40656
+ level: "error",
40657
+ message: `Failed to set cache for personnel by classification: ${err.message}`
40658
+ });
40659
+ });
40660
+ return result;
40661
+ } catch (error) {
40662
+ if (error instanceof import_nodejs_utils62.AppError) {
40663
+ throw error;
40664
+ } else {
40665
+ throw new import_nodejs_utils62.InternalServerError(
40666
+ "Failed to get personnel by classification."
40667
+ );
40668
+ }
40669
+ }
40670
+ }
40671
+ function delCachedData() {
40672
+ delNamespace().then(() => {
40673
+ import_nodejs_utils62.logger.log({
40674
+ level: "info",
40675
+ message: `Cache cleared for namespace: ${namespace_collection}`
40676
+ });
40677
+ }).catch((err) => {
40678
+ import_nodejs_utils62.logger.log({
40679
+ level: "error",
40680
+ message: `Failed to clear cache for namespace: ${namespace_collection}: ${err.message}`
40681
+ });
40682
+ });
40683
+ }
40684
+ return {
40685
+ createIndexes,
40686
+ add,
40687
+ updateById,
40688
+ getAll,
40689
+ getById,
40690
+ deleteById,
40691
+ getByClassification,
40692
+ delCachedData
40693
+ };
40694
+ }
40695
+
40696
+ // src/resources/personnel/personnel.controller.ts
40697
+ var import_nodejs_utils63 = require("@eeplatform/nodejs-utils");
40698
+ var import_joi36 = __toESM(require("joi"));
40699
+ function usePersonnelController() {
40700
+ const {
40701
+ getAll: _getAll,
40702
+ getById: _getById,
40703
+ add: _add,
40704
+ updateById: _updateById,
40705
+ deleteById: _deleteById,
40706
+ getByClassification: _getByClassification
40707
+ } = usePersonnelRepo();
40708
+ async function add(req, res, next) {
40709
+ const value = req.body;
40710
+ const { error } = schemaPersonnel.validate(value);
40711
+ if (error) {
40712
+ next(new import_nodejs_utils63.BadRequestError(error.message));
40713
+ import_nodejs_utils63.logger.info(`Controller: ${error.message}`);
40714
+ return;
40715
+ }
40716
+ try {
40717
+ const result = await _add(value);
40718
+ res.json(result);
40719
+ return;
40720
+ } catch (error2) {
40721
+ next(error2);
40722
+ }
40723
+ }
40724
+ async function updateById(req, res, next) {
40725
+ const value = req.body;
40726
+ const id = req.params.id ?? "";
40727
+ const validation = import_joi36.default.object({
40728
+ id: import_joi36.default.string().hex().required(),
40729
+ value: import_joi36.default.object({
40730
+ firstName: import_joi36.default.string().optional(),
40731
+ lastName: import_joi36.default.string().optional(),
40732
+ middleName: import_joi36.default.string().optional().allow("", null),
40733
+ classification: import_joi36.default.string().optional(),
40734
+ status: import_joi36.default.string().optional()
40735
+ }).min(1)
40736
+ });
40737
+ const { error } = validation.validate({ id, value });
40738
+ if (error) {
40739
+ next(new import_nodejs_utils63.BadRequestError(error.message));
40740
+ import_nodejs_utils63.logger.info(`Controller: ${error.message}`);
40741
+ return;
40742
+ }
40743
+ try {
40744
+ const result = await _updateById(id, value);
40745
+ res.json(result);
40746
+ return;
40747
+ } catch (error2) {
40748
+ next(error2);
40749
+ }
40750
+ }
40751
+ async function getAll(req, res, next) {
40752
+ const query = req.query;
40753
+ const validation = import_joi36.default.object({
40754
+ page: import_joi36.default.number().min(1).optional().allow("", null),
40755
+ limit: import_joi36.default.number().min(1).optional().allow("", null),
40756
+ search: import_joi36.default.string().optional().allow("", null),
40757
+ status: import_joi36.default.string().optional().allow("", null),
40758
+ classification: import_joi36.default.string().optional().allow("", null)
40759
+ });
40760
+ const { error } = validation.validate(query);
40761
+ if (error) {
40762
+ next(new import_nodejs_utils63.BadRequestError(error.message));
40763
+ return;
40764
+ }
40765
+ const page = parseInt(req.query.page) ?? 1;
40766
+ let limit = parseInt(req.query.limit) ?? 20;
40767
+ limit = isNaN(limit) ? 20 : limit;
40768
+ const sort = req.query.sort ? String(req.query.sort).split(",") : "";
40769
+ const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
40770
+ const sortObj = {};
40771
+ if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
40772
+ sort.forEach((field, index) => {
40773
+ sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
40774
+ });
40775
+ }
40776
+ const status = req.query.status ?? "active";
40777
+ const search = req.query.search ?? "";
40778
+ try {
40779
+ const personnel = await _getAll({
40780
+ page,
40781
+ limit,
40782
+ sort: sortObj,
40783
+ status,
40784
+ search
40785
+ });
40786
+ res.json(personnel);
40787
+ return;
40788
+ } catch (error2) {
40789
+ next(error2);
40790
+ }
40791
+ }
40792
+ async function getAllBySchool(req, res, next) {
40793
+ const school = req.params.school;
40794
+ const schoolValidation = import_joi36.default.string().hex().required();
40795
+ const { error: schoolError } = schoolValidation.validate(school);
40796
+ if (schoolError) {
40797
+ next(new import_nodejs_utils63.BadRequestError(schoolError.message));
40798
+ return;
40799
+ }
40800
+ const query = req.query;
40801
+ const validation = import_joi36.default.object({
40802
+ page: import_joi36.default.number().min(1).optional().allow("", null),
40803
+ limit: import_joi36.default.number().min(1).optional().allow("", null),
40804
+ search: import_joi36.default.string().optional().allow("", null),
40805
+ status: import_joi36.default.string().optional().allow("", null),
40806
+ classification: import_joi36.default.string().optional().allow("", null)
40807
+ });
40808
+ const { error } = validation.validate(query);
40809
+ if (error) {
40810
+ next(new import_nodejs_utils63.BadRequestError(error.message));
40811
+ return;
40812
+ }
40813
+ const page = parseInt(req.query.page) ?? 1;
40814
+ let limit = parseInt(req.query.limit) ?? 20;
40815
+ limit = isNaN(limit) ? 20 : limit;
40816
+ const sort = req.query.sort ? String(req.query.sort).split(",") : "";
40817
+ const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
40818
+ const sortObj = {};
40819
+ if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
40820
+ sort.forEach((field, index) => {
40821
+ sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
40822
+ });
40823
+ }
40824
+ const status = req.query.status ?? "active";
40825
+ const search = req.query.search ?? "";
40826
+ try {
40827
+ const personnel = await _getAll({
40828
+ school,
40829
+ page,
40830
+ limit,
40831
+ sort: sortObj,
40832
+ status,
40833
+ search
40834
+ });
40835
+ res.json(personnel);
40836
+ return;
40837
+ } catch (error2) {
40838
+ next(error2);
40839
+ }
40840
+ }
40841
+ async function getById(req, res, next) {
40842
+ const id = req.params.id;
40843
+ const validation = import_joi36.default.object({
40844
+ id: import_joi36.default.string().hex().required()
40845
+ });
40846
+ const { error } = validation.validate({ id });
40847
+ if (error) {
40848
+ next(new import_nodejs_utils63.BadRequestError(error.message));
40849
+ return;
40850
+ }
40851
+ try {
40852
+ const personnel = await _getById(id);
40853
+ res.json({
40854
+ message: "Successfully retrieved personnel.",
40855
+ data: personnel
40856
+ });
40857
+ return;
40858
+ } catch (error2) {
40859
+ next(error2);
40860
+ }
40861
+ }
40862
+ async function deleteById(req, res, next) {
40863
+ const id = req.params.id;
40864
+ const validation = import_joi36.default.object({
40865
+ id: import_joi36.default.string().hex().required()
40866
+ });
40867
+ const { error } = validation.validate({ id });
40868
+ if (error) {
40869
+ next(new import_nodejs_utils63.BadRequestError(error.message));
40870
+ return;
40871
+ }
40872
+ try {
40873
+ const result = await _deleteById(id);
40874
+ res.json({
40875
+ message: "Successfully deleted personnel.",
40876
+ data: result
40877
+ });
40878
+ return;
40879
+ } catch (error2) {
40880
+ next(error2);
40881
+ }
40882
+ }
40883
+ async function getByClassification(req, res, next) {
40884
+ const classification = req.params.classification;
40885
+ const validation = import_joi36.default.object({
40886
+ classification: import_joi36.default.string().required()
40887
+ });
40888
+ const { error } = validation.validate({ classification });
40889
+ if (error) {
40890
+ next(new import_nodejs_utils63.BadRequestError(error.message));
40891
+ return;
40892
+ }
40893
+ try {
40894
+ const personnel = await _getByClassification(classification);
40895
+ res.json({
40896
+ message: "Successfully retrieved personnel by classification.",
40897
+ data: personnel
40898
+ });
40899
+ return;
40900
+ } catch (error2) {
40901
+ next(error2);
40902
+ }
40903
+ }
40904
+ return {
40905
+ add,
40906
+ updateById,
40907
+ getAll,
40908
+ getAllBySchool,
40909
+ getById,
40910
+ deleteById,
40911
+ getByClassification
40912
+ };
40913
+ }
40914
+
38354
40915
  // src/config.ts
38355
40916
  var dotenv = __toESM(require("dotenv"));
38356
40917
  dotenv.config();
38357
40918
  // Annotate the CommonJS export names for ESM import in node:
38358
40919
  0 && (module.exports = {
38359
40920
  MAsset,
40921
+ MBuilding,
40922
+ MBuildingUnit,
38360
40923
  MCurriculum,
38361
40924
  MCurriculumSubject,
38362
40925
  MGradeLevel,
38363
40926
  MLearner,
40927
+ MPersonnel,
38364
40928
  MPlantilla,
38365
40929
  MStockCard,
38366
40930
  allowedSectionStudentStatuses,
@@ -38371,9 +40935,12 @@ dotenv.config();
38371
40935
  modelSection,
38372
40936
  modelSectionPreset,
38373
40937
  modelSectionStudent,
40938
+ modelSectionSubject,
38374
40939
  schemaAsset,
38375
40940
  schemaAssetUpdateOption,
38376
40941
  schemaBasicEduCount,
40942
+ schemaBuilding,
40943
+ schemaBuildingUnit,
38377
40944
  schemaCurriculum,
38378
40945
  schemaCurriculumSubject,
38379
40946
  schemaCurriculumSubjectAdd,
@@ -38382,6 +40949,7 @@ dotenv.config();
38382
40949
  schemaEnrollment,
38383
40950
  schemaGenerateSections,
38384
40951
  schemaGradeLevel,
40952
+ schemaPersonnel,
38385
40953
  schemaPlantilla,
38386
40954
  schemaRegion,
38387
40955
  schemaSchool,
@@ -38389,11 +40957,20 @@ dotenv.config();
38389
40957
  schemaSection,
38390
40958
  schemaSectionPreset,
38391
40959
  schemaSectionStudent,
40960
+ schemaSectionSubject,
40961
+ schemaSectionSubjectSetup,
38392
40962
  schemaStockCard,
40963
+ schemaUpdateOptions,
38393
40964
  schemaUpdateStatus,
38394
40965
  useAssetController,
38395
40966
  useAssetRepo,
38396
40967
  useBasicEduCountRepo,
40968
+ useBuildingController,
40969
+ useBuildingRepo,
40970
+ useBuildingService,
40971
+ useBuildingUnitController,
40972
+ useBuildingUnitRepo,
40973
+ useBuildingUnitService,
38397
40974
  useCurriculumController,
38398
40975
  useCurriculumRepo,
38399
40976
  useCurriculumSubjectController,
@@ -38409,6 +40986,8 @@ dotenv.config();
38409
40986
  useGradeLevelRepo,
38410
40987
  useLearnerController,
38411
40988
  useLearnerRepo,
40989
+ usePersonnelController,
40990
+ usePersonnelRepo,
38412
40991
  usePlantillaController,
38413
40992
  usePlantillaRepo,
38414
40993
  usePlantillaService,
@@ -38422,6 +41001,9 @@ dotenv.config();
38422
41001
  useSectionPresetRepo,
38423
41002
  useSectionRepo,
38424
41003
  useSectionStudentRepo,
41004
+ useSectionSubjectController,
41005
+ useSectionSubjectRepo,
41006
+ useSectionSubjectService,
38425
41007
  useStockCardController,
38426
41008
  useStockCardRepository,
38427
41009
  useStockCardService