@eeplatform/core 1.4.5 → 1.5.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.mjs CHANGED
@@ -10389,7 +10389,7 @@ var require_ms = __commonJS({
10389
10389
  options = options || {};
10390
10390
  var type = typeof val;
10391
10391
  if (type === "string" && val.length > 0) {
10392
- return parse3(val);
10392
+ return parse4(val);
10393
10393
  } else if (type === "number" && isNaN(val) === false) {
10394
10394
  return options.long ? fmtLong(val) : fmtShort(val);
10395
10395
  }
@@ -10397,7 +10397,7 @@ var require_ms = __commonJS({
10397
10397
  "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
10398
10398
  );
10399
10399
  };
10400
- function parse3(str) {
10400
+ function parse4(str) {
10401
10401
  str = String(str);
10402
10402
  if (str.length > 100) {
10403
10403
  return;
@@ -28410,7 +28410,10 @@ function useBuildingUnitService() {
28410
28410
  try {
28411
28411
  await session.startTransaction();
28412
28412
  for (let index = 0; index < value.qty; index++) {
28413
- await _add({ ...value.building }, session);
28413
+ await _add(
28414
+ { ...value.building, name: `${value.building.name} ${index + 1}` },
28415
+ session
28416
+ );
28414
28417
  }
28415
28418
  await session.commitTransaction();
28416
28419
  return "Building unit added successfully.";
@@ -29925,6 +29928,10 @@ import Joi41 from "joi";
29925
29928
  import { ObjectId as ObjectId46 } from "mongodb";
29926
29929
  var schemaPlantilla = Joi41.object({
29927
29930
  _id: Joi41.string().hex().optional().allow(null, ""),
29931
+ org: Joi41.string().hex().required(),
29932
+ orgUnitCode: Joi41.string().optional().allow(null, ""),
29933
+ employmentType: Joi41.string().optional().allow(null, ""),
29934
+ personnelType: Joi41.string().required(),
29928
29935
  itemNumber: Joi41.string().required(),
29929
29936
  positionTitle: Joi41.string().required(),
29930
29937
  positionCategory: Joi41.string().required(),
@@ -29933,8 +29940,7 @@ var schemaPlantilla = Joi41.object({
29933
29940
  division: Joi41.string().hex().optional().allow(null, ""),
29934
29941
  divisionName: Joi41.string().optional().allow(null, ""),
29935
29942
  salaryGrade: Joi41.number().required(),
29936
- step: Joi41.number().optional().allow(null, 0),
29937
- incumbent: Joi41.string().optional().allow(null, ""),
29943
+ employeeName: Joi41.string().optional().allow(null, ""),
29938
29944
  annualSalary: Joi41.number().optional().allow(null, 0),
29939
29945
  monthlySalary: Joi41.number().optional().allow(null, 0),
29940
29946
  status: Joi41.string().required(),
@@ -29962,14 +29968,18 @@ function MPlantilla(data) {
29962
29968
  positionCategory: data.positionCategory ?? "",
29963
29969
  status: data.status ?? "active",
29964
29970
  salaryGrade: data.salaryGrade ?? 0,
29965
- step: data.step ?? 0,
29966
29971
  monthlySalary: data.monthlySalary ?? 0,
29967
29972
  annualSalary: data.annualSalary ?? 0,
29968
29973
  region: data.region ?? "",
29969
29974
  regionName: data.regionName ?? "",
29970
29975
  division: data.division ?? "",
29971
29976
  divisionName: data.divisionName ?? "",
29972
- incumbent: data.incumbent ?? "",
29977
+ org: data.org ?? "",
29978
+ orgUnitCode: data.orgUnitCode ?? "",
29979
+ employmentType: data.employmentType ?? "",
29980
+ personnelType: data.personnelType ?? "",
29981
+ employee: data.employee ?? "",
29982
+ employeeName: data.employeeName ?? "",
29973
29983
  createdAt: data.createdAt ? new Date(data.createdAt) : /* @__PURE__ */ new Date(),
29974
29984
  updatedAt: data.updatedAt ? new Date(data.updatedAt) : "",
29975
29985
  deletedAt: data.deletedAt ? new Date(data.deletedAt) : ""
@@ -30319,7 +30329,8 @@ function usePlantillaService() {
30319
30329
  salaryGrade: parseInt(
30320
30330
  plantillaData.salarygrade || plantillaData.salary_grade || "1"
30321
30331
  ) || 1,
30322
- step: parseInt(plantillaData.step || "1") || 1,
30332
+ org: "",
30333
+ personnelType: "",
30323
30334
  status: status.trim() || "active"
30324
30335
  };
30325
30336
  if (region)
@@ -30332,9 +30343,6 @@ function usePlantillaService() {
30332
30343
  if (plantillaData.divisionname || plantillaData.division_name) {
30333
30344
  plantilla.divisionName = plantillaData.divisionname || plantillaData.division_name;
30334
30345
  }
30335
- if (plantillaData.incumbent) {
30336
- plantilla.incumbent = plantillaData.incumbent;
30337
- }
30338
30346
  if (plantillaData.employee) {
30339
30347
  plantilla.employee = plantillaData.employee;
30340
30348
  }
@@ -30615,6 +30623,1154 @@ function usePlantillaController() {
30615
30623
  bulkAddPlantillas
30616
30624
  };
30617
30625
  }
30626
+
30627
+ // src/models/office.model.ts
30628
+ import { BadRequestError as BadRequestError78 } from "@eeplatform/nodejs-utils";
30629
+ import Joi43 from "joi";
30630
+ import { ObjectId as ObjectId48 } from "mongodb";
30631
+ var schemaOffice = Joi43.object({
30632
+ _id: Joi43.string().hex().optional().allow(null, ""),
30633
+ name: Joi43.string().required(),
30634
+ code: Joi43.string().required(),
30635
+ type: Joi43.string().required(),
30636
+ parent: Joi43.string().hex().optional().allow(null, ""),
30637
+ path: Joi43.string().required(),
30638
+ status: Joi43.string().required(),
30639
+ createdAt: Joi43.date().iso().optional().allow(null, ""),
30640
+ updatedAt: Joi43.date().iso().optional().allow(null, ""),
30641
+ deletedAt: Joi43.date().iso().optional().allow(null, "")
30642
+ });
30643
+ function MOffice(data) {
30644
+ const { error } = schemaOffice.validate(data);
30645
+ if (error) {
30646
+ throw new BadRequestError78(error.message);
30647
+ }
30648
+ if (data._id && typeof data._id === "string") {
30649
+ try {
30650
+ data._id = new ObjectId48(data._id);
30651
+ } catch (error2) {
30652
+ throw new BadRequestError78("Invalid _id.");
30653
+ }
30654
+ }
30655
+ if (data.parent && typeof data.parent === "string") {
30656
+ try {
30657
+ data.parent = new ObjectId48(data.parent);
30658
+ } catch (error2) {
30659
+ throw new BadRequestError78("Invalid parent.");
30660
+ }
30661
+ }
30662
+ return {
30663
+ _id: data._id,
30664
+ name: data.name ?? "",
30665
+ code: data.code ?? "",
30666
+ type: data.type ?? "",
30667
+ parent: data.parent ?? "",
30668
+ path: data.path ?? "",
30669
+ status: data.status ?? "active",
30670
+ createdAt: data.createdAt ? new Date(data.createdAt) : /* @__PURE__ */ new Date(),
30671
+ updatedAt: data.updatedAt ? new Date(data.updatedAt) : "",
30672
+ deletedAt: data.deletedAt ? new Date(data.deletedAt) : ""
30673
+ };
30674
+ }
30675
+
30676
+ // src/repositories/office.repository.ts
30677
+ import {
30678
+ AppError as AppError19,
30679
+ BadRequestError as BadRequestError79,
30680
+ InternalServerError as InternalServerError29,
30681
+ logger as logger38,
30682
+ makeCacheKey as makeCacheKey24,
30683
+ paginate as paginate20,
30684
+ useAtlas as useAtlas40,
30685
+ useCache as useCache25
30686
+ } from "@eeplatform/nodejs-utils";
30687
+ import { ObjectId as ObjectId49 } from "mongodb";
30688
+ function useOfficeRepo() {
30689
+ const db = useAtlas40.getDb();
30690
+ if (!db) {
30691
+ throw new Error("Unable to connect to server.");
30692
+ }
30693
+ const namespace_collection = "offices";
30694
+ const collection = db.collection(namespace_collection);
30695
+ const { getCache, setCache, delNamespace } = useCache25(namespace_collection);
30696
+ async function createIndexes() {
30697
+ try {
30698
+ await collection.createIndexes([
30699
+ {
30700
+ key: { name: 1, code: 1 },
30701
+ unique: true,
30702
+ name: "unique_name_code_index"
30703
+ },
30704
+ { key: { type: 1 } },
30705
+ { key: { parent: 1 } },
30706
+ { key: { status: 1 } }
30707
+ ]);
30708
+ } catch (error) {
30709
+ throw new Error("Failed to create index on offices.");
30710
+ }
30711
+ }
30712
+ async function add(value, session, clearCache = true) {
30713
+ try {
30714
+ value = MOffice(value);
30715
+ const res = await collection.insertOne(value, { session });
30716
+ if (clearCache) {
30717
+ delCachedData();
30718
+ }
30719
+ return res.insertedId;
30720
+ } catch (error) {
30721
+ logger38.log({
30722
+ level: "error",
30723
+ message: error.message
30724
+ });
30725
+ if (error instanceof AppError19) {
30726
+ throw error;
30727
+ } else {
30728
+ const isDuplicated = error.message.includes("duplicate");
30729
+ if (isDuplicated) {
30730
+ throw new BadRequestError79("Office already exists.");
30731
+ }
30732
+ throw new Error("Failed to create office.");
30733
+ }
30734
+ }
30735
+ }
30736
+ async function updateById(_id, value, session) {
30737
+ try {
30738
+ _id = new ObjectId49(_id);
30739
+ } catch (error) {
30740
+ throw new BadRequestError79("Invalid ID.");
30741
+ }
30742
+ value.updatedAt = /* @__PURE__ */ new Date();
30743
+ try {
30744
+ const res = await collection.updateOne(
30745
+ { _id },
30746
+ { $set: value },
30747
+ { session }
30748
+ );
30749
+ delCachedData();
30750
+ return res;
30751
+ } catch (error) {
30752
+ logger38.log({
30753
+ level: "error",
30754
+ message: error.message
30755
+ });
30756
+ if (error instanceof AppError19) {
30757
+ throw error;
30758
+ } else {
30759
+ throw new Error("Failed to update office.");
30760
+ }
30761
+ }
30762
+ }
30763
+ async function getAll({
30764
+ search = "",
30765
+ page = 1,
30766
+ limit = 10,
30767
+ sort = {},
30768
+ type = "",
30769
+ parent = "",
30770
+ status = "active"
30771
+ } = {}) {
30772
+ page = page > 0 ? page - 1 : 0;
30773
+ const query = {
30774
+ status
30775
+ };
30776
+ sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
30777
+ if (search) {
30778
+ query.$text = { $search: search };
30779
+ }
30780
+ if (type) {
30781
+ query.type = type;
30782
+ }
30783
+ if (parent) {
30784
+ try {
30785
+ query.parent = new ObjectId49(parent);
30786
+ } catch (error) {
30787
+ throw new BadRequestError79("Invalid parent ID.");
30788
+ }
30789
+ }
30790
+ const cacheParams = {
30791
+ page,
30792
+ limit,
30793
+ sort: JSON.stringify(sort)
30794
+ };
30795
+ if (search)
30796
+ cacheParams.search = search;
30797
+ if (type)
30798
+ cacheParams.type = type;
30799
+ if (parent)
30800
+ cacheParams.parent = parent;
30801
+ if (status !== "active")
30802
+ cacheParams.status = status;
30803
+ const cacheKey = makeCacheKey24(namespace_collection, cacheParams);
30804
+ logger38.log({
30805
+ level: "info",
30806
+ message: `Cache key for getAll offices: ${cacheKey}`
30807
+ });
30808
+ try {
30809
+ const cached = await getCache(cacheKey);
30810
+ if (cached) {
30811
+ logger38.log({
30812
+ level: "info",
30813
+ message: `Cache hit for getAll offices: ${cacheKey}`
30814
+ });
30815
+ return cached;
30816
+ }
30817
+ const items = await collection.aggregate([
30818
+ { $match: query },
30819
+ { $sort: sort },
30820
+ { $skip: page * limit },
30821
+ { $limit: limit }
30822
+ ]).toArray();
30823
+ const length = await collection.countDocuments(query);
30824
+ const data = paginate20(items, page, limit, length);
30825
+ setCache(cacheKey, data, 600).then(() => {
30826
+ logger38.log({
30827
+ level: "info",
30828
+ message: `Cache set for getAll offices: ${cacheKey}`
30829
+ });
30830
+ }).catch((err) => {
30831
+ logger38.log({
30832
+ level: "error",
30833
+ message: `Failed to set cache for getAll offices: ${err.message}`
30834
+ });
30835
+ });
30836
+ return data;
30837
+ } catch (error) {
30838
+ logger38.log({ level: "error", message: `${error}` });
30839
+ throw error;
30840
+ }
30841
+ }
30842
+ async function getById(_id) {
30843
+ try {
30844
+ _id = new ObjectId49(_id);
30845
+ } catch (error) {
30846
+ throw new BadRequestError79("Invalid ID.");
30847
+ }
30848
+ const cacheKey = makeCacheKey24(namespace_collection, { _id: String(_id) });
30849
+ try {
30850
+ const cached = await getCache(cacheKey);
30851
+ if (cached) {
30852
+ logger38.log({
30853
+ level: "info",
30854
+ message: `Cache hit for getById office: ${cacheKey}`
30855
+ });
30856
+ return cached;
30857
+ }
30858
+ const result = await collection.findOne({
30859
+ _id
30860
+ });
30861
+ setCache(cacheKey, result, 300).then(() => {
30862
+ logger38.log({
30863
+ level: "info",
30864
+ message: `Cache set for office by id: ${cacheKey}`
30865
+ });
30866
+ }).catch((err) => {
30867
+ logger38.log({
30868
+ level: "error",
30869
+ message: `Failed to set cache for office by id: ${err.message}`
30870
+ });
30871
+ });
30872
+ return result;
30873
+ } catch (error) {
30874
+ if (error instanceof AppError19) {
30875
+ throw error;
30876
+ } else {
30877
+ throw new InternalServerError29("Failed to get office.");
30878
+ }
30879
+ }
30880
+ }
30881
+ async function deleteById(_id, session) {
30882
+ try {
30883
+ _id = new ObjectId49(_id);
30884
+ } catch (error) {
30885
+ throw new BadRequestError79("Invalid ID.");
30886
+ }
30887
+ try {
30888
+ const res = await collection.updateOne(
30889
+ { _id },
30890
+ { $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
30891
+ );
30892
+ delCachedData();
30893
+ return res;
30894
+ } catch (error) {
30895
+ logger38.log({
30896
+ level: "error",
30897
+ message: error.message
30898
+ });
30899
+ if (error instanceof AppError19) {
30900
+ throw error;
30901
+ } else {
30902
+ throw new InternalServerError29("Failed to delete office.");
30903
+ }
30904
+ }
30905
+ }
30906
+ function delCachedData() {
30907
+ delNamespace().then(() => {
30908
+ logger38.log({
30909
+ level: "info",
30910
+ message: `Cache namespace cleared for ${namespace_collection}`
30911
+ });
30912
+ }).catch((err) => {
30913
+ logger38.log({
30914
+ level: "error",
30915
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
30916
+ });
30917
+ });
30918
+ }
30919
+ return {
30920
+ createIndexes,
30921
+ add,
30922
+ getAll,
30923
+ getById,
30924
+ updateById,
30925
+ deleteById,
30926
+ delCachedData
30927
+ };
30928
+ }
30929
+
30930
+ // src/services/office.service.ts
30931
+ import { BadRequestError as BadRequestError80, useAtlas as useAtlas41, logger as logger39 } from "@eeplatform/nodejs-utils";
30932
+ import * as XLSX3 from "xlsx";
30933
+ import * as Papa3 from "papaparse";
30934
+ function useOfficeService() {
30935
+ const { add: addOffice, delCachedData } = useOfficeRepo();
30936
+ async function addBulk(file) {
30937
+ logger39.log({
30938
+ level: "info",
30939
+ message: `Starting office bulk upload. File: ${file.originalname}, Size: ${file.size} bytes`
30940
+ });
30941
+ const MAX_SIZE = 16 * 1024 * 1024;
30942
+ let offices = [];
30943
+ let totalSize = 0;
30944
+ let validatedOffices = [];
30945
+ if (!file.buffer) {
30946
+ throw new BadRequestError80("File buffer is empty or corrupted");
30947
+ }
30948
+ try {
30949
+ const fileExtension = file.originalname.split(".").pop()?.toLowerCase();
30950
+ if (fileExtension === "csv") {
30951
+ const csvData = file.buffer.toString("utf-8");
30952
+ totalSize = Buffer.byteLength(csvData, "utf8");
30953
+ if (totalSize > MAX_SIZE) {
30954
+ throw new BadRequestError80(
30955
+ `File size exceeds limit. Maximum allowed: ${MAX_SIZE / 1024 / 1024}MB, Received: ${(totalSize / 1024 / 1024).toFixed(2)}MB`
30956
+ );
30957
+ }
30958
+ const parseResult = Papa3.parse(csvData, {
30959
+ header: true,
30960
+ skipEmptyLines: true,
30961
+ transformHeader: (header) => {
30962
+ return header.toLowerCase().replace(/\s+/g, "").replace(/[^\w]/g, "");
30963
+ }
30964
+ });
30965
+ if (parseResult.errors.length > 0) {
30966
+ throw new BadRequestError80(
30967
+ `CSV parsing errors: ${parseResult.errors.map((e) => e.message).join(", ")}`
30968
+ );
30969
+ }
30970
+ offices = parseResult.data || [];
30971
+ } else if (["xlsx", "xls"].includes(fileExtension || "")) {
30972
+ totalSize = file.buffer.length;
30973
+ if (totalSize > MAX_SIZE) {
30974
+ throw new BadRequestError80(
30975
+ `File size exceeds limit. Maximum allowed: ${MAX_SIZE / 1024 / 1024}MB, Received: ${(totalSize / 1024 / 1024).toFixed(2)}MB`
30976
+ );
30977
+ }
30978
+ const workbook = XLSX3.read(file.buffer, { type: "buffer" });
30979
+ const sheetName = workbook.SheetNames[0];
30980
+ if (!sheetName) {
30981
+ throw new BadRequestError80("Excel file contains no sheets");
30982
+ }
30983
+ const worksheet = workbook.Sheets[sheetName];
30984
+ offices = XLSX3.utils.sheet_to_json(worksheet, {
30985
+ header: 1,
30986
+ defval: ""
30987
+ });
30988
+ if (offices.length > 0) {
30989
+ const headers = offices[0];
30990
+ offices = offices.slice(1).map((row) => {
30991
+ const obj = {};
30992
+ headers.forEach((header, index) => {
30993
+ obj[header.trim()] = row[index] || "";
30994
+ });
30995
+ return obj;
30996
+ });
30997
+ }
30998
+ } else {
30999
+ throw new BadRequestError80(
31000
+ "Unsupported file format. Please upload CSV, XLS, or XLSX files."
31001
+ );
31002
+ }
31003
+ if (!offices || offices.length === 0) {
31004
+ throw new BadRequestError80("File is empty or contains no valid data");
31005
+ }
31006
+ const results = {
31007
+ total: offices.length,
31008
+ successful: 0,
31009
+ failed: 0,
31010
+ errors: []
31011
+ };
31012
+ logger39.log({
31013
+ level: "info",
31014
+ message: `Processing ${offices.length} offices from file`
31015
+ });
31016
+ for (let i = 0; i < offices.length; i++) {
31017
+ const officeData = offices[i];
31018
+ try {
31019
+ const cleanOffice = {
31020
+ name: String(officeData.name || "").trim(),
31021
+ code: String(officeData.code || "").trim(),
31022
+ type: String(officeData.type || "").trim(),
31023
+ path: String(officeData.path || "").trim(),
31024
+ status: String(officeData.status || "active").trim()
31025
+ };
31026
+ if (officeData.parent && String(officeData.parent).trim()) {
31027
+ cleanOffice.parent = String(officeData.parent).trim();
31028
+ }
31029
+ const { error } = schemaOffice.validate(cleanOffice);
31030
+ if (error) {
31031
+ results.errors.push(`Row ${i + 1}: ${error.message}`);
31032
+ results.failed++;
31033
+ continue;
31034
+ }
31035
+ validatedOffices.push(cleanOffice);
31036
+ } catch (error) {
31037
+ results.errors.push(`Row ${i + 1}: ${error.message}`);
31038
+ results.failed++;
31039
+ }
31040
+ }
31041
+ if (validatedOffices.length === 0) {
31042
+ throw new BadRequestError80(
31043
+ "No valid offices found in file. Please check the format and data."
31044
+ );
31045
+ }
31046
+ const db = useAtlas41.getDb();
31047
+ if (!db) {
31048
+ throw new Error("Database connection not available");
31049
+ }
31050
+ const session = db.client.startSession();
31051
+ try {
31052
+ await session.withTransaction(async () => {
31053
+ const batchSize = 100;
31054
+ for (let i = 0; i < validatedOffices.length; i += batchSize) {
31055
+ const batch = validatedOffices.slice(i, i + batchSize);
31056
+ for (const office of batch) {
31057
+ try {
31058
+ await addOffice(office, session, false);
31059
+ results.successful++;
31060
+ } catch (error) {
31061
+ results.failed++;
31062
+ results.errors.push(
31063
+ `Failed to insert office "${office.name}": ${error.message}`
31064
+ );
31065
+ logger39.log({
31066
+ level: "error",
31067
+ message: `Failed to insert office: ${error.message}`
31068
+ });
31069
+ }
31070
+ }
31071
+ }
31072
+ });
31073
+ delCachedData();
31074
+ logger39.log({
31075
+ level: "info",
31076
+ message: `Bulk upload completed. Successful: ${results.successful}, Failed: ${results.failed}`
31077
+ });
31078
+ return results;
31079
+ } catch (error) {
31080
+ logger39.log({
31081
+ level: "error",
31082
+ message: `Transaction failed: ${error.message}`
31083
+ });
31084
+ throw new BadRequestError80(`Bulk upload failed: ${error.message}`);
31085
+ } finally {
31086
+ await session.endSession();
31087
+ }
31088
+ } catch (error) {
31089
+ logger39.log({
31090
+ level: "error",
31091
+ message: `Bulk office upload failed: ${error.message}`
31092
+ });
31093
+ if (error instanceof BadRequestError80) {
31094
+ throw error;
31095
+ }
31096
+ throw new BadRequestError80(`File processing failed: ${error.message}`);
31097
+ }
31098
+ }
31099
+ return {
31100
+ addBulk
31101
+ };
31102
+ }
31103
+
31104
+ // src/controllers/office.controller.ts
31105
+ import { BadRequestError as BadRequestError81 } from "@eeplatform/nodejs-utils";
31106
+ import Joi44 from "joi";
31107
+ function useOfficeController() {
31108
+ const {
31109
+ add: _add,
31110
+ getAll: _getAll,
31111
+ getById: _getById,
31112
+ updateById: _updateByIdById,
31113
+ deleteById: _deleteByIdById
31114
+ } = useOfficeRepo();
31115
+ const { addBulk: _addBulk } = useOfficeService();
31116
+ async function add(req, res, next) {
31117
+ const value = req.body;
31118
+ const validation = Joi44.object({
31119
+ name: Joi44.string().required(),
31120
+ code: Joi44.string().required(),
31121
+ type: Joi44.string().required(),
31122
+ path: Joi44.string().required(),
31123
+ parent: Joi44.string().hex().optional().allow(null, ""),
31124
+ status: Joi44.string().optional().allow(null, "")
31125
+ });
31126
+ const { error } = validation.validate(value);
31127
+ if (error) {
31128
+ next(new BadRequestError81(error.message));
31129
+ return;
31130
+ }
31131
+ try {
31132
+ const id = await _add(value);
31133
+ res.json({ message: "Office created successfully", id });
31134
+ return;
31135
+ } catch (error2) {
31136
+ next(error2);
31137
+ }
31138
+ }
31139
+ async function getAll(req, res, next) {
31140
+ const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
31141
+ const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
31142
+ const search = req.query.search ?? "";
31143
+ const type = req.query.type ?? "";
31144
+ const parent = req.query.parent ?? "";
31145
+ const status = req.query.status ?? "active";
31146
+ const isPageNumber = isFinite(page);
31147
+ if (!isPageNumber) {
31148
+ next(new BadRequestError81("Invalid page number."));
31149
+ return;
31150
+ }
31151
+ const isLimitNumber = isFinite(limit);
31152
+ if (!isLimitNumber) {
31153
+ next(new BadRequestError81("Invalid limit number."));
31154
+ return;
31155
+ }
31156
+ const validation = Joi44.object({
31157
+ page: Joi44.number().min(1).optional().allow("", null),
31158
+ limit: Joi44.number().min(1).optional().allow("", null),
31159
+ search: Joi44.string().optional().allow("", null),
31160
+ type: Joi44.string().optional().allow("", null),
31161
+ parent: Joi44.string().optional().allow("", null),
31162
+ status: Joi44.string().optional().allow("", null)
31163
+ });
31164
+ const { error } = validation.validate({
31165
+ page,
31166
+ limit,
31167
+ search,
31168
+ type,
31169
+ parent,
31170
+ status
31171
+ });
31172
+ if (error) {
31173
+ next(new BadRequestError81(error.message));
31174
+ return;
31175
+ }
31176
+ try {
31177
+ const offices = await _getAll({
31178
+ search,
31179
+ page,
31180
+ limit,
31181
+ type,
31182
+ parent,
31183
+ status
31184
+ });
31185
+ res.json(offices);
31186
+ return;
31187
+ } catch (error2) {
31188
+ next(error2);
31189
+ }
31190
+ }
31191
+ async function getById(req, res, next) {
31192
+ const id = req.params.id;
31193
+ const validation = Joi44.object({
31194
+ id: Joi44.string().hex().required()
31195
+ });
31196
+ const { error } = validation.validate({ id });
31197
+ if (error) {
31198
+ next(new BadRequestError81(error.message));
31199
+ return;
31200
+ }
31201
+ try {
31202
+ const office = await _getById(id);
31203
+ if (!office) {
31204
+ next(new BadRequestError81("Office not found."));
31205
+ return;
31206
+ }
31207
+ res.json(office);
31208
+ return;
31209
+ } catch (error2) {
31210
+ next(error2);
31211
+ }
31212
+ }
31213
+ async function updateById(req, res, next) {
31214
+ const id = req.params.id;
31215
+ const value = req.body;
31216
+ const validation = Joi44.object({
31217
+ id: Joi44.string().hex().required(),
31218
+ name: Joi44.string().optional(),
31219
+ code: Joi44.string().optional(),
31220
+ type: Joi44.string().optional(),
31221
+ parent: Joi44.string().hex().optional().allow(null, ""),
31222
+ path: Joi44.string().optional(),
31223
+ status: Joi44.string().optional()
31224
+ });
31225
+ const { error } = validation.validate({ id, ...value });
31226
+ if (error) {
31227
+ next(new BadRequestError81(error.message));
31228
+ return;
31229
+ }
31230
+ try {
31231
+ const result = await _updateByIdById(id, value);
31232
+ if (result.matchedCount === 0) {
31233
+ next(new BadRequestError81("Office not found."));
31234
+ return;
31235
+ }
31236
+ res.json({ message: "Office updated successfully" });
31237
+ return;
31238
+ } catch (error2) {
31239
+ next(error2);
31240
+ }
31241
+ }
31242
+ async function deleteById(req, res, next) {
31243
+ const id = req.params.id;
31244
+ const validation = Joi44.object({
31245
+ id: Joi44.string().hex().required()
31246
+ });
31247
+ const { error } = validation.validate({ id });
31248
+ if (error) {
31249
+ next(new BadRequestError81(error.message));
31250
+ return;
31251
+ }
31252
+ try {
31253
+ const result = await _deleteByIdById(id);
31254
+ if (result.matchedCount === 0) {
31255
+ next(new BadRequestError81("Office not found."));
31256
+ return;
31257
+ }
31258
+ res.json({ message: "Office deleted successfully" });
31259
+ return;
31260
+ } catch (error2) {
31261
+ next(error2);
31262
+ }
31263
+ }
31264
+ async function bulkAddOffices(req, res, next) {
31265
+ if (!req.file) {
31266
+ res.status(400).send("File is required!");
31267
+ return;
31268
+ }
31269
+ try {
31270
+ const result = await _addBulk(req.file);
31271
+ res.status(201).json(result);
31272
+ return;
31273
+ } catch (error) {
31274
+ next(error);
31275
+ return;
31276
+ }
31277
+ }
31278
+ return {
31279
+ add,
31280
+ getAll,
31281
+ getById,
31282
+ updateById,
31283
+ deleteById,
31284
+ bulkAddOffices
31285
+ };
31286
+ }
31287
+
31288
+ // src/models/curriculum.model.ts
31289
+ import { BadRequestError as BadRequestError82, logger as logger40 } from "@eeplatform/nodejs-utils";
31290
+ import Joi45 from "joi";
31291
+ import { ObjectId as ObjectId50 } from "mongodb";
31292
+ var schemaCurriculum = Joi45.object({
31293
+ _id: Joi45.string().hex().optional(),
31294
+ school: Joi45.string().hex().required(),
31295
+ code: Joi45.string().required(),
31296
+ educationLevel: Joi45.string().required(),
31297
+ gradeLevel: Joi45.string().required(),
31298
+ subjectCode: Joi45.string().required(),
31299
+ subjectName: Joi45.string().required(),
31300
+ subjectType: Joi45.string().required(),
31301
+ sessionFrequency: Joi45.number().integer().min(0).required(),
31302
+ sessionDuration: Joi45.number().integer().min(0).required(),
31303
+ totalMinutesPerWeek: Joi45.number().integer().min(0).required(),
31304
+ curriculumMemoRef: Joi45.string().optional().allow("", null),
31305
+ status: Joi45.string().optional().allow("", null),
31306
+ createdAt: Joi45.date().optional().allow("", null),
31307
+ updatedAt: Joi45.date().optional().allow("", null),
31308
+ deletedAt: Joi45.date().optional().allow("", null),
31309
+ createdBy: Joi45.string().optional().allow("", null),
31310
+ updatedBy: Joi45.string().optional().allow("", null),
31311
+ deletedBy: Joi45.string().optional().allow("", null)
31312
+ });
31313
+ function MCurriculum(value) {
31314
+ const { error } = schemaCurriculum.validate(value);
31315
+ if (error) {
31316
+ logger40.info(`Curriculum Model: ${error.message}`);
31317
+ throw new BadRequestError82(error.message);
31318
+ }
31319
+ if (value._id && typeof value._id === "string") {
31320
+ try {
31321
+ value._id = new ObjectId50(value._id);
31322
+ } catch (error2) {
31323
+ throw new BadRequestError82("Invalid _id format");
31324
+ }
31325
+ }
31326
+ return {
31327
+ _id: value._id ?? void 0,
31328
+ school: value.school ?? "",
31329
+ code: value.code ?? "",
31330
+ educationLevel: value.educationLevel ?? "",
31331
+ gradeLevel: value.gradeLevel ?? "",
31332
+ subjectCode: value.subjectCode ?? "",
31333
+ subjectName: value.subjectName ?? "",
31334
+ subjectType: value.subjectType ?? "",
31335
+ sessionFrequency: value.sessionFrequency ?? 0,
31336
+ sessionDuration: value.sessionDuration ?? 0,
31337
+ totalMinutesPerWeek: value.totalMinutesPerWeek ?? 0,
31338
+ curriculumMemoRef: value.curriculumMemoRef ?? "",
31339
+ status: value.status ?? "active",
31340
+ createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
31341
+ updatedAt: value.updatedAt ?? "",
31342
+ deletedAt: value.deletedAt ?? "",
31343
+ createdBy: value.createdBy ?? "",
31344
+ updatedBy: value.updatedBy ?? "",
31345
+ deletedBy: value.deletedBy ?? ""
31346
+ };
31347
+ }
31348
+
31349
+ // src/repositories/curriculum.repository.ts
31350
+ import {
31351
+ AppError as AppError20,
31352
+ BadRequestError as BadRequestError83,
31353
+ InternalServerError as InternalServerError30,
31354
+ logger as logger41,
31355
+ makeCacheKey as makeCacheKey25,
31356
+ paginate as paginate21,
31357
+ useAtlas as useAtlas42,
31358
+ useCache as useCache26
31359
+ } from "@eeplatform/nodejs-utils";
31360
+ import { ObjectId as ObjectId51 } from "mongodb";
31361
+ function useCurriculumRepo() {
31362
+ const db = useAtlas42.getDb();
31363
+ if (!db) {
31364
+ throw new Error("Unable to connect to server.");
31365
+ }
31366
+ const namespace_collection = "school.curriculums";
31367
+ const collection = db.collection(namespace_collection);
31368
+ const { getCache, setCache, delNamespace } = useCache26(namespace_collection);
31369
+ async function createIndexes() {
31370
+ try {
31371
+ await collection.createIndexes([
31372
+ { key: { code: 1 }, unique: true, name: "unique_code_index" },
31373
+ { key: { educationLevel: 1 } },
31374
+ { key: { gradeLevel: 1 } },
31375
+ { key: { subjectCode: 1 } },
31376
+ { key: { status: 1 } }
31377
+ ]);
31378
+ } catch (error) {
31379
+ throw new Error("Failed to create index on curriculums.");
31380
+ }
31381
+ }
31382
+ async function add(value, session) {
31383
+ try {
31384
+ value = MCurriculum(value);
31385
+ const res = await collection.insertOne(value, { session });
31386
+ delCachedData();
31387
+ return res.insertedId;
31388
+ } catch (error) {
31389
+ logger41.log({
31390
+ level: "error",
31391
+ message: error.message
31392
+ });
31393
+ if (error instanceof AppError20) {
31394
+ throw error;
31395
+ } else {
31396
+ const isDuplicated = error.message.includes("duplicate");
31397
+ if (isDuplicated) {
31398
+ throw new BadRequestError83("Curriculum already exists.");
31399
+ }
31400
+ throw new Error("Failed to create curriculum.");
31401
+ }
31402
+ }
31403
+ }
31404
+ async function updateById(_id, value, session) {
31405
+ try {
31406
+ _id = new ObjectId51(_id);
31407
+ } catch (error) {
31408
+ throw new BadRequestError83("Invalid ID.");
31409
+ }
31410
+ try {
31411
+ const res = await collection.updateOne(
31412
+ { _id },
31413
+ { $set: { ...value, updatedAt: /* @__PURE__ */ new Date() } },
31414
+ { session }
31415
+ );
31416
+ delCachedData();
31417
+ return res;
31418
+ } catch (error) {
31419
+ logger41.log({
31420
+ level: "error",
31421
+ message: error.message
31422
+ });
31423
+ if (error instanceof AppError20) {
31424
+ throw error;
31425
+ } else {
31426
+ throw new Error("Failed to update curriculum.");
31427
+ }
31428
+ }
31429
+ }
31430
+ async function getAll({
31431
+ search = "",
31432
+ page = 1,
31433
+ limit = 10,
31434
+ sort = {},
31435
+ educationLevel = "",
31436
+ gradeLevel = "",
31437
+ subjectCode = "",
31438
+ status = "active"
31439
+ } = {}) {
31440
+ page = page > 0 ? page - 1 : 0;
31441
+ const query = {
31442
+ status
31443
+ };
31444
+ sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
31445
+ if (search) {
31446
+ query.$or = [
31447
+ { code: { $regex: search, $options: "i" } },
31448
+ { subjectName: { $regex: search, $options: "i" } },
31449
+ { subjectCode: { $regex: search, $options: "i" } }
31450
+ ];
31451
+ }
31452
+ if (educationLevel) {
31453
+ query.educationLevel = educationLevel;
31454
+ }
31455
+ if (gradeLevel) {
31456
+ query.gradeLevel = gradeLevel;
31457
+ }
31458
+ if (subjectCode) {
31459
+ query.subjectCode = subjectCode;
31460
+ }
31461
+ const cacheParams = {
31462
+ page,
31463
+ limit,
31464
+ sort: JSON.stringify(sort)
31465
+ };
31466
+ if (search)
31467
+ cacheParams.search = search;
31468
+ if (educationLevel)
31469
+ cacheParams.educationLevel = educationLevel;
31470
+ if (gradeLevel)
31471
+ cacheParams.gradeLevel = gradeLevel;
31472
+ if (subjectCode)
31473
+ cacheParams.subjectCode = subjectCode;
31474
+ if (status !== "active")
31475
+ cacheParams.status = status;
31476
+ const cacheKey = makeCacheKey25(namespace_collection, cacheParams);
31477
+ logger41.log({
31478
+ level: "info",
31479
+ message: `Cache key for getAll curriculums: ${cacheKey}`
31480
+ });
31481
+ try {
31482
+ const cached = await getCache(cacheKey);
31483
+ if (cached) {
31484
+ logger41.log({
31485
+ level: "info",
31486
+ message: `Cache hit for getAll curriculums: ${cacheKey}`
31487
+ });
31488
+ return cached;
31489
+ }
31490
+ const items = await collection.aggregate([
31491
+ { $match: query },
31492
+ { $sort: sort },
31493
+ { $skip: page * limit },
31494
+ { $limit: limit }
31495
+ ]).toArray();
31496
+ const length = await collection.countDocuments(query);
31497
+ const data = paginate21(items, page, limit, length);
31498
+ setCache(cacheKey, data, 600).then(() => {
31499
+ logger41.log({
31500
+ level: "info",
31501
+ message: `Cache set for getAll curriculums: ${cacheKey}`
31502
+ });
31503
+ }).catch((err) => {
31504
+ logger41.log({
31505
+ level: "error",
31506
+ message: `Failed to set cache for getAll curriculums: ${err.message}`
31507
+ });
31508
+ });
31509
+ return data;
31510
+ } catch (error) {
31511
+ logger41.log({ level: "error", message: `${error}` });
31512
+ throw error;
31513
+ }
31514
+ }
31515
+ async function getById(_id) {
31516
+ try {
31517
+ _id = new ObjectId51(_id);
31518
+ } catch (error) {
31519
+ throw new BadRequestError83("Invalid ID.");
31520
+ }
31521
+ const cacheKey = makeCacheKey25(namespace_collection, { _id: String(_id) });
31522
+ try {
31523
+ const cached = await getCache(cacheKey);
31524
+ if (cached) {
31525
+ logger41.log({
31526
+ level: "info",
31527
+ message: `Cache hit for getById curriculum: ${cacheKey}`
31528
+ });
31529
+ return cached;
31530
+ }
31531
+ const result = await collection.findOne({
31532
+ _id
31533
+ });
31534
+ setCache(cacheKey, result, 300).then(() => {
31535
+ logger41.log({
31536
+ level: "info",
31537
+ message: `Cache set for curriculum by id: ${cacheKey}`
31538
+ });
31539
+ }).catch((err) => {
31540
+ logger41.log({
31541
+ level: "error",
31542
+ message: `Failed to set cache for curriculum by id: ${err.message}`
31543
+ });
31544
+ });
31545
+ return result;
31546
+ } catch (error) {
31547
+ if (error instanceof AppError20) {
31548
+ throw error;
31549
+ } else {
31550
+ throw new InternalServerError30("Failed to get curriculum.");
31551
+ }
31552
+ }
31553
+ }
31554
+ async function deleteById(_id, session) {
31555
+ try {
31556
+ _id = new ObjectId51(_id);
31557
+ } catch (error) {
31558
+ throw new BadRequestError83("Invalid ID.");
31559
+ }
31560
+ try {
31561
+ const res = await collection.updateOne(
31562
+ { _id },
31563
+ { $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
31564
+ );
31565
+ delCachedData();
31566
+ return res;
31567
+ } catch (error) {
31568
+ logger41.log({
31569
+ level: "error",
31570
+ message: error.message
31571
+ });
31572
+ if (error instanceof AppError20) {
31573
+ throw error;
31574
+ } else {
31575
+ throw new InternalServerError30("Failed to delete curriculum.");
31576
+ }
31577
+ }
31578
+ }
31579
+ function delCachedData() {
31580
+ delNamespace().then(() => {
31581
+ logger41.log({
31582
+ level: "info",
31583
+ message: `Cache namespace cleared for ${namespace_collection}`
31584
+ });
31585
+ }).catch((err) => {
31586
+ logger41.log({
31587
+ level: "error",
31588
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
31589
+ });
31590
+ });
31591
+ }
31592
+ return {
31593
+ createIndexes,
31594
+ add,
31595
+ getAll,
31596
+ getById,
31597
+ updateById,
31598
+ deleteById
31599
+ };
31600
+ }
31601
+
31602
+ // src/controllers/curriculum.controller.ts
31603
+ import { BadRequestError as BadRequestError84, logger as logger42 } from "@eeplatform/nodejs-utils";
31604
+ import Joi46 from "joi";
31605
+ function useCurriculumController() {
31606
+ const {
31607
+ getAll: _getAll,
31608
+ getById: _getById,
31609
+ add: _add,
31610
+ updateById: _updateById,
31611
+ deleteById: _deleteById
31612
+ } = useCurriculumRepo();
31613
+ async function add(req, res, next) {
31614
+ const value = req.body;
31615
+ const validation = Joi46.object({
31616
+ code: Joi46.string().required(),
31617
+ school: Joi46.string().hex().required(),
31618
+ educationLevel: Joi46.string().required(),
31619
+ gradeLevel: Joi46.string().required(),
31620
+ subjectCode: Joi46.string().required(),
31621
+ subjectName: Joi46.string().required(),
31622
+ subjectType: Joi46.string().required(),
31623
+ sessionFrequency: Joi46.number().integer().min(0).required(),
31624
+ sessionDuration: Joi46.number().integer().min(0).required(),
31625
+ totalMinutesPerWeek: Joi46.number().integer().min(0).required(),
31626
+ curriculumMemoRef: Joi46.string().optional().allow("", null),
31627
+ status: Joi46.string().optional().allow("", null)
31628
+ });
31629
+ const { error } = validation.validate(value);
31630
+ if (error) {
31631
+ next(new BadRequestError84(error.message));
31632
+ logger42.info(`Controller: ${error.message}`);
31633
+ return;
31634
+ }
31635
+ try {
31636
+ const result = await _add(value);
31637
+ res.json(result);
31638
+ return;
31639
+ } catch (error2) {
31640
+ next(error2);
31641
+ }
31642
+ }
31643
+ async function updateById(req, res, next) {
31644
+ const value = req.body;
31645
+ const id = req.params.id ?? "";
31646
+ const validation = Joi46.object({
31647
+ id: Joi46.string().hex().required(),
31648
+ value: Joi46.object({
31649
+ code: Joi46.string().optional(),
31650
+ educationLevel: Joi46.string().optional(),
31651
+ gradeLevel: Joi46.string().optional(),
31652
+ subjectCode: Joi46.string().optional(),
31653
+ subjectName: Joi46.string().optional(),
31654
+ subjectType: Joi46.string().optional(),
31655
+ sessionFrequency: Joi46.number().integer().min(0).optional(),
31656
+ sessionDuration: Joi46.number().integer().min(0).optional(),
31657
+ totalMinutesPerWeek: Joi46.number().integer().min(0).optional(),
31658
+ curriculumMemoRef: Joi46.string().optional().allow("", null)
31659
+ }).min(1)
31660
+ });
31661
+ const { error } = validation.validate({ id, value });
31662
+ if (error) {
31663
+ next(new BadRequestError84(error.message));
31664
+ logger42.info(`Controller: ${error.message}`);
31665
+ return;
31666
+ }
31667
+ try {
31668
+ const result = await _updateById(id, value);
31669
+ res.json(result);
31670
+ return;
31671
+ } catch (error2) {
31672
+ next(error2);
31673
+ }
31674
+ }
31675
+ async function getAll(req, res, next) {
31676
+ const query = req.query;
31677
+ const validation = Joi46.object({
31678
+ page: Joi46.number().min(1).optional().allow("", null),
31679
+ limit: Joi46.number().min(1).optional().allow("", null),
31680
+ search: Joi46.string().optional().allow("", null),
31681
+ educationLevel: Joi46.string().optional().allow("", null),
31682
+ gradeLevel: Joi46.string().optional().allow("", null),
31683
+ subjectCode: Joi46.string().optional().allow("", null),
31684
+ status: Joi46.string().optional().allow("", null)
31685
+ });
31686
+ const { error } = validation.validate(query);
31687
+ if (error) {
31688
+ next(new BadRequestError84(error.message));
31689
+ return;
31690
+ }
31691
+ const page = parseInt(req.query.page) ?? 1;
31692
+ let limit = parseInt(req.query.limit) ?? 20;
31693
+ limit = isNaN(limit) ? 20 : limit;
31694
+ const sort = req.query.sort ? String(req.query.sort).split(",") : "";
31695
+ const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
31696
+ const sortObj = {};
31697
+ if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
31698
+ sort.forEach((field, index) => {
31699
+ sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
31700
+ });
31701
+ }
31702
+ const status = req.query.status ?? "active";
31703
+ const educationLevel = req.query.educationLevel ?? "";
31704
+ const gradeLevel = req.query.gradeLevel ?? "";
31705
+ const subjectCode = req.query.subjectCode ?? "";
31706
+ const search = req.query.search ?? "";
31707
+ try {
31708
+ const curriculums = await _getAll({
31709
+ page,
31710
+ limit,
31711
+ sort: sortObj,
31712
+ status,
31713
+ educationLevel,
31714
+ gradeLevel,
31715
+ subjectCode,
31716
+ search
31717
+ });
31718
+ res.json(curriculums);
31719
+ return;
31720
+ } catch (error2) {
31721
+ next(error2);
31722
+ }
31723
+ }
31724
+ async function getById(req, res, next) {
31725
+ const id = req.params.id;
31726
+ const validation = Joi46.object({
31727
+ id: Joi46.string().hex().required()
31728
+ });
31729
+ const { error } = validation.validate({ id });
31730
+ if (error) {
31731
+ next(new BadRequestError84(error.message));
31732
+ return;
31733
+ }
31734
+ try {
31735
+ const curriculum = await _getById(id);
31736
+ res.json({
31737
+ message: "Successfully retrieved curriculum.",
31738
+ data: { curriculum }
31739
+ });
31740
+ return;
31741
+ } catch (error2) {
31742
+ next(error2);
31743
+ }
31744
+ }
31745
+ async function deleteById(req, res, next) {
31746
+ const id = req.params.id;
31747
+ const validation = Joi46.object({
31748
+ id: Joi46.string().hex().required()
31749
+ });
31750
+ const { error } = validation.validate({ id });
31751
+ if (error) {
31752
+ next(new BadRequestError84(error.message));
31753
+ return;
31754
+ }
31755
+ try {
31756
+ const result = await _deleteById(id);
31757
+ res.json({
31758
+ message: "Successfully deleted curriculum.",
31759
+ data: result
31760
+ });
31761
+ return;
31762
+ } catch (error2) {
31763
+ next(error2);
31764
+ }
31765
+ }
31766
+ return {
31767
+ add,
31768
+ getAll,
31769
+ getById,
31770
+ updateById,
31771
+ deleteById
31772
+ };
31773
+ }
30618
31774
  export {
30619
31775
  ACCESS_TOKEN_EXPIRY,
30620
31776
  ACCESS_TOKEN_SECRET,
@@ -30636,12 +31792,14 @@ export {
30636
31792
  MAsset,
30637
31793
  MBuilding,
30638
31794
  MBuildingUnit,
31795
+ MCurriculum,
30639
31796
  MDivision,
30640
31797
  MEntity,
30641
31798
  MFile,
30642
31799
  MMember,
30643
31800
  MONGO_DB,
30644
31801
  MONGO_URI,
31802
+ MOffice,
30645
31803
  MOrder,
30646
31804
  MOrg,
30647
31805
  MPaymentMethod,
@@ -30682,7 +31840,9 @@ export {
30682
31840
  schemaAssetUpdateOption,
30683
31841
  schemaBuilding,
30684
31842
  schemaBuildingUnit,
31843
+ schemaCurriculum,
30685
31844
  schemaDivision,
31845
+ schemaOffice,
30686
31846
  schemaPlantilla,
30687
31847
  schemaRegion,
30688
31848
  schemaSchool,
@@ -30700,6 +31860,8 @@ export {
30700
31860
  useBuildingUnitRepo,
30701
31861
  useCounterModel,
30702
31862
  useCounterRepo,
31863
+ useCurriculumController,
31864
+ useCurriculumRepo,
30703
31865
  useDivisionController,
30704
31866
  useDivisionRepo,
30705
31867
  useDivisionService,
@@ -30715,6 +31877,9 @@ export {
30715
31877
  useInvoiceService,
30716
31878
  useMemberController,
30717
31879
  useMemberRepo,
31880
+ useOfficeController,
31881
+ useOfficeRepo,
31882
+ useOfficeService,
30718
31883
  useOrderController,
30719
31884
  useOrderRepo,
30720
31885
  useOrgController,