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