@eeplatform/basic-edu 1.10.7 → 1.10.9

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.mjs CHANGED
@@ -2038,7 +2038,7 @@ import Joi3 from "joi";
2038
2038
  import { ObjectId as ObjectId3 } from "mongodb";
2039
2039
  var schemaSubject = Joi3.object({
2040
2040
  _id: Joi3.string().hex().optional(),
2041
- school: Joi3.string().hex().optional().allow("", null),
2041
+ school: Joi3.string().hex().required(),
2042
2042
  schoolName: Joi3.string().optional().allow("", null),
2043
2043
  curriculum: Joi3.string().hex().required(),
2044
2044
  curriculumName: Joi3.string().required(),
@@ -2065,6 +2065,8 @@ var schemaSubject = Joi3.object({
2065
2065
  deletedBy: Joi3.string().optional().allow("", null)
2066
2066
  });
2067
2067
  var schemaSubjectAdd = Joi3.object({
2068
+ school: Joi3.string().hex().required(),
2069
+ schoolName: Joi3.string().optional().allow("", null),
2068
2070
  curriculum: Joi3.string().hex().required(),
2069
2071
  curriculumName: Joi3.string().required(),
2070
2072
  effectiveSchoolYear: Joi3.array().items(Joi3.number().integer().min(1900)).optional(),
@@ -2088,6 +2090,11 @@ function modelSubject(value) {
2088
2090
  logger4.info(`Subject Model: ${error.message}`);
2089
2091
  throw new BadRequestError4(error.message);
2090
2092
  }
2093
+ try {
2094
+ value.school = new ObjectId3(value.school);
2095
+ } catch (error2) {
2096
+ throw new BadRequestError4("Invalid school ID format");
2097
+ }
2091
2098
  if (value._id && typeof value._id === "string") {
2092
2099
  try {
2093
2100
  value._id = new ObjectId3(value._id);
@@ -2102,13 +2109,6 @@ function modelSubject(value) {
2102
2109
  throw new BadRequestError4("Invalid curriculum ID format");
2103
2110
  }
2104
2111
  }
2105
- if (value.school && typeof value.school === "string") {
2106
- try {
2107
- value.school = new ObjectId3(value.school);
2108
- } catch (error2) {
2109
- throw new BadRequestError4("Invalid school ID format");
2110
- }
2111
- }
2112
2112
  if (value.program && typeof value.program === "string") {
2113
2113
  try {
2114
2114
  value.program = new ObjectId3(value.program);
@@ -2237,6 +2237,7 @@ function useSubjectRepo() {
2237
2237
  }
2238
2238
  }
2239
2239
  async function getAll({
2240
+ school = "",
2240
2241
  search = "",
2241
2242
  page = 1,
2242
2243
  limit = 10,
@@ -2244,18 +2245,27 @@ function useSubjectRepo() {
2244
2245
  status = "active",
2245
2246
  curriculum,
2246
2247
  educationLevel,
2247
- gradeLevel,
2248
- schoolYear = 0
2248
+ gradeLevel
2249
2249
  } = {}) {
2250
2250
  page = page > 0 ? page - 1 : 0;
2251
- const query = {
2252
- status
2253
- };
2251
+ const query = {};
2254
2252
  const cacheParams = {
2255
2253
  page,
2256
2254
  limit,
2257
2255
  sort: JSON.stringify(sort)
2258
2256
  };
2257
+ if (status) {
2258
+ query.status = status;
2259
+ cacheParams.status = status;
2260
+ }
2261
+ if (school) {
2262
+ try {
2263
+ query.school = new ObjectId4(school);
2264
+ } catch (error) {
2265
+ throw new BadRequestError5("Invalid school ID format.");
2266
+ }
2267
+ cacheParams.school = school;
2268
+ }
2259
2269
  if (curriculum) {
2260
2270
  try {
2261
2271
  query.curriculum = new ObjectId4(curriculum);
@@ -2272,10 +2282,6 @@ function useSubjectRepo() {
2272
2282
  query.gradeLevel = gradeLevel;
2273
2283
  cacheParams.gradeLevel = gradeLevel;
2274
2284
  }
2275
- if (schoolYear) {
2276
- query.effectiveSchoolYear = schoolYear;
2277
- cacheParams.schoolYear = schoolYear;
2278
- }
2279
2285
  sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
2280
2286
  if (search) {
2281
2287
  query.$or = [
@@ -2587,6 +2593,8 @@ function useSubjectService() {
2587
2593
  const gradeLevel = value.gradeLevel[index];
2588
2594
  await add(
2589
2595
  {
2596
+ school: value.school,
2597
+ schoolName: value.schoolName,
2590
2598
  curriculum: value.curriculum,
2591
2599
  curriculumName: value.curriculumName,
2592
2600
  effectiveSchoolYear: value.effectiveSchoolYear,
@@ -2738,6 +2746,62 @@ function useSubjectController() {
2738
2746
  next(error2);
2739
2747
  }
2740
2748
  }
2749
+ async function getBySchool(req, res, next) {
2750
+ const school = req.params.school ?? "";
2751
+ const { error: errorSchool } = Joi4.string().hex().required().validate(school);
2752
+ if (errorSchool) {
2753
+ next(new BadRequestError6(errorSchool.message));
2754
+ return;
2755
+ }
2756
+ const query = req.query;
2757
+ const validation = Joi4.object({
2758
+ page: Joi4.number().min(1).optional().allow("", null),
2759
+ limit: Joi4.number().min(1).optional().allow("", null),
2760
+ search: Joi4.string().optional().allow("", null),
2761
+ status: Joi4.string().optional().allow("", null),
2762
+ curriculum: Joi4.string().hex().optional().allow("", null),
2763
+ educationLevel: Joi4.string().optional().allow("", null),
2764
+ gradeLevel: Joi4.string().optional().allow("", null)
2765
+ });
2766
+ const { error } = validation.validate(query);
2767
+ if (error) {
2768
+ next(new BadRequestError6(error.message));
2769
+ return;
2770
+ }
2771
+ const page = parseInt(req.query.page) ?? 1;
2772
+ let limit = parseInt(req.query.limit) ?? 20;
2773
+ limit = isNaN(limit) ? 20 : limit;
2774
+ const sort = req.query.sort ? String(req.query.sort).split(",") : "";
2775
+ const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
2776
+ const sortObj = {};
2777
+ if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
2778
+ sort.forEach((field, index) => {
2779
+ sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
2780
+ });
2781
+ }
2782
+ const status = req.query.status ?? "active";
2783
+ const search = req.query.search ?? "";
2784
+ const curriculum = req.query.curriculum ?? "";
2785
+ const educationLevel = req.query.educationLevel ?? "";
2786
+ const gradeLevel = req.query.gradeLevel ?? "";
2787
+ try {
2788
+ const curriculumSubjects = await _getAll({
2789
+ school,
2790
+ page,
2791
+ limit,
2792
+ sort: sortObj,
2793
+ status,
2794
+ search,
2795
+ curriculum,
2796
+ educationLevel,
2797
+ gradeLevel
2798
+ });
2799
+ res.json(curriculumSubjects);
2800
+ return;
2801
+ } catch (error2) {
2802
+ next(error2);
2803
+ }
2804
+ }
2741
2805
  async function getAsOptions(req, res, next) {
2742
2806
  const query = req.query;
2743
2807
  const validation = Joi4.object({
@@ -2845,6 +2909,7 @@ function useSubjectController() {
2845
2909
  return {
2846
2910
  add,
2847
2911
  addMany,
2912
+ getBySchool,
2848
2913
  getAll,
2849
2914
  getById,
2850
2915
  getByCurriculum,
@@ -40788,7 +40853,7 @@ function useSectionRepo() {
40788
40853
  school = "",
40789
40854
  schoolYear = "",
40790
40855
  gradeLevel = ""
40791
- } = {}) {
40856
+ } = {}, session) {
40792
40857
  page = page > 0 ? page - 1 : 0;
40793
40858
  const query = {
40794
40859
  deletedAt: { $in: ["", null] },
@@ -40835,12 +40900,15 @@ function useSectionRepo() {
40835
40900
  });
40836
40901
  return cached;
40837
40902
  }
40838
- const items = await collection.aggregate([
40839
- { $match: query },
40840
- { $sort: sort },
40841
- { $skip: page * limit },
40842
- { $limit: limit }
40843
- ]).toArray();
40903
+ const items = await collection.aggregate(
40904
+ [
40905
+ { $match: query },
40906
+ { $sort: sort },
40907
+ { $skip: page * limit },
40908
+ { $limit: limit }
40909
+ ],
40910
+ { session }
40911
+ ).toArray();
40844
40912
  const length = await collection.countDocuments(query);
40845
40913
  const data = paginate17(items, page, limit, length);
40846
40914
  setCache(cacheKey, data, 600).then(() => {
@@ -40905,7 +40973,10 @@ function useSectionRepo() {
40905
40973
  }
40906
40974
  async function getSection(options) {
40907
40975
  const query = {};
40908
- const cacheKeyOptions = { tag: "getSection" };
40976
+ const cacheKeyOptions = {
40977
+ tag: "getSection",
40978
+ status: "notDeleted"
40979
+ };
40909
40980
  try {
40910
40981
  query.school = new ObjectId34(options.school);
40911
40982
  cacheKeyOptions.school = String(options.school);
@@ -41060,7 +41131,7 @@ function useSectionRepo() {
41060
41131
  const updateValue = field === "adviser" ? new ObjectId34(value) : value;
41061
41132
  await collection.updateOne(
41062
41133
  { _id, deletedAt: { $in: ["", null] } },
41063
- { $set: { [field]: updateValue, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } },
41134
+ { $set: { [field]: updateValue, updatedAt: /* @__PURE__ */ new Date() } },
41064
41135
  { session }
41065
41136
  );
41066
41137
  delCachedData();
@@ -41080,7 +41151,7 @@ function useSectionRepo() {
41080
41151
  { _id, deletedAt: { $in: ["", null] } },
41081
41152
  {
41082
41153
  $addToSet: { students: studentId },
41083
- $set: { updatedAt: (/* @__PURE__ */ new Date()).toISOString() }
41154
+ $set: { updatedAt: /* @__PURE__ */ new Date() }
41084
41155
  },
41085
41156
  { session }
41086
41157
  );
@@ -41102,7 +41173,7 @@ function useSectionRepo() {
41102
41173
  {
41103
41174
  // @ts-ignore
41104
41175
  $pull: { students: studentId },
41105
- $set: { updatedAt: (/* @__PURE__ */ new Date()).toISOString() }
41176
+ $set: { updatedAt: /* @__PURE__ */ new Date() }
41106
41177
  },
41107
41178
  { session }
41108
41179
  );
@@ -41112,23 +41183,42 @@ function useSectionRepo() {
41112
41183
  throw new InternalServerError16("Failed to remove student from section.");
41113
41184
  }
41114
41185
  }
41115
- async function deleteById(_id) {
41186
+ async function deleteById(_id, session) {
41116
41187
  try {
41117
41188
  _id = new ObjectId34(_id);
41118
41189
  } catch (error) {
41119
41190
  throw new BadRequestError56(namespace_collection + " Invalid ID.");
41120
41191
  }
41121
41192
  try {
41122
- await collection.updateOne(
41123
- { _id },
41124
- { $set: { status: "deleted", deletedAt: (/* @__PURE__ */ new Date()).toISOString() } }
41125
- );
41193
+ await collection.deleteOne({ _id }, { session });
41126
41194
  delCachedData();
41127
41195
  return "Successfully deleted section.";
41128
41196
  } catch (error) {
41129
41197
  throw new InternalServerError16("Failed to delete section.");
41130
41198
  }
41131
41199
  }
41200
+ async function deleteByIds(_id, session) {
41201
+ if (_id && Array.isArray(_id)) {
41202
+ _id = _id.map((id) => {
41203
+ try {
41204
+ return new ObjectId34(id);
41205
+ } catch (error) {
41206
+ throw new BadRequestError56(namespace_collection + " Invalid ID.");
41207
+ }
41208
+ });
41209
+ }
41210
+ try {
41211
+ await collection.updateOne(
41212
+ { _id: { $in: _id } },
41213
+ { $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } },
41214
+ { session }
41215
+ );
41216
+ delCachedData();
41217
+ return "Successfully deleted sections.";
41218
+ } catch (error) {
41219
+ throw new InternalServerError16("Failed to delete sections.");
41220
+ }
41221
+ }
41132
41222
  async function updateSizeById(_id, size, session) {
41133
41223
  try {
41134
41224
  _id = new ObjectId34(_id);
@@ -41138,7 +41228,7 @@ function useSectionRepo() {
41138
41228
  try {
41139
41229
  await collection.updateOne(
41140
41230
  { _id },
41141
- { $set: { student: size, updateAt: /* @__PURE__ */ new Date() } },
41231
+ { $set: { students: size, updateAt: /* @__PURE__ */ new Date() } },
41142
41232
  { session }
41143
41233
  );
41144
41234
  delCachedData();
@@ -41148,6 +41238,7 @@ function useSectionRepo() {
41148
41238
  }
41149
41239
  }
41150
41240
  return {
41241
+ delCachedData,
41151
41242
  createIndexes,
41152
41243
  add,
41153
41244
  getAll,
@@ -41159,7 +41250,8 @@ function useSectionRepo() {
41159
41250
  addStudentToSection,
41160
41251
  removeStudentFromSection,
41161
41252
  deleteById,
41162
- updateSizeById
41253
+ updateSizeById,
41254
+ deleteByIds
41163
41255
  };
41164
41256
  }
41165
41257
 
@@ -41339,7 +41431,7 @@ function useSectionStudentRepo() {
41339
41431
  gradeLevel = "",
41340
41432
  section = "",
41341
41433
  schoolYear = ""
41342
- } = {}) {
41434
+ } = {}, session) {
41343
41435
  const { error } = Joi37.object({
41344
41436
  page: Joi37.number().min(1).default(1),
41345
41437
  limit: Joi37.number().min(1).max(100).default(10),
@@ -41401,11 +41493,10 @@ function useSectionStudentRepo() {
41401
41493
  return cachedData;
41402
41494
  }
41403
41495
  page = page > 0 ? page - 1 : 0;
41404
- const items = await collection.aggregate([
41405
- { $match: query },
41406
- { $skip: page * limit },
41407
- { $limit: limit }
41408
- ]).toArray();
41496
+ const items = await collection.aggregate(
41497
+ [{ $match: query }, { $skip: page * limit }, { $limit: limit }],
41498
+ { session }
41499
+ ).toArray();
41409
41500
  const length = await collection.countDocuments(query);
41410
41501
  const data = paginate18(items, page, limit, length);
41411
41502
  setCache(cacheKey, data, 600).then(() => {
@@ -41480,6 +41571,13 @@ function useSectionStudentRepo() {
41480
41571
  } catch (error) {
41481
41572
  throw new BadRequestError58("Invalid section student ID.");
41482
41573
  }
41574
+ try {
41575
+ if (typeof options.section === "string") {
41576
+ options.section = new ObjectId36(options.section);
41577
+ }
41578
+ } catch (error) {
41579
+ throw new BadRequestError58("Invalid section ID.");
41580
+ }
41483
41581
  try {
41484
41582
  await collection.updateMany({ _id }, { $set: options }, { session });
41485
41583
  delCachedData();
@@ -42492,6 +42590,32 @@ function useTeachingLoadSlotRepo() {
42492
42590
  }
42493
42591
  }
42494
42592
  }
42593
+ async function deleteBySection(section, session) {
42594
+ try {
42595
+ section = new ObjectId40(section);
42596
+ } catch (error) {
42597
+ throw new BadRequestError63(namespace_collection + " Invalid section ID.");
42598
+ }
42599
+ try {
42600
+ const res = await collection.updateOne(
42601
+ { section },
42602
+ { $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } },
42603
+ { session }
42604
+ );
42605
+ delCachedData();
42606
+ return res;
42607
+ } catch (error) {
42608
+ logger35.log({
42609
+ level: "error",
42610
+ message: error.message
42611
+ });
42612
+ if (error instanceof AppError23) {
42613
+ throw error;
42614
+ } else {
42615
+ throw new InternalServerError19("Failed to delete teaching load slot.");
42616
+ }
42617
+ }
42618
+ }
42495
42619
  function delCachedData() {
42496
42620
  delNamespace().then(() => {
42497
42621
  logger35.log({
@@ -42512,7 +42636,8 @@ function useTeachingLoadSlotRepo() {
42512
42636
  getAll,
42513
42637
  getById,
42514
42638
  deleteById,
42515
- delCachedData
42639
+ delCachedData,
42640
+ deleteBySection
42516
42641
  };
42517
42642
  }
42518
42643
 
@@ -42628,6 +42753,43 @@ function useTeachingLoadSlotController() {
42628
42753
  next(error2);
42629
42754
  }
42630
42755
  }
42756
+ async function getBySection(req, res, next) {
42757
+ const section = req.params.section ?? "";
42758
+ const validation = Joi42.string().hex().required();
42759
+ const { error: errorTeacher } = validation.validate(section);
42760
+ if (errorTeacher) {
42761
+ next(new BadRequestError64(errorTeacher.message));
42762
+ logger36.info(`Controller: ${errorTeacher.message}`);
42763
+ return;
42764
+ }
42765
+ const query = req.query;
42766
+ const schema = Joi42.object({
42767
+ page: Joi42.number().min(1).optional().allow("", null),
42768
+ limit: Joi42.number().min(1).max(100).optional().allow("", null),
42769
+ status: Joi42.string().optional().allow("", null)
42770
+ });
42771
+ const { error } = schema.validate(query);
42772
+ if (error) {
42773
+ next(new BadRequestError64(error.message));
42774
+ logger36.info(`Controller: ${error.message}`);
42775
+ return;
42776
+ }
42777
+ const page = Number(req.query.page ?? 1);
42778
+ const limit = Number(req.query.limit ?? 10);
42779
+ const status = req.query.status ?? "active";
42780
+ try {
42781
+ const result = await _getAll({
42782
+ section,
42783
+ page,
42784
+ limit,
42785
+ status
42786
+ });
42787
+ res.json(result);
42788
+ return;
42789
+ } catch (error2) {
42790
+ next(error2);
42791
+ }
42792
+ }
42631
42793
  async function getByTeacher(req, res, next) {
42632
42794
  const teacher = req.params.teacher ?? "";
42633
42795
  const schemaTeacher = Joi42.string().hex().required();
@@ -42816,7 +42978,8 @@ function useTeachingLoadSlotController() {
42816
42978
  getById,
42817
42979
  deleteById,
42818
42980
  getByTeachingLoad,
42819
- getByTeacher
42981
+ getByTeacher,
42982
+ getBySection
42820
42983
  };
42821
42984
  }
42822
42985
 
@@ -43390,15 +43553,25 @@ function usePersonnelController() {
43390
43553
  function useSectionService() {
43391
43554
  const { getCountByGradeLevel, getByGradeLevel: getLeanerByGradeLevel } = useLearnerRepo();
43392
43555
  const { getByGradeLevel } = useGradeLevelRepo();
43393
- const { add: createSection, getSection, updateSizeById } = useSectionRepo();
43556
+ const {
43557
+ add: createSection,
43558
+ getSection,
43559
+ updateSizeById,
43560
+ getAll: getAllSection,
43561
+ deleteById: deleteSectionById,
43562
+ delCachedData: delCachedSectionData
43563
+ } = useSectionRepo();
43394
43564
  const {
43395
43565
  add: assignStudent,
43396
43566
  getStudent,
43397
- updateSectionById
43567
+ updateSectionById,
43568
+ getAll: getAllStudents,
43569
+ delCachedData: delCachedSectionStudentData
43398
43570
  } = useSectionStudentRepo();
43399
43571
  const { getById: getSchoolById } = useSchoolRepo();
43400
43572
  const { getAll: getAllPersonnel } = usePersonnelRepo();
43401
43573
  const { add: addTeachingLoad, getByTeacher } = useTeachingLoadRepo();
43574
+ const { deleteBySection: deleteTeachingLoadSlotsBySection } = useTeachingLoadSlotRepo();
43402
43575
  function distributeStudents(total, minPer, maxPer) {
43403
43576
  if (total <= 0)
43404
43577
  return [];
@@ -43498,6 +43671,8 @@ function useSectionService() {
43498
43671
  let studentSkipped = 0;
43499
43672
  let subjectsAssigned = 0;
43500
43673
  let subjectsSkipped = 0;
43674
+ await delCachedSectionData();
43675
+ await delCachedSectionStudentData();
43501
43676
  for (let i = 0; i < sectionSizes.length; i++) {
43502
43677
  const size = sectionSizes[i];
43503
43678
  const sectionName = String(i + 1);
@@ -43512,11 +43687,7 @@ function useSectionService() {
43512
43687
  sectionId = existingSection._id?.toString() || "";
43513
43688
  sectionsSkipped++;
43514
43689
  if (size !== existingSection.students) {
43515
- await updateSizeById(
43516
- existingSection._id?.toString() || "",
43517
- size,
43518
- session
43519
- );
43690
+ await updateSizeById(sectionId, size, session);
43520
43691
  }
43521
43692
  } else {
43522
43693
  sectionId = await createSection(
@@ -43558,14 +43729,13 @@ function useSectionService() {
43558
43729
  const existingStudent = await getStudent({
43559
43730
  student: student._id.toString(),
43560
43731
  schoolYear: value.schoolYear,
43561
- section: sectionId,
43562
43732
  gradeLevel: value.gradeLevel
43563
43733
  });
43564
43734
  if (existingStudent) {
43565
43735
  studentSkipped++;
43566
- if (existingStudent.section !== sectionId) {
43736
+ if (String(existingStudent.section) !== sectionId) {
43567
43737
  await updateSectionById(
43568
- sectionId,
43738
+ existingStudent._id?.toString() ?? "",
43569
43739
  { section: sectionId, sectionName },
43570
43740
  session
43571
43741
  );
@@ -43639,6 +43809,36 @@ function useSectionService() {
43639
43809
  }
43640
43810
  }
43641
43811
  await session.commitTransaction();
43812
+ await session.startTransaction();
43813
+ await delCachedSectionData();
43814
+ await delCachedSectionStudentData();
43815
+ const sections = await getAllSection(
43816
+ {
43817
+ school: value.school,
43818
+ schoolYear: value.schoolYear,
43819
+ gradeLevel: value.gradeLevel
43820
+ },
43821
+ session
43822
+ );
43823
+ if (sections && sections.items && sections.items.length) {
43824
+ for (const section of sections.items) {
43825
+ const sectionId = section._id?.toString() || "";
43826
+ const students = await getAllStudents(
43827
+ {
43828
+ school: value.school,
43829
+ schoolYear: value.schoolYear,
43830
+ section: sectionId
43831
+ },
43832
+ session
43833
+ );
43834
+ if (students && students.items && students.items.length) {
43835
+ continue;
43836
+ }
43837
+ await deleteSectionById(sectionId, session);
43838
+ await deleteTeachingLoadSlotsBySection(sectionId, session);
43839
+ }
43840
+ }
43841
+ await session.commitTransaction();
43642
43842
  return {
43643
43843
  message: "Sections generated successfully.",
43644
43844
  summary: {