@eeplatform/core 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +111 -1
- package/dist/index.js +1124 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1141 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -27066,6 +27066,7 @@ var schemaBuildingUnit = Joi33.object({
|
|
|
27066
27066
|
var schemaUpdateOptions = Joi33.object({
|
|
27067
27067
|
name: Joi33.string().optional().allow("", null),
|
|
27068
27068
|
building: Joi33.string().hex().optional().allow("", null),
|
|
27069
|
+
buildingName: Joi33.string().optional().allow("", null),
|
|
27069
27070
|
level: Joi33.number().integer().min(1).optional().allow("", null),
|
|
27070
27071
|
category: Joi33.string().optional().allow("", null),
|
|
27071
27072
|
type: Joi33.string().optional().allow("", null),
|
|
@@ -27492,6 +27493,36 @@ function useBuildingUnitRepo() {
|
|
|
27492
27493
|
}
|
|
27493
27494
|
}
|
|
27494
27495
|
}
|
|
27496
|
+
async function updateByBuildingId(building, value, session) {
|
|
27497
|
+
const { error } = schemaUpdateOptions.validate(value);
|
|
27498
|
+
if (error) {
|
|
27499
|
+
throw new BadRequestError61(error.message);
|
|
27500
|
+
}
|
|
27501
|
+
try {
|
|
27502
|
+
building = new ObjectId41(building);
|
|
27503
|
+
} catch (error2) {
|
|
27504
|
+
throw new BadRequestError61("Invalid building ID.");
|
|
27505
|
+
}
|
|
27506
|
+
try {
|
|
27507
|
+
const res = await collection.updateMany(
|
|
27508
|
+
{ building },
|
|
27509
|
+
{ $set: value },
|
|
27510
|
+
{ session }
|
|
27511
|
+
);
|
|
27512
|
+
delCachedData();
|
|
27513
|
+
return res;
|
|
27514
|
+
} catch (error2) {
|
|
27515
|
+
logger31.log({
|
|
27516
|
+
level: "error",
|
|
27517
|
+
message: error2.message
|
|
27518
|
+
});
|
|
27519
|
+
if (error2 instanceof AppError15) {
|
|
27520
|
+
throw error2;
|
|
27521
|
+
} else {
|
|
27522
|
+
throw new Error("Failed to update building unit.");
|
|
27523
|
+
}
|
|
27524
|
+
}
|
|
27525
|
+
}
|
|
27495
27526
|
async function getAll({
|
|
27496
27527
|
search = "",
|
|
27497
27528
|
page = 1,
|
|
@@ -27739,7 +27770,8 @@ function useBuildingUnitRepo() {
|
|
|
27739
27770
|
getByBuildingLevel,
|
|
27740
27771
|
updateById,
|
|
27741
27772
|
getByBuilding,
|
|
27742
|
-
deleteById
|
|
27773
|
+
deleteById,
|
|
27774
|
+
updateByBuildingId
|
|
27743
27775
|
};
|
|
27744
27776
|
}
|
|
27745
27777
|
|
|
@@ -27748,20 +27780,25 @@ import { BadRequestError as BadRequestError63, logger as logger32 } from "@eepla
|
|
|
27748
27780
|
import Joi34 from "joi";
|
|
27749
27781
|
|
|
27750
27782
|
// src/services/building.service.ts
|
|
27751
|
-
import {
|
|
27783
|
+
import {
|
|
27784
|
+
BadRequestError as BadRequestError62,
|
|
27785
|
+
NotFoundError as NotFoundError10,
|
|
27786
|
+
useAtlas as useAtlas33
|
|
27787
|
+
} from "@eeplatform/nodejs-utils";
|
|
27752
27788
|
function useBuildingService() {
|
|
27753
27789
|
const {
|
|
27754
27790
|
updateById: _updateById,
|
|
27755
27791
|
getById: _getById,
|
|
27756
27792
|
deleteById: _deleteById
|
|
27757
27793
|
} = useBuildingRepo();
|
|
27758
|
-
const { getByBuildingLevel, getByBuilding } = useBuildingUnitRepo();
|
|
27794
|
+
const { getByBuildingLevel, getByBuilding, updateByBuildingId } = useBuildingUnitRepo();
|
|
27759
27795
|
async function updateById(id, data) {
|
|
27760
27796
|
data.levels = Number(data.levels);
|
|
27797
|
+
const session = useAtlas33.getClient()?.startSession();
|
|
27761
27798
|
try {
|
|
27762
27799
|
const building = await _getById(id);
|
|
27763
27800
|
if (!building) {
|
|
27764
|
-
throw new
|
|
27801
|
+
throw new NotFoundError10("Building not found.");
|
|
27765
27802
|
}
|
|
27766
27803
|
if (data.levels < building.levels) {
|
|
27767
27804
|
const unit = await getByBuildingLevel(id, building.levels);
|
|
@@ -27771,10 +27808,18 @@ function useBuildingService() {
|
|
|
27771
27808
|
);
|
|
27772
27809
|
}
|
|
27773
27810
|
}
|
|
27774
|
-
|
|
27811
|
+
session?.startTransaction();
|
|
27812
|
+
if (building.name !== data.name) {
|
|
27813
|
+
await updateByBuildingId(id, { buildingName: data.name }, session);
|
|
27814
|
+
}
|
|
27815
|
+
const result = await _updateById(id, data, session);
|
|
27816
|
+
await session?.commitTransaction();
|
|
27775
27817
|
return result;
|
|
27776
27818
|
} catch (error) {
|
|
27819
|
+
await session?.abortTransaction();
|
|
27777
27820
|
throw error;
|
|
27821
|
+
} finally {
|
|
27822
|
+
session?.endSession();
|
|
27778
27823
|
}
|
|
27779
27824
|
}
|
|
27780
27825
|
async function deleteById(id) {
|
|
@@ -27945,11 +27990,11 @@ import { BadRequestError as BadRequestError64 } from "@eeplatform/nodejs-utils";
|
|
|
27945
27990
|
import Joi35 from "joi";
|
|
27946
27991
|
|
|
27947
27992
|
// src/services/building-unit.service.ts
|
|
27948
|
-
import { useAtlas as
|
|
27993
|
+
import { useAtlas as useAtlas34 } from "@eeplatform/nodejs-utils";
|
|
27949
27994
|
function useBuildingUnitService() {
|
|
27950
27995
|
const { add: _add } = useBuildingUnitRepo();
|
|
27951
27996
|
async function add(value) {
|
|
27952
|
-
const session =
|
|
27997
|
+
const session = useAtlas34.getClient()?.startSession();
|
|
27953
27998
|
if (!session) {
|
|
27954
27999
|
throw new Error("Unable to start session for building unit service.");
|
|
27955
28000
|
}
|
|
@@ -28131,6 +28176,1086 @@ function useBuildingUnitController() {
|
|
|
28131
28176
|
deleteById
|
|
28132
28177
|
};
|
|
28133
28178
|
}
|
|
28179
|
+
|
|
28180
|
+
// src/models/asset.model.ts
|
|
28181
|
+
import { BadRequestError as BadRequestError65 } from "@eeplatform/nodejs-utils";
|
|
28182
|
+
import Joi36 from "joi";
|
|
28183
|
+
import { ObjectId as ObjectId42 } from "mongodb";
|
|
28184
|
+
var schemaAsset = Joi36.object({
|
|
28185
|
+
_id: Joi36.string().hex().optional(),
|
|
28186
|
+
school: Joi36.string().hex().required(),
|
|
28187
|
+
asset_type: Joi36.string().required().allow("supply", "furniture-equipment", "fixed-asset"),
|
|
28188
|
+
name: Joi36.string().required(),
|
|
28189
|
+
category: Joi36.string().optional().allow("", null),
|
|
28190
|
+
type: Joi36.string().optional().allow("", null),
|
|
28191
|
+
brand: Joi36.string().optional().allow("", null),
|
|
28192
|
+
unit: Joi36.string().required(),
|
|
28193
|
+
status: Joi36.string().optional().allow("", null),
|
|
28194
|
+
createdAt: Joi36.date().optional().allow("", null),
|
|
28195
|
+
updatedAt: Joi36.date().optional().allow("", null),
|
|
28196
|
+
deletedAt: Joi36.date().optional().allow("", null),
|
|
28197
|
+
metadata: Joi36.object({
|
|
28198
|
+
title: Joi36.string().optional().allow("", null),
|
|
28199
|
+
isbn: Joi36.string().optional().allow("", null),
|
|
28200
|
+
author: Joi36.string().optional().allow("", null),
|
|
28201
|
+
edition: Joi36.string().optional().allow("", null),
|
|
28202
|
+
subject: Joi36.string().optional().allow("", null),
|
|
28203
|
+
grade_level: Joi36.number().integer().min(0).optional().allow("", null),
|
|
28204
|
+
publisher: Joi36.string().optional().allow("", null),
|
|
28205
|
+
language: Joi36.string().optional().allow("", null)
|
|
28206
|
+
}).optional().allow(null)
|
|
28207
|
+
});
|
|
28208
|
+
var schemaAssetUpdateOption = Joi36.object({
|
|
28209
|
+
name: Joi36.string().optional().allow("", null),
|
|
28210
|
+
category: Joi36.string().optional().allow("", null),
|
|
28211
|
+
type: Joi36.string().optional().allow("", null),
|
|
28212
|
+
brand: Joi36.string().optional().allow("", null),
|
|
28213
|
+
qty: Joi36.number().integer().min(0).optional().allow("", null),
|
|
28214
|
+
unit: Joi36.string().optional().allow("", null),
|
|
28215
|
+
metadata: Joi36.object({
|
|
28216
|
+
title: Joi36.string().optional().allow("", null),
|
|
28217
|
+
isbn: Joi36.string().optional().allow("", null),
|
|
28218
|
+
author: Joi36.string().optional().allow("", null),
|
|
28219
|
+
edition: Joi36.string().optional().allow("", null),
|
|
28220
|
+
subject: Joi36.string().optional().allow("", null),
|
|
28221
|
+
grade_level: Joi36.number().integer().min(0).optional().allow("", null),
|
|
28222
|
+
publisher: Joi36.string().optional().allow("", null),
|
|
28223
|
+
language: Joi36.string().optional().allow("", null)
|
|
28224
|
+
}).optional().allow(null)
|
|
28225
|
+
});
|
|
28226
|
+
function MAsset(value) {
|
|
28227
|
+
const { error } = schemaAsset.validate(value);
|
|
28228
|
+
if (error) {
|
|
28229
|
+
throw new BadRequestError65(error.message);
|
|
28230
|
+
}
|
|
28231
|
+
if (value._id && typeof value._id === "string") {
|
|
28232
|
+
try {
|
|
28233
|
+
value._id = new ObjectId42();
|
|
28234
|
+
} catch (error2) {
|
|
28235
|
+
throw new BadRequestError65("Invalid ID.");
|
|
28236
|
+
}
|
|
28237
|
+
}
|
|
28238
|
+
try {
|
|
28239
|
+
value.school = new ObjectId42(value.school);
|
|
28240
|
+
} catch (error2) {
|
|
28241
|
+
throw new BadRequestError65("Invalid school ID.");
|
|
28242
|
+
}
|
|
28243
|
+
value.createdAt = value.createdAt ? new Date(value.createdAt) : /* @__PURE__ */ new Date();
|
|
28244
|
+
value.updatedAt = value.updatedAt ? new Date(value.updatedAt) : "";
|
|
28245
|
+
value.deletedAt = value.deletedAt ? new Date(value.deletedAt) : "";
|
|
28246
|
+
return {
|
|
28247
|
+
_id: value._id ?? new ObjectId42(),
|
|
28248
|
+
school: value.school,
|
|
28249
|
+
asset_type: value.asset_type ?? "supply",
|
|
28250
|
+
name: value.name,
|
|
28251
|
+
category: value.category ?? "",
|
|
28252
|
+
type: value.type ?? "",
|
|
28253
|
+
brand: value.brand ?? "",
|
|
28254
|
+
qty: value.qty ?? 0,
|
|
28255
|
+
condition: value.condition ?? {
|
|
28256
|
+
good: 0,
|
|
28257
|
+
disposal: 0,
|
|
28258
|
+
lost: 0,
|
|
28259
|
+
damaged: 0
|
|
28260
|
+
},
|
|
28261
|
+
unit: value.unit ?? "",
|
|
28262
|
+
status: value.status ?? "active",
|
|
28263
|
+
createdAt: value.createdAt,
|
|
28264
|
+
updatedAt: value.updatedAt,
|
|
28265
|
+
deletedAt: value.deletedAt,
|
|
28266
|
+
metadata: value.metadata ?? {}
|
|
28267
|
+
};
|
|
28268
|
+
}
|
|
28269
|
+
|
|
28270
|
+
// src/repositories/asset.repository.ts
|
|
28271
|
+
import {
|
|
28272
|
+
BadRequestError as BadRequestError66,
|
|
28273
|
+
logger as logger33,
|
|
28274
|
+
makeCacheKey as makeCacheKey21,
|
|
28275
|
+
paginate as paginate17,
|
|
28276
|
+
useAtlas as useAtlas35,
|
|
28277
|
+
useCache as useCache22
|
|
28278
|
+
} from "@eeplatform/nodejs-utils";
|
|
28279
|
+
import { ObjectId as ObjectId43 } from "mongodb";
|
|
28280
|
+
function useAssetRepo() {
|
|
28281
|
+
const db = useAtlas35.getDb();
|
|
28282
|
+
if (!db) {
|
|
28283
|
+
throw new BadRequestError66("Unable to connect to server.");
|
|
28284
|
+
}
|
|
28285
|
+
const namespace_collection = "school.assets";
|
|
28286
|
+
const collection = db.collection(namespace_collection);
|
|
28287
|
+
const { getCache, setCache, delNamespace } = useCache22(namespace_collection);
|
|
28288
|
+
function delCachedData() {
|
|
28289
|
+
delNamespace().then(() => {
|
|
28290
|
+
logger33.log({
|
|
28291
|
+
level: "info",
|
|
28292
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
28293
|
+
});
|
|
28294
|
+
}).catch((err) => {
|
|
28295
|
+
logger33.log({
|
|
28296
|
+
level: "error",
|
|
28297
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
28298
|
+
});
|
|
28299
|
+
});
|
|
28300
|
+
}
|
|
28301
|
+
async function createIndex() {
|
|
28302
|
+
try {
|
|
28303
|
+
await collection.createIndexes([
|
|
28304
|
+
{ key: { school: 1 } },
|
|
28305
|
+
{ key: { name: 1 } },
|
|
28306
|
+
{ key: { name: "text" } }
|
|
28307
|
+
]);
|
|
28308
|
+
} catch (error) {
|
|
28309
|
+
throw new BadRequestError66("Failed to create index on asset.");
|
|
28310
|
+
}
|
|
28311
|
+
}
|
|
28312
|
+
async function add(value) {
|
|
28313
|
+
try {
|
|
28314
|
+
value = MAsset(value);
|
|
28315
|
+
const res = await collection.insertOne(value);
|
|
28316
|
+
delCachedData();
|
|
28317
|
+
return res.insertedId;
|
|
28318
|
+
} catch (error) {
|
|
28319
|
+
throw new BadRequestError66("Failed to create asset item.");
|
|
28320
|
+
}
|
|
28321
|
+
}
|
|
28322
|
+
async function updateById(_id, value, session) {
|
|
28323
|
+
const { error } = schemaAssetUpdateOption.validate(value);
|
|
28324
|
+
if (error) {
|
|
28325
|
+
throw new BadRequestError66(error.message);
|
|
28326
|
+
}
|
|
28327
|
+
try {
|
|
28328
|
+
_id = new ObjectId43(_id);
|
|
28329
|
+
} catch (error2) {
|
|
28330
|
+
throw new BadRequestError66("Invalid ID.");
|
|
28331
|
+
}
|
|
28332
|
+
try {
|
|
28333
|
+
const res = await collection.updateOne(
|
|
28334
|
+
{ _id },
|
|
28335
|
+
{ $set: value },
|
|
28336
|
+
{ session }
|
|
28337
|
+
);
|
|
28338
|
+
if (res.modifiedCount) {
|
|
28339
|
+
delCachedData();
|
|
28340
|
+
}
|
|
28341
|
+
return "Successfully updated asset item.";
|
|
28342
|
+
} catch (error2) {
|
|
28343
|
+
throw new BadRequestError66("Failed to update asset item.");
|
|
28344
|
+
}
|
|
28345
|
+
}
|
|
28346
|
+
async function deleteById(_id) {
|
|
28347
|
+
try {
|
|
28348
|
+
_id = new ObjectId43(_id);
|
|
28349
|
+
} catch (error) {
|
|
28350
|
+
throw new BadRequestError66("Invalid ID.");
|
|
28351
|
+
}
|
|
28352
|
+
try {
|
|
28353
|
+
const res = await collection.deleteOne({ _id });
|
|
28354
|
+
if (res.deletedCount) {
|
|
28355
|
+
delCachedData();
|
|
28356
|
+
return "Successfully deleted asset item.";
|
|
28357
|
+
}
|
|
28358
|
+
return "Successfully deleted asset item.";
|
|
28359
|
+
} catch (error) {
|
|
28360
|
+
throw new BadRequestError66("Failed to delete asset item.");
|
|
28361
|
+
}
|
|
28362
|
+
}
|
|
28363
|
+
async function getById(_id) {
|
|
28364
|
+
try {
|
|
28365
|
+
_id = new ObjectId43(_id);
|
|
28366
|
+
} catch (error) {
|
|
28367
|
+
throw new BadRequestError66("Invalid ID.");
|
|
28368
|
+
}
|
|
28369
|
+
const cacheKey = makeCacheKey21(namespace_collection, { _id: String(_id) });
|
|
28370
|
+
const cachedData = await getCache(cacheKey);
|
|
28371
|
+
if (cachedData) {
|
|
28372
|
+
return cachedData;
|
|
28373
|
+
}
|
|
28374
|
+
try {
|
|
28375
|
+
const res = await collection.findOne({ _id });
|
|
28376
|
+
if (!res) {
|
|
28377
|
+
throw new BadRequestError66("Asset item not found.");
|
|
28378
|
+
}
|
|
28379
|
+
setCache(cacheKey, res).then(() => {
|
|
28380
|
+
logger33.log({
|
|
28381
|
+
level: "info",
|
|
28382
|
+
message: `Cache set for asset item by ID: ${cacheKey}`
|
|
28383
|
+
});
|
|
28384
|
+
}).catch((err) => {
|
|
28385
|
+
logger33.log({
|
|
28386
|
+
level: "error",
|
|
28387
|
+
message: `Failed to set cache for asset item by ID: ${cacheKey} - ${err.message}`
|
|
28388
|
+
});
|
|
28389
|
+
});
|
|
28390
|
+
return res;
|
|
28391
|
+
} catch (error) {
|
|
28392
|
+
if (error instanceof BadRequestError66) {
|
|
28393
|
+
throw error;
|
|
28394
|
+
}
|
|
28395
|
+
throw new BadRequestError66("Failed to retrieve asset item.");
|
|
28396
|
+
}
|
|
28397
|
+
}
|
|
28398
|
+
async function getAll({
|
|
28399
|
+
page = 1,
|
|
28400
|
+
search = "",
|
|
28401
|
+
limit = 20,
|
|
28402
|
+
status = "active",
|
|
28403
|
+
school = "",
|
|
28404
|
+
sort = { _id: -1 },
|
|
28405
|
+
asset_type = "supply"
|
|
28406
|
+
} = {}) {
|
|
28407
|
+
page = page ? page - 1 : 0;
|
|
28408
|
+
try {
|
|
28409
|
+
school = new ObjectId43(school);
|
|
28410
|
+
} catch (error) {
|
|
28411
|
+
throw new BadRequestError66("Invalid school ID.");
|
|
28412
|
+
}
|
|
28413
|
+
const query = {
|
|
28414
|
+
school,
|
|
28415
|
+
status,
|
|
28416
|
+
asset_type
|
|
28417
|
+
};
|
|
28418
|
+
const cacheKeyOptions = {
|
|
28419
|
+
page,
|
|
28420
|
+
limit,
|
|
28421
|
+
status,
|
|
28422
|
+
school: String(school),
|
|
28423
|
+
sort: JSON.stringify(sort),
|
|
28424
|
+
asset_type
|
|
28425
|
+
};
|
|
28426
|
+
if (search) {
|
|
28427
|
+
query.$text = { $search: search };
|
|
28428
|
+
cacheKeyOptions.search = search;
|
|
28429
|
+
}
|
|
28430
|
+
try {
|
|
28431
|
+
const cacheKey = makeCacheKey21(namespace_collection, cacheKeyOptions);
|
|
28432
|
+
const cached = await getCache(cacheKey);
|
|
28433
|
+
if (cached) {
|
|
28434
|
+
logger33.log({
|
|
28435
|
+
level: "info",
|
|
28436
|
+
message: `Cache hit for getAll asset items: ${cacheKey}`
|
|
28437
|
+
});
|
|
28438
|
+
return cached;
|
|
28439
|
+
}
|
|
28440
|
+
const items = await collection.aggregate([
|
|
28441
|
+
{ $match: query },
|
|
28442
|
+
{
|
|
28443
|
+
$sort: sort
|
|
28444
|
+
},
|
|
28445
|
+
{
|
|
28446
|
+
$skip: page * limit
|
|
28447
|
+
},
|
|
28448
|
+
{
|
|
28449
|
+
$limit: limit
|
|
28450
|
+
}
|
|
28451
|
+
]).toArray();
|
|
28452
|
+
const length = await collection.countDocuments(query);
|
|
28453
|
+
const data = paginate17(items, page, limit, length);
|
|
28454
|
+
setCache(cacheKey, data, 500).then(() => {
|
|
28455
|
+
logger33.log({
|
|
28456
|
+
level: "info",
|
|
28457
|
+
message: `Cache set for getAll asset items: ${cacheKey}`
|
|
28458
|
+
});
|
|
28459
|
+
}).catch((err) => {
|
|
28460
|
+
logger33.log({
|
|
28461
|
+
level: "error",
|
|
28462
|
+
message: `Failed to set cache for getAll asset items: ${err.message}`
|
|
28463
|
+
});
|
|
28464
|
+
});
|
|
28465
|
+
return data;
|
|
28466
|
+
} catch (error) {
|
|
28467
|
+
console.log("Error in getAll:", error);
|
|
28468
|
+
throw new BadRequestError66("Failed to retrieve asset items.");
|
|
28469
|
+
}
|
|
28470
|
+
}
|
|
28471
|
+
async function getCategories(school, asset_type) {
|
|
28472
|
+
try {
|
|
28473
|
+
school = new ObjectId43(school);
|
|
28474
|
+
} catch (error) {
|
|
28475
|
+
throw new BadRequestError66("Invalid school ID.");
|
|
28476
|
+
}
|
|
28477
|
+
const cacheKey = makeCacheKey21(namespace_collection, {
|
|
28478
|
+
school,
|
|
28479
|
+
asset_type,
|
|
28480
|
+
type: "category-as-options"
|
|
28481
|
+
});
|
|
28482
|
+
const cachedData = await getCache(cacheKey);
|
|
28483
|
+
if (cachedData) {
|
|
28484
|
+
return cachedData;
|
|
28485
|
+
}
|
|
28486
|
+
try {
|
|
28487
|
+
const categories = await collection.aggregate([
|
|
28488
|
+
{
|
|
28489
|
+
$match: { school, asset_type }
|
|
28490
|
+
},
|
|
28491
|
+
{
|
|
28492
|
+
$group: {
|
|
28493
|
+
_id: "$category",
|
|
28494
|
+
value: { $first: "$category" },
|
|
28495
|
+
title: {
|
|
28496
|
+
$first: "$category"
|
|
28497
|
+
}
|
|
28498
|
+
}
|
|
28499
|
+
},
|
|
28500
|
+
{
|
|
28501
|
+
$project: {
|
|
28502
|
+
_id: 0,
|
|
28503
|
+
title: 1,
|
|
28504
|
+
value: 1
|
|
28505
|
+
}
|
|
28506
|
+
},
|
|
28507
|
+
{ $sort: { title: 1 } }
|
|
28508
|
+
]).toArray();
|
|
28509
|
+
setCache(cacheKey, categories).then(() => {
|
|
28510
|
+
logger33.log({
|
|
28511
|
+
level: "info",
|
|
28512
|
+
message: `Cache set for getCategoriesBySchool: ${cacheKey}`
|
|
28513
|
+
});
|
|
28514
|
+
}).catch((err) => {
|
|
28515
|
+
logger33.log({
|
|
28516
|
+
level: "error",
|
|
28517
|
+
message: `Failed to set cache for getCategoriesBySchool: ${err.message}`
|
|
28518
|
+
});
|
|
28519
|
+
});
|
|
28520
|
+
return categories;
|
|
28521
|
+
} catch (error) {
|
|
28522
|
+
if (error instanceof BadRequestError66) {
|
|
28523
|
+
throw error;
|
|
28524
|
+
}
|
|
28525
|
+
throw new BadRequestError66("Failed to retrieve asset categories.");
|
|
28526
|
+
}
|
|
28527
|
+
}
|
|
28528
|
+
async function getTypes(school, asset_type) {
|
|
28529
|
+
try {
|
|
28530
|
+
school = new ObjectId43(school);
|
|
28531
|
+
} catch (error) {
|
|
28532
|
+
throw new BadRequestError66("Invalid school ID.");
|
|
28533
|
+
}
|
|
28534
|
+
const cacheKey = makeCacheKey21(namespace_collection, {
|
|
28535
|
+
school,
|
|
28536
|
+
asset_type,
|
|
28537
|
+
type: "types-as-options"
|
|
28538
|
+
});
|
|
28539
|
+
const cachedData = await getCache(cacheKey);
|
|
28540
|
+
if (cachedData) {
|
|
28541
|
+
return cachedData;
|
|
28542
|
+
}
|
|
28543
|
+
try {
|
|
28544
|
+
const categories = await collection.aggregate([
|
|
28545
|
+
{
|
|
28546
|
+
$match: { school, asset_type }
|
|
28547
|
+
},
|
|
28548
|
+
{
|
|
28549
|
+
$group: {
|
|
28550
|
+
_id: "$type",
|
|
28551
|
+
value: { $first: "$type" },
|
|
28552
|
+
category: { $first: "$category" },
|
|
28553
|
+
title: { $first: "$name" },
|
|
28554
|
+
subtitle: { $first: "" }
|
|
28555
|
+
// keep empty for now, can be filled later
|
|
28556
|
+
}
|
|
28557
|
+
},
|
|
28558
|
+
{
|
|
28559
|
+
$project: {
|
|
28560
|
+
_id: 0,
|
|
28561
|
+
title: 1,
|
|
28562
|
+
value: 1,
|
|
28563
|
+
category: 1,
|
|
28564
|
+
subtitle: 1
|
|
28565
|
+
}
|
|
28566
|
+
},
|
|
28567
|
+
{ $sort: { title: 1 } }
|
|
28568
|
+
]).toArray();
|
|
28569
|
+
setCache(cacheKey, categories).then(() => {
|
|
28570
|
+
logger33.log({
|
|
28571
|
+
level: "info",
|
|
28572
|
+
message: `Cache set for getCategoriesBySchool: ${cacheKey}`
|
|
28573
|
+
});
|
|
28574
|
+
}).catch((err) => {
|
|
28575
|
+
logger33.log({
|
|
28576
|
+
level: "error",
|
|
28577
|
+
message: `Failed to set cache for getCategoriesBySchool: ${err.message}`
|
|
28578
|
+
});
|
|
28579
|
+
});
|
|
28580
|
+
return categories;
|
|
28581
|
+
} catch (error) {
|
|
28582
|
+
if (error instanceof BadRequestError66) {
|
|
28583
|
+
throw error;
|
|
28584
|
+
}
|
|
28585
|
+
throw new BadRequestError66("Failed to retrieve asset categories.");
|
|
28586
|
+
}
|
|
28587
|
+
}
|
|
28588
|
+
async function getUnitsBySchool(school) {
|
|
28589
|
+
try {
|
|
28590
|
+
school = new ObjectId43(school);
|
|
28591
|
+
} catch (error) {
|
|
28592
|
+
throw new BadRequestError66("Invalid school ID.");
|
|
28593
|
+
}
|
|
28594
|
+
const cacheKey = makeCacheKey21(namespace_collection, {
|
|
28595
|
+
school,
|
|
28596
|
+
type: "unit-as-options"
|
|
28597
|
+
});
|
|
28598
|
+
const cachedData = await getCache(cacheKey);
|
|
28599
|
+
if (cachedData) {
|
|
28600
|
+
return cachedData;
|
|
28601
|
+
}
|
|
28602
|
+
try {
|
|
28603
|
+
const categories = await collection.aggregate([
|
|
28604
|
+
{
|
|
28605
|
+
$match: { school }
|
|
28606
|
+
},
|
|
28607
|
+
{
|
|
28608
|
+
$group: {
|
|
28609
|
+
_id: "$unit",
|
|
28610
|
+
value: { $first: "$unit" },
|
|
28611
|
+
title: {
|
|
28612
|
+
$first: "$unit"
|
|
28613
|
+
}
|
|
28614
|
+
}
|
|
28615
|
+
},
|
|
28616
|
+
{
|
|
28617
|
+
$project: {
|
|
28618
|
+
_id: 0,
|
|
28619
|
+
title: 1,
|
|
28620
|
+
value: 1
|
|
28621
|
+
}
|
|
28622
|
+
},
|
|
28623
|
+
{ $sort: { title: 1 } }
|
|
28624
|
+
]).toArray();
|
|
28625
|
+
setCache(cacheKey, categories).then(() => {
|
|
28626
|
+
logger33.log({
|
|
28627
|
+
level: "info",
|
|
28628
|
+
message: `Cache set for getUnitBy: ${cacheKey}`
|
|
28629
|
+
});
|
|
28630
|
+
}).catch((err) => {
|
|
28631
|
+
logger33.log({
|
|
28632
|
+
level: "error",
|
|
28633
|
+
message: `Failed to set cache for getUnitBy: ${err.message}`
|
|
28634
|
+
});
|
|
28635
|
+
});
|
|
28636
|
+
return categories;
|
|
28637
|
+
} catch (error) {
|
|
28638
|
+
console.log(error);
|
|
28639
|
+
if (error instanceof BadRequestError66) {
|
|
28640
|
+
throw error;
|
|
28641
|
+
}
|
|
28642
|
+
throw new BadRequestError66(
|
|
28643
|
+
"Failed to retrieve asset unit of measurements."
|
|
28644
|
+
);
|
|
28645
|
+
}
|
|
28646
|
+
}
|
|
28647
|
+
return {
|
|
28648
|
+
createIndex,
|
|
28649
|
+
add,
|
|
28650
|
+
updateById,
|
|
28651
|
+
deleteById,
|
|
28652
|
+
getById,
|
|
28653
|
+
getAll,
|
|
28654
|
+
getCategories,
|
|
28655
|
+
getTypes,
|
|
28656
|
+
getUnitsBySchool
|
|
28657
|
+
};
|
|
28658
|
+
}
|
|
28659
|
+
|
|
28660
|
+
// src/controllers/asset.controller.ts
|
|
28661
|
+
import { BadRequestError as BadRequestError67 } from "@eeplatform/nodejs-utils";
|
|
28662
|
+
import Joi37 from "joi";
|
|
28663
|
+
function useAssetController() {
|
|
28664
|
+
const {
|
|
28665
|
+
add: _add,
|
|
28666
|
+
getAll: _getAll,
|
|
28667
|
+
deleteById: _deleteById,
|
|
28668
|
+
updateById: _updateById,
|
|
28669
|
+
getById: _getById,
|
|
28670
|
+
getCategories: _getCategories,
|
|
28671
|
+
getTypes: _getTypes,
|
|
28672
|
+
getUnitsBySchool: _getUnitsBySchool
|
|
28673
|
+
} = useAssetRepo();
|
|
28674
|
+
async function add(req, res, next) {
|
|
28675
|
+
const value = req.body;
|
|
28676
|
+
const { error } = schemaAsset.validate(value);
|
|
28677
|
+
if (error) {
|
|
28678
|
+
next(new BadRequestError67(error.message));
|
|
28679
|
+
return;
|
|
28680
|
+
}
|
|
28681
|
+
try {
|
|
28682
|
+
const id = await _add(value);
|
|
28683
|
+
res.json({ message: "Successfully added asset item.", id });
|
|
28684
|
+
} catch (error2) {
|
|
28685
|
+
next(error2);
|
|
28686
|
+
}
|
|
28687
|
+
}
|
|
28688
|
+
async function getAll(req, res, next) {
|
|
28689
|
+
const query = req.query;
|
|
28690
|
+
const validation = Joi37.object({
|
|
28691
|
+
page: Joi37.number().min(1).optional().allow("", null),
|
|
28692
|
+
limit: Joi37.number().min(1).optional().allow("", null),
|
|
28693
|
+
search: Joi37.string().optional().allow("", null),
|
|
28694
|
+
status: Joi37.string().optional().allow("", null),
|
|
28695
|
+
school: Joi37.string().hex().optional().allow("", null),
|
|
28696
|
+
asset_type: Joi37.string().required().allow("supply", "furniture-equipment", "fixed-asset")
|
|
28697
|
+
});
|
|
28698
|
+
const { error } = validation.validate(query);
|
|
28699
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
28700
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
28701
|
+
const search = req.query.search ?? "";
|
|
28702
|
+
const status = req.query.status ?? "active";
|
|
28703
|
+
const school = req.query.school ?? "";
|
|
28704
|
+
const asset_type = req.query.asset_type ?? "supply";
|
|
28705
|
+
const isPageNumber = isFinite(page);
|
|
28706
|
+
if (!isPageNumber) {
|
|
28707
|
+
next(new BadRequestError67("Invalid page number."));
|
|
28708
|
+
return;
|
|
28709
|
+
}
|
|
28710
|
+
const isLimitNumber = isFinite(limit);
|
|
28711
|
+
if (!isLimitNumber) {
|
|
28712
|
+
next(new BadRequestError67("Invalid limit number."));
|
|
28713
|
+
return;
|
|
28714
|
+
}
|
|
28715
|
+
if (error) {
|
|
28716
|
+
next(new BadRequestError67(error.message));
|
|
28717
|
+
return;
|
|
28718
|
+
}
|
|
28719
|
+
try {
|
|
28720
|
+
const regions = await _getAll({
|
|
28721
|
+
page,
|
|
28722
|
+
limit,
|
|
28723
|
+
search,
|
|
28724
|
+
status,
|
|
28725
|
+
school,
|
|
28726
|
+
asset_type
|
|
28727
|
+
});
|
|
28728
|
+
res.json(regions);
|
|
28729
|
+
return;
|
|
28730
|
+
} catch (error2) {
|
|
28731
|
+
next(error2);
|
|
28732
|
+
}
|
|
28733
|
+
}
|
|
28734
|
+
async function deleteById(req, res, next) {
|
|
28735
|
+
const id = req.params.id;
|
|
28736
|
+
const validation = Joi37.string().hex().required();
|
|
28737
|
+
const { error } = validation.validate(id);
|
|
28738
|
+
if (error) {
|
|
28739
|
+
next(new BadRequestError67(error.message));
|
|
28740
|
+
return;
|
|
28741
|
+
}
|
|
28742
|
+
try {
|
|
28743
|
+
await _deleteById(id);
|
|
28744
|
+
res.json({ message: "Successfully deleted asset item.", id });
|
|
28745
|
+
} catch (error2) {
|
|
28746
|
+
next(error2);
|
|
28747
|
+
}
|
|
28748
|
+
}
|
|
28749
|
+
async function getById(req, res, next) {
|
|
28750
|
+
const id = req.params.id;
|
|
28751
|
+
const validation = Joi37.string().hex().required();
|
|
28752
|
+
const { error } = validation.validate(id);
|
|
28753
|
+
if (error) {
|
|
28754
|
+
next(new BadRequestError67(error.message));
|
|
28755
|
+
return;
|
|
28756
|
+
}
|
|
28757
|
+
try {
|
|
28758
|
+
const data = await _getById(id);
|
|
28759
|
+
res.json(data);
|
|
28760
|
+
} catch (error2) {
|
|
28761
|
+
next(error2);
|
|
28762
|
+
}
|
|
28763
|
+
}
|
|
28764
|
+
async function updateById(req, res, next) {
|
|
28765
|
+
const id = req.params.id;
|
|
28766
|
+
const value = req.body;
|
|
28767
|
+
const { error } = schemaAssetUpdateOption.validate(value);
|
|
28768
|
+
if (error) {
|
|
28769
|
+
next(new BadRequestError67(error.message));
|
|
28770
|
+
return;
|
|
28771
|
+
}
|
|
28772
|
+
try {
|
|
28773
|
+
await _updateById(id, value);
|
|
28774
|
+
res.json({ message: "Successfully updated asset item.", id });
|
|
28775
|
+
} catch (error2) {
|
|
28776
|
+
next(error2);
|
|
28777
|
+
}
|
|
28778
|
+
}
|
|
28779
|
+
async function getCategories(req, res, next) {
|
|
28780
|
+
const school = req.params.school;
|
|
28781
|
+
const asset_type = req.params.asset_type;
|
|
28782
|
+
const validation = Joi37.string().hex().required();
|
|
28783
|
+
const { error } = validation.validate(school);
|
|
28784
|
+
if (error) {
|
|
28785
|
+
next(new BadRequestError67(error.message));
|
|
28786
|
+
return;
|
|
28787
|
+
}
|
|
28788
|
+
try {
|
|
28789
|
+
const data = await _getCategories(school, asset_type);
|
|
28790
|
+
res.json(data);
|
|
28791
|
+
} catch (error2) {
|
|
28792
|
+
next(error2);
|
|
28793
|
+
}
|
|
28794
|
+
}
|
|
28795
|
+
async function getTypes(req, res, next) {
|
|
28796
|
+
const school = req.params.school;
|
|
28797
|
+
const asset_type = req.params.asset_type;
|
|
28798
|
+
const validation = Joi37.string().hex().required();
|
|
28799
|
+
const { error } = validation.validate(school);
|
|
28800
|
+
if (error) {
|
|
28801
|
+
next(new BadRequestError67(error.message));
|
|
28802
|
+
return;
|
|
28803
|
+
}
|
|
28804
|
+
try {
|
|
28805
|
+
const data = await _getTypes(school, asset_type);
|
|
28806
|
+
res.json(data);
|
|
28807
|
+
} catch (error2) {
|
|
28808
|
+
next(error2);
|
|
28809
|
+
}
|
|
28810
|
+
}
|
|
28811
|
+
async function getUnitsBySchool(req, res, next) {
|
|
28812
|
+
const school = req.params.school;
|
|
28813
|
+
const validation = Joi37.string().hex().required();
|
|
28814
|
+
const { error } = validation.validate(school);
|
|
28815
|
+
if (error) {
|
|
28816
|
+
next(new BadRequestError67(error.message));
|
|
28817
|
+
return;
|
|
28818
|
+
}
|
|
28819
|
+
try {
|
|
28820
|
+
const data = await _getUnitsBySchool(school);
|
|
28821
|
+
res.json(data);
|
|
28822
|
+
} catch (error2) {
|
|
28823
|
+
next(error2);
|
|
28824
|
+
}
|
|
28825
|
+
}
|
|
28826
|
+
return {
|
|
28827
|
+
add,
|
|
28828
|
+
getAll,
|
|
28829
|
+
deleteById,
|
|
28830
|
+
updateById,
|
|
28831
|
+
getById,
|
|
28832
|
+
getCategories,
|
|
28833
|
+
getTypes,
|
|
28834
|
+
getUnitsBySchool
|
|
28835
|
+
};
|
|
28836
|
+
}
|
|
28837
|
+
|
|
28838
|
+
// src/models/stock-card.model.ts
|
|
28839
|
+
import { BadRequestError as BadRequestError68 } from "@eeplatform/nodejs-utils";
|
|
28840
|
+
import Joi38 from "joi";
|
|
28841
|
+
import { ObjectId as ObjectId44 } from "mongodb";
|
|
28842
|
+
var schemaStockCard = Joi38.object({
|
|
28843
|
+
_id: Joi38.string().hex().optional().allow("", null),
|
|
28844
|
+
school: Joi38.string().hex().required(),
|
|
28845
|
+
item: Joi38.string().hex().required(),
|
|
28846
|
+
balance: Joi38.number().optional().allow(null, 0),
|
|
28847
|
+
qty: Joi38.number().required(),
|
|
28848
|
+
unitCost: Joi38.number().optional().allow(null, 0),
|
|
28849
|
+
totalCost: Joi38.number().optional().allow(null, 0),
|
|
28850
|
+
status: Joi38.string().required(),
|
|
28851
|
+
condition: Joi38.string().required(),
|
|
28852
|
+
supplier: Joi38.string().optional().allow("", null),
|
|
28853
|
+
location: Joi38.string().optional().allow("", null),
|
|
28854
|
+
locationName: Joi38.string().optional().allow("", null),
|
|
28855
|
+
reason: Joi38.string().optional().allow("", null),
|
|
28856
|
+
remarks: Joi38.string().optional().allow("", null),
|
|
28857
|
+
createdAt: Joi38.date().optional().allow("", null),
|
|
28858
|
+
updatedAt: Joi38.date().optional().allow("", null),
|
|
28859
|
+
deletedAt: Joi38.date().optional().allow("", null)
|
|
28860
|
+
});
|
|
28861
|
+
function MStockCard(value) {
|
|
28862
|
+
const { error } = schemaStockCard.validate(value);
|
|
28863
|
+
if (error) {
|
|
28864
|
+
throw new BadRequestError68(`Invalid stock card data: ${error.message}`);
|
|
28865
|
+
}
|
|
28866
|
+
if (value._id && typeof value._id === "string") {
|
|
28867
|
+
try {
|
|
28868
|
+
value._id = new ObjectId44(value._id);
|
|
28869
|
+
} catch (err) {
|
|
28870
|
+
throw new BadRequestError68("Invalid stock card ID.");
|
|
28871
|
+
}
|
|
28872
|
+
}
|
|
28873
|
+
try {
|
|
28874
|
+
value.item = new ObjectId44(value.item);
|
|
28875
|
+
} catch (err) {
|
|
28876
|
+
throw new BadRequestError68("Invalid item ID.");
|
|
28877
|
+
}
|
|
28878
|
+
try {
|
|
28879
|
+
value.school = new ObjectId44(value.school);
|
|
28880
|
+
} catch (err) {
|
|
28881
|
+
throw new BadRequestError68("Invalid school ID.");
|
|
28882
|
+
}
|
|
28883
|
+
return {
|
|
28884
|
+
_id: value._id ?? void 0,
|
|
28885
|
+
school: value.school,
|
|
28886
|
+
item: value.item,
|
|
28887
|
+
balance: value.balance,
|
|
28888
|
+
qty: value.qty,
|
|
28889
|
+
unitCost: value.unitCost,
|
|
28890
|
+
totalCost: value.totalCost,
|
|
28891
|
+
status: value.status,
|
|
28892
|
+
condition: value.condition,
|
|
28893
|
+
supplier: value.supplier ?? "",
|
|
28894
|
+
location: value.location ?? void 0,
|
|
28895
|
+
locationName: value.locationName ?? "",
|
|
28896
|
+
reason: value.reason ?? "",
|
|
28897
|
+
remarks: value.remarks ?? "",
|
|
28898
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
28899
|
+
updatedAt: value.updatedAt ?? "",
|
|
28900
|
+
deletedAt: value.deletedAt ?? ""
|
|
28901
|
+
};
|
|
28902
|
+
}
|
|
28903
|
+
|
|
28904
|
+
// src/repositories/stock-card.repository.ts
|
|
28905
|
+
import {
|
|
28906
|
+
BadRequestError as BadRequestError69,
|
|
28907
|
+
logger as logger34,
|
|
28908
|
+
makeCacheKey as makeCacheKey22,
|
|
28909
|
+
paginate as paginate18,
|
|
28910
|
+
useAtlas as useAtlas36,
|
|
28911
|
+
useCache as useCache23
|
|
28912
|
+
} from "@eeplatform/nodejs-utils";
|
|
28913
|
+
import { ObjectId as ObjectId45 } from "mongodb";
|
|
28914
|
+
function useStockCardRepository() {
|
|
28915
|
+
const db = useAtlas36.getDb();
|
|
28916
|
+
if (!db) {
|
|
28917
|
+
throw new BadRequestError69("Unable to connect to server.");
|
|
28918
|
+
}
|
|
28919
|
+
const namespace_collection = "school.assets.stock-cards";
|
|
28920
|
+
const collection = db.collection(namespace_collection);
|
|
28921
|
+
const { getCache, setCache, delNamespace } = useCache23(namespace_collection);
|
|
28922
|
+
function delCachedData() {
|
|
28923
|
+
delNamespace().then(() => {
|
|
28924
|
+
logger34.log({
|
|
28925
|
+
level: "info",
|
|
28926
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
28927
|
+
});
|
|
28928
|
+
}).catch((err) => {
|
|
28929
|
+
logger34.log({
|
|
28930
|
+
level: "error",
|
|
28931
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
28932
|
+
});
|
|
28933
|
+
});
|
|
28934
|
+
}
|
|
28935
|
+
async function createIndex() {
|
|
28936
|
+
try {
|
|
28937
|
+
await collection.createIndexes([
|
|
28938
|
+
{ key: { school: 1 } },
|
|
28939
|
+
{ key: { item: 1 } }
|
|
28940
|
+
]);
|
|
28941
|
+
} catch (error) {
|
|
28942
|
+
throw new BadRequestError69("Failed to create index on stock card.");
|
|
28943
|
+
}
|
|
28944
|
+
}
|
|
28945
|
+
async function add(value, session) {
|
|
28946
|
+
try {
|
|
28947
|
+
value = MStockCard(value);
|
|
28948
|
+
const res = await collection.insertOne(value, { session });
|
|
28949
|
+
delCachedData();
|
|
28950
|
+
return res.insertedId;
|
|
28951
|
+
} catch (error) {
|
|
28952
|
+
throw new BadRequestError69("Failed to create stock card.");
|
|
28953
|
+
}
|
|
28954
|
+
}
|
|
28955
|
+
async function getById(_id) {
|
|
28956
|
+
try {
|
|
28957
|
+
_id = new ObjectId45(_id);
|
|
28958
|
+
} catch (error) {
|
|
28959
|
+
throw new BadRequestError69("Invalid ID.");
|
|
28960
|
+
}
|
|
28961
|
+
const cacheKey = makeCacheKey22(namespace_collection, { _id: String(_id) });
|
|
28962
|
+
const cachedData = await getCache(cacheKey);
|
|
28963
|
+
if (cachedData) {
|
|
28964
|
+
return cachedData;
|
|
28965
|
+
}
|
|
28966
|
+
try {
|
|
28967
|
+
const res = await collection.findOne({ _id });
|
|
28968
|
+
if (!res) {
|
|
28969
|
+
throw new BadRequestError69("Asset item not found.");
|
|
28970
|
+
}
|
|
28971
|
+
setCache(cacheKey, res).then(() => {
|
|
28972
|
+
logger34.log({
|
|
28973
|
+
level: "info",
|
|
28974
|
+
message: `Cache set for stock card by ID: ${cacheKey}`
|
|
28975
|
+
});
|
|
28976
|
+
}).catch((err) => {
|
|
28977
|
+
logger34.log({
|
|
28978
|
+
level: "error",
|
|
28979
|
+
message: `Failed to set cache for stock card by ID: ${cacheKey} - ${err.message}`
|
|
28980
|
+
});
|
|
28981
|
+
});
|
|
28982
|
+
return res;
|
|
28983
|
+
} catch (error) {
|
|
28984
|
+
if (error instanceof BadRequestError69) {
|
|
28985
|
+
throw error;
|
|
28986
|
+
}
|
|
28987
|
+
throw new BadRequestError69("Failed to retrieve stock card.");
|
|
28988
|
+
}
|
|
28989
|
+
}
|
|
28990
|
+
async function getAll({ page = 1, limit = 20, school = "", sort = { _id: 1 }, id = "" } = {}) {
|
|
28991
|
+
page = page ? page - 1 : 0;
|
|
28992
|
+
try {
|
|
28993
|
+
school = new ObjectId45(school);
|
|
28994
|
+
} catch (error) {
|
|
28995
|
+
throw new BadRequestError69("Invalid school ID.");
|
|
28996
|
+
}
|
|
28997
|
+
try {
|
|
28998
|
+
id = new ObjectId45(id);
|
|
28999
|
+
} catch (error) {
|
|
29000
|
+
throw new BadRequestError69("Invalid ID.");
|
|
29001
|
+
}
|
|
29002
|
+
const query = {
|
|
29003
|
+
school,
|
|
29004
|
+
item: id
|
|
29005
|
+
};
|
|
29006
|
+
const cacheKeyOptions = {
|
|
29007
|
+
page,
|
|
29008
|
+
limit,
|
|
29009
|
+
school: String(school),
|
|
29010
|
+
sort: JSON.stringify(sort),
|
|
29011
|
+
item: id
|
|
29012
|
+
};
|
|
29013
|
+
try {
|
|
29014
|
+
const cacheKey = makeCacheKey22(namespace_collection, cacheKeyOptions);
|
|
29015
|
+
const cached = await getCache(cacheKey);
|
|
29016
|
+
if (cached) {
|
|
29017
|
+
logger34.log({
|
|
29018
|
+
level: "info",
|
|
29019
|
+
message: `Cache hit for getAll stock cards: ${cacheKey}`
|
|
29020
|
+
});
|
|
29021
|
+
return cached;
|
|
29022
|
+
}
|
|
29023
|
+
const items = await collection.aggregate([
|
|
29024
|
+
{ $match: query },
|
|
29025
|
+
{
|
|
29026
|
+
$sort: sort
|
|
29027
|
+
},
|
|
29028
|
+
{
|
|
29029
|
+
$skip: page * limit
|
|
29030
|
+
},
|
|
29031
|
+
{
|
|
29032
|
+
$limit: limit
|
|
29033
|
+
}
|
|
29034
|
+
]).toArray();
|
|
29035
|
+
const length = await collection.countDocuments(query);
|
|
29036
|
+
const data = paginate18(items, page, limit, length);
|
|
29037
|
+
setCache(cacheKey, data, 500).then(() => {
|
|
29038
|
+
logger34.log({
|
|
29039
|
+
level: "info",
|
|
29040
|
+
message: `Cache set for getAll stock cards: ${cacheKey}`
|
|
29041
|
+
});
|
|
29042
|
+
}).catch((err) => {
|
|
29043
|
+
logger34.log({
|
|
29044
|
+
level: "error",
|
|
29045
|
+
message: `Failed to set cache for getAll stock cards: ${err.message}`
|
|
29046
|
+
});
|
|
29047
|
+
});
|
|
29048
|
+
return data;
|
|
29049
|
+
} catch (error) {
|
|
29050
|
+
console.log("Error in getAll:", error);
|
|
29051
|
+
throw new BadRequestError69("Failed to retrieve stock cards.");
|
|
29052
|
+
}
|
|
29053
|
+
}
|
|
29054
|
+
async function getSuppliers(school) {
|
|
29055
|
+
try {
|
|
29056
|
+
school = new ObjectId45(school);
|
|
29057
|
+
} catch (error) {
|
|
29058
|
+
throw new BadRequestError69("Invalid school ID.");
|
|
29059
|
+
}
|
|
29060
|
+
const cacheKey = makeCacheKey22(namespace_collection, {
|
|
29061
|
+
school,
|
|
29062
|
+
type: "supplier-as-options"
|
|
29063
|
+
});
|
|
29064
|
+
const cachedData = await getCache(cacheKey);
|
|
29065
|
+
if (cachedData) {
|
|
29066
|
+
return cachedData;
|
|
29067
|
+
}
|
|
29068
|
+
try {
|
|
29069
|
+
const suppliers = await collection.aggregate([
|
|
29070
|
+
{
|
|
29071
|
+
$match: { school }
|
|
29072
|
+
},
|
|
29073
|
+
{
|
|
29074
|
+
$group: {
|
|
29075
|
+
_id: "$supplier",
|
|
29076
|
+
value: { $first: "$supplier" },
|
|
29077
|
+
title: {
|
|
29078
|
+
$first: "$supplier"
|
|
29079
|
+
}
|
|
29080
|
+
}
|
|
29081
|
+
},
|
|
29082
|
+
{
|
|
29083
|
+
$project: {
|
|
29084
|
+
_id: 0,
|
|
29085
|
+
title: 1,
|
|
29086
|
+
value: 1
|
|
29087
|
+
}
|
|
29088
|
+
},
|
|
29089
|
+
{ $sort: { title: 1 } }
|
|
29090
|
+
]).toArray();
|
|
29091
|
+
setCache(cacheKey, suppliers).then(() => {
|
|
29092
|
+
logger34.log({
|
|
29093
|
+
level: "info",
|
|
29094
|
+
message: `Cache set for getSuppliersBySchool: ${cacheKey}`
|
|
29095
|
+
});
|
|
29096
|
+
}).catch((err) => {
|
|
29097
|
+
logger34.log({
|
|
29098
|
+
level: "error",
|
|
29099
|
+
message: `Failed to set cache for getSuppliersBySchool: ${err.message}`
|
|
29100
|
+
});
|
|
29101
|
+
});
|
|
29102
|
+
return suppliers;
|
|
29103
|
+
} catch (error) {
|
|
29104
|
+
if (error instanceof BadRequestError69) {
|
|
29105
|
+
throw error;
|
|
29106
|
+
}
|
|
29107
|
+
throw new BadRequestError69("Failed to retrieve asset suppliers.");
|
|
29108
|
+
}
|
|
29109
|
+
}
|
|
29110
|
+
return {
|
|
29111
|
+
createIndex,
|
|
29112
|
+
add,
|
|
29113
|
+
getById,
|
|
29114
|
+
getAll,
|
|
29115
|
+
getSuppliers
|
|
29116
|
+
};
|
|
29117
|
+
}
|
|
29118
|
+
|
|
29119
|
+
// src/controllers/stock-card.controller.ts
|
|
29120
|
+
import { BadRequestError as BadRequestError71 } from "@eeplatform/nodejs-utils";
|
|
29121
|
+
import Joi39 from "joi";
|
|
29122
|
+
|
|
29123
|
+
// src/services/stock-card.service.ts
|
|
29124
|
+
import {
|
|
29125
|
+
BadRequestError as BadRequestError70,
|
|
29126
|
+
NotFoundError as NotFoundError11,
|
|
29127
|
+
useAtlas as useAtlas37
|
|
29128
|
+
} from "@eeplatform/nodejs-utils";
|
|
29129
|
+
function useStockCardService() {
|
|
29130
|
+
const { add: _add, getById: _getById } = useStockCardRepository();
|
|
29131
|
+
const { getById: _getAssetById, updateById: updateAssetById } = useAssetRepo();
|
|
29132
|
+
async function add(data) {
|
|
29133
|
+
const session = useAtlas37.getClient()?.startSession();
|
|
29134
|
+
if (!session) {
|
|
29135
|
+
throw new BadRequestError70("Unable to start database session.");
|
|
29136
|
+
}
|
|
29137
|
+
session.startTransaction();
|
|
29138
|
+
try {
|
|
29139
|
+
const asset = await _getAssetById(data.item);
|
|
29140
|
+
if (!asset) {
|
|
29141
|
+
throw new NotFoundError11("Asset not found.");
|
|
29142
|
+
}
|
|
29143
|
+
data.balance = (asset.qty ?? 0) + data.qty;
|
|
29144
|
+
await _add(data, session);
|
|
29145
|
+
await updateAssetById(data.item, { qty: data.balance }, session);
|
|
29146
|
+
await session.commitTransaction();
|
|
29147
|
+
return "Successfully added stock card.";
|
|
29148
|
+
} catch (error) {
|
|
29149
|
+
await session.abortTransaction();
|
|
29150
|
+
throw new BadRequestError70("Failed to add stock card.");
|
|
29151
|
+
} finally {
|
|
29152
|
+
session.endSession();
|
|
29153
|
+
}
|
|
29154
|
+
}
|
|
29155
|
+
return {
|
|
29156
|
+
add
|
|
29157
|
+
};
|
|
29158
|
+
}
|
|
29159
|
+
|
|
29160
|
+
// src/controllers/stock-card.controller.ts
|
|
29161
|
+
function useStockCardController() {
|
|
29162
|
+
const {
|
|
29163
|
+
getAll: _getAll,
|
|
29164
|
+
getById: _getById,
|
|
29165
|
+
getSuppliers: _getSuppliers
|
|
29166
|
+
} = useStockCardRepository();
|
|
29167
|
+
const { add: _add } = useStockCardService();
|
|
29168
|
+
async function add(req, res, next) {
|
|
29169
|
+
const value = req.body;
|
|
29170
|
+
const { error } = schemaStockCard.validate(value);
|
|
29171
|
+
if (error) {
|
|
29172
|
+
next(new BadRequestError71(error.message));
|
|
29173
|
+
return;
|
|
29174
|
+
}
|
|
29175
|
+
try {
|
|
29176
|
+
const id = await _add(value);
|
|
29177
|
+
res.json({ message: "Successfully added asset item.", id });
|
|
29178
|
+
} catch (error2) {
|
|
29179
|
+
next(error2);
|
|
29180
|
+
}
|
|
29181
|
+
}
|
|
29182
|
+
async function getAll(req, res, next) {
|
|
29183
|
+
const query = req.query;
|
|
29184
|
+
const validation = Joi39.object({
|
|
29185
|
+
page: Joi39.number().min(1).optional().allow("", null),
|
|
29186
|
+
limit: Joi39.number().min(1).optional().allow("", null),
|
|
29187
|
+
school: Joi39.string().hex().optional().allow("", null),
|
|
29188
|
+
id: Joi39.string().hex().required()
|
|
29189
|
+
});
|
|
29190
|
+
const { error } = validation.validate(query);
|
|
29191
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
29192
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
29193
|
+
const school = req.query.school ?? "";
|
|
29194
|
+
const id = req.query.id ?? "supply";
|
|
29195
|
+
const isPageNumber = isFinite(page);
|
|
29196
|
+
if (!isPageNumber) {
|
|
29197
|
+
next(new BadRequestError71("Invalid page number."));
|
|
29198
|
+
return;
|
|
29199
|
+
}
|
|
29200
|
+
const isLimitNumber = isFinite(limit);
|
|
29201
|
+
if (!isLimitNumber) {
|
|
29202
|
+
next(new BadRequestError71("Invalid limit number."));
|
|
29203
|
+
return;
|
|
29204
|
+
}
|
|
29205
|
+
if (error) {
|
|
29206
|
+
next(new BadRequestError71(error.message));
|
|
29207
|
+
return;
|
|
29208
|
+
}
|
|
29209
|
+
try {
|
|
29210
|
+
const regions = await _getAll({
|
|
29211
|
+
page,
|
|
29212
|
+
limit,
|
|
29213
|
+
id,
|
|
29214
|
+
school
|
|
29215
|
+
});
|
|
29216
|
+
res.json(regions);
|
|
29217
|
+
return;
|
|
29218
|
+
} catch (error2) {
|
|
29219
|
+
next(error2);
|
|
29220
|
+
}
|
|
29221
|
+
}
|
|
29222
|
+
async function getById(req, res, next) {
|
|
29223
|
+
const id = req.params.id;
|
|
29224
|
+
const validation = Joi39.string().hex().required();
|
|
29225
|
+
const { error } = validation.validate(id);
|
|
29226
|
+
if (error) {
|
|
29227
|
+
next(new BadRequestError71(error.message));
|
|
29228
|
+
return;
|
|
29229
|
+
}
|
|
29230
|
+
try {
|
|
29231
|
+
const data = await _getById(id);
|
|
29232
|
+
res.json(data);
|
|
29233
|
+
} catch (error2) {
|
|
29234
|
+
next(error2);
|
|
29235
|
+
}
|
|
29236
|
+
}
|
|
29237
|
+
async function getSuppliers(req, res, next) {
|
|
29238
|
+
const school = req.params.school;
|
|
29239
|
+
const validation = Joi39.string().hex().required();
|
|
29240
|
+
const { error } = validation.validate(school);
|
|
29241
|
+
if (error) {
|
|
29242
|
+
next(new BadRequestError71(error.message));
|
|
29243
|
+
return;
|
|
29244
|
+
}
|
|
29245
|
+
try {
|
|
29246
|
+
const data = await _getSuppliers(school);
|
|
29247
|
+
res.json(data);
|
|
29248
|
+
} catch (error2) {
|
|
29249
|
+
next(error2);
|
|
29250
|
+
}
|
|
29251
|
+
}
|
|
29252
|
+
return {
|
|
29253
|
+
add,
|
|
29254
|
+
getAll,
|
|
29255
|
+
getById,
|
|
29256
|
+
getSuppliers
|
|
29257
|
+
};
|
|
29258
|
+
}
|
|
28134
29259
|
export {
|
|
28135
29260
|
ACCESS_TOKEN_EXPIRY,
|
|
28136
29261
|
ACCESS_TOKEN_SECRET,
|
|
@@ -28149,6 +29274,7 @@ export {
|
|
|
28149
29274
|
MAILER_TRANSPORT_PORT,
|
|
28150
29275
|
MAILER_TRANSPORT_SECURE,
|
|
28151
29276
|
MAddress,
|
|
29277
|
+
MAsset,
|
|
28152
29278
|
MBuilding,
|
|
28153
29279
|
MBuildingUnit,
|
|
28154
29280
|
MDivision,
|
|
@@ -28164,6 +29290,7 @@ export {
|
|
|
28164
29290
|
MRegion,
|
|
28165
29291
|
MRole,
|
|
28166
29292
|
MSchool,
|
|
29293
|
+
MStockCard,
|
|
28167
29294
|
MSubscription,
|
|
28168
29295
|
MToken,
|
|
28169
29296
|
MUser,
|
|
@@ -28191,14 +29318,19 @@ export {
|
|
|
28191
29318
|
addressSchema,
|
|
28192
29319
|
isDev,
|
|
28193
29320
|
schema,
|
|
29321
|
+
schemaAsset,
|
|
29322
|
+
schemaAssetUpdateOption,
|
|
28194
29323
|
schemaBuilding,
|
|
28195
29324
|
schemaBuildingUnit,
|
|
28196
29325
|
schemaDivision,
|
|
28197
29326
|
schemaRegion,
|
|
28198
29327
|
schemaSchool,
|
|
29328
|
+
schemaStockCard,
|
|
28199
29329
|
schemaUpdateOptions,
|
|
28200
29330
|
useAddressController,
|
|
28201
29331
|
useAddressRepo,
|
|
29332
|
+
useAssetController,
|
|
29333
|
+
useAssetRepo,
|
|
28202
29334
|
useAuthController,
|
|
28203
29335
|
useAuthService,
|
|
28204
29336
|
useBuildingController,
|
|
@@ -28246,6 +29378,8 @@ export {
|
|
|
28246
29378
|
useSchoolController,
|
|
28247
29379
|
useSchoolRepo,
|
|
28248
29380
|
useSchoolService,
|
|
29381
|
+
useStockCardController,
|
|
29382
|
+
useStockCardRepository,
|
|
28249
29383
|
useSubscriptionController,
|
|
28250
29384
|
useSubscriptionRepo,
|
|
28251
29385
|
useSubscriptionService,
|