@goweekdays/core 2.12.3 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -71,12 +71,17 @@ __export(src_exports, {
71
71
  VERIFICATION_USER_INVITE_DURATION: () => VERIFICATION_USER_INVITE_DURATION,
72
72
  XENDIT_BASE_URL: () => XENDIT_BASE_URL,
73
73
  XENDIT_SECRET_KEY: () => XENDIT_SECRET_KEY,
74
+ chartOfAccountNormalBalances: () => chartOfAccountNormalBalances,
75
+ chartOfAccountTypes: () => chartOfAccountTypes,
74
76
  currencies: () => currencies,
75
77
  isDev: () => isDev,
76
78
  jobApplicationStatuses: () => jobApplicationStatuses,
79
+ journalEntryStatuses: () => journalEntryStatuses,
80
+ journalEntryTypes: () => journalEntryTypes,
77
81
  ledgerBillStatuses: () => ledgerBillStatuses,
78
82
  ledgerBillTypes: () => ledgerBillTypes,
79
83
  modelApp: () => modelApp,
84
+ modelChartOfAccount: () => modelChartOfAccount,
80
85
  modelJobApplication: () => modelJobApplication,
81
86
  modelJobPost: () => modelJobPost,
82
87
  modelJobProfile: () => modelJobProfile,
@@ -88,6 +93,8 @@ __export(src_exports, {
88
93
  modelJobStatusSetup: () => modelJobStatusSetup,
89
94
  modelJobStatusTrans: () => modelJobStatusTrans,
90
95
  modelJobSummary: () => modelJobSummary,
96
+ modelJournalEntry: () => modelJournalEntry,
97
+ modelJournalLine: () => modelJournalLine,
91
98
  modelLedgerBill: () => modelLedgerBill,
92
99
  modelMember: () => modelMember,
93
100
  modelOption: () => modelOption,
@@ -99,6 +106,7 @@ __export(src_exports, {
99
106
  modelRole: () => modelRole,
100
107
  modelSubscription: () => modelSubscription,
101
108
  modelSubscriptionTransaction: () => modelSubscriptionTransaction,
109
+ modelTax: () => modelTax,
102
110
  modelUser: () => modelUser,
103
111
  modelVerification: () => modelVerification,
104
112
  schemaApp: () => schemaApp,
@@ -107,6 +115,9 @@ __export(src_exports, {
107
115
  schemaBuilding: () => schemaBuilding,
108
116
  schemaBuildingUnit: () => schemaBuildingUnit,
109
117
  schemaCertification: () => schemaCertification,
118
+ schemaChartOfAccountBase: () => schemaChartOfAccountBase,
119
+ schemaChartOfAccountStd: () => schemaChartOfAccountStd,
120
+ schemaChartOfAccountUpdate: () => schemaChartOfAccountUpdate,
110
121
  schemaEducation: () => schemaEducation,
111
122
  schemaGroup: () => schemaGroup,
112
123
  schemaInviteMember: () => schemaInviteMember,
@@ -133,6 +144,11 @@ __export(src_exports, {
133
144
  schemaJobStatusTrans: () => schemaJobStatusTrans,
134
145
  schemaJobSummary: () => schemaJobSummary,
135
146
  schemaJobSummaryInc: () => schemaJobSummaryInc,
147
+ schemaJournalEntryCtrl: () => schemaJournalEntryCtrl,
148
+ schemaJournalEntryGetAll: () => schemaJournalEntryGetAll,
149
+ schemaJournalEntryRepo: () => schemaJournalEntryRepo,
150
+ schemaJournalLineCtrl: () => schemaJournalLineCtrl,
151
+ schemaJournalLineRepo: () => schemaJournalLineRepo,
136
152
  schemaLanguage: () => schemaLanguage,
137
153
  schemaLedgerBill: () => schemaLedgerBill,
138
154
  schemaLedgerBillingSummary: () => schemaLedgerBillingSummary,
@@ -163,11 +179,14 @@ __export(src_exports, {
163
179
  schemaSubscriptionSeats: () => schemaSubscriptionSeats,
164
180
  schemaSubscriptionTransaction: () => schemaSubscriptionTransaction,
165
181
  schemaSubscriptionUpdate: () => schemaSubscriptionUpdate,
182
+ schemaTax: () => schemaTax,
183
+ schemaTaxUpdate: () => schemaTaxUpdate,
166
184
  schemaUpdateOptions: () => schemaUpdateOptions,
167
185
  schemaUser: () => schemaUser,
168
186
  schemaVerification: () => schemaVerification,
169
187
  schemaVerificationOrgInvite: () => schemaVerificationOrgInvite,
170
188
  schemaWorkExp: () => schemaWorkExp,
189
+ taxDirections: () => taxDirections,
171
190
  transactionSchema: () => transactionSchema,
172
191
  useAppController: () => useAppController,
173
192
  useAppRepo: () => useAppRepo,
@@ -180,6 +199,8 @@ __export(src_exports, {
180
199
  useBuildingUnitController: () => useBuildingUnitController,
181
200
  useBuildingUnitRepo: () => useBuildingUnitRepo,
182
201
  useBuildingUnitService: () => useBuildingUnitService,
202
+ useChartOfAccountController: () => useChartOfAccountController,
203
+ useChartOfAccountRepo: () => useChartOfAccountRepo,
183
204
  useCounterModel: () => useCounterModel,
184
205
  useCounterRepo: () => useCounterRepo,
185
206
  useFileController: () => useFileController,
@@ -198,6 +219,11 @@ __export(src_exports, {
198
219
  useJobSummaryCtrl: () => useJobSummaryCtrl,
199
220
  useJobSummaryRepo: () => useJobSummaryRepo,
200
221
  useJobSummarySvc: () => useJobSummarySvc,
222
+ useJournalEntryController: () => useJournalEntryController,
223
+ useJournalEntryRepo: () => useJournalEntryRepo,
224
+ useJournalEntryService: () => useJournalEntryService,
225
+ useJournalLineController: () => useJournalLineController,
226
+ useJournalLineRepo: () => useJournalLineRepo,
201
227
  useLedgerBillingController: () => useLedgerBillingController,
202
228
  useLedgerBillingRepo: () => useLedgerBillingRepo,
203
229
  useMemberController: () => useMemberController,
@@ -228,6 +254,8 @@ __export(src_exports, {
228
254
  useSubscriptionService: () => useSubscriptionService,
229
255
  useSubscriptionTransactionController: () => useSubscriptionTransactionController,
230
256
  useSubscriptionTransactionRepo: () => useSubscriptionTransactionRepo,
257
+ useTaxController: () => useTaxController,
258
+ useTaxRepo: () => useTaxRepo,
231
259
  useUserController: () => useUserController,
232
260
  useUserRepo: () => useUserRepo,
233
261
  useUserService: () => useUserService,
@@ -11094,6 +11122,24 @@ function useOrgController() {
11094
11122
  companySearch: _companySearch
11095
11123
  } = useOrgRepo();
11096
11124
  const { addPilot: _addPilot } = useOrgService();
11125
+ async function validOrg(req, res, next) {
11126
+ const org = req.params.org ?? "";
11127
+ const { error } = import_joi49.default.string().hex().required().validate(org);
11128
+ if (error) {
11129
+ next(new import_utils57.BadRequestError("Invalid organization ID."));
11130
+ return;
11131
+ }
11132
+ try {
11133
+ const organization = await _getById(org);
11134
+ if (!organization) {
11135
+ next(new import_utils57.BadRequestError("Organization not found."));
11136
+ return;
11137
+ }
11138
+ next();
11139
+ } catch (error2) {
11140
+ next(error2);
11141
+ }
11142
+ }
11097
11143
  async function add(req, res, next) {
11098
11144
  const value = req.body;
11099
11145
  const { error } = schemaOrgAdd.validate(value);
@@ -11267,6 +11313,7 @@ function useOrgController() {
11267
11313
  }
11268
11314
  }
11269
11315
  return {
11316
+ validOrg,
11270
11317
  add,
11271
11318
  getOrgsByUserId,
11272
11319
  getByName,
@@ -13797,10 +13844,10 @@ function useCounterRepo() {
13797
13844
  throw new Error("Failed to create index.");
13798
13845
  }
13799
13846
  }
13800
- async function add(type) {
13847
+ async function add(type, session) {
13801
13848
  try {
13802
13849
  const value = createCounter({ type });
13803
- await collection.insertOne(value);
13850
+ await collection.insertOne(value, { session });
13804
13851
  delCachedData();
13805
13852
  } catch (error) {
13806
13853
  throw new Error("Failed to add counter.");
@@ -13810,7 +13857,7 @@ function useCounterRepo() {
13810
13857
  try {
13811
13858
  const res = await collection.updateOne(
13812
13859
  { type },
13813
- { $inc: { count: 1 } },
13860
+ { $inc: { count: 1 }, $set: { updatedAt: /* @__PURE__ */ new Date() } },
13814
13861
  { session }
13815
13862
  );
13816
13863
  delCachedData();
@@ -17004,6 +17051,2307 @@ function useJobSummaryCtrl() {
17004
17051
  getByOrg
17005
17052
  };
17006
17053
  }
17054
+
17055
+ // src/resources/finance-tax/tax.model.ts
17056
+ var import_utils87 = require("@goweekdays/utils");
17057
+ var import_joi69 = __toESM(require("joi"));
17058
+ var import_mongodb40 = require("mongodb");
17059
+ var taxDirections = ["input", "output", "withholding"];
17060
+ var schemaTax = import_joi69.default.object({
17061
+ org: import_joi69.default.string().hex().required(),
17062
+ name: import_joi69.default.string().required(),
17063
+ rate: import_joi69.default.number().required(),
17064
+ direction: import_joi69.default.string().valid(...taxDirections).required()
17065
+ });
17066
+ var schemaTaxUpdate = import_joi69.default.object({
17067
+ name: import_joi69.default.string().required(),
17068
+ rate: import_joi69.default.number().required(),
17069
+ direction: import_joi69.default.string().valid(...taxDirections).required()
17070
+ });
17071
+ function modelTax(data) {
17072
+ const { error } = schemaTax.validate(data);
17073
+ if (error) {
17074
+ throw new import_utils87.BadRequestError(`Invalid tax data: ${error.message}`);
17075
+ }
17076
+ try {
17077
+ data.org = new import_mongodb40.ObjectId(data.org);
17078
+ } catch (error2) {
17079
+ throw new import_utils87.BadRequestError(`Invalid org ID: ${data.org}`);
17080
+ }
17081
+ return {
17082
+ _id: data._id,
17083
+ org: data.org,
17084
+ name: data.name,
17085
+ rate: data.rate,
17086
+ direction: data.direction,
17087
+ status: data.status ?? "active",
17088
+ createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
17089
+ updatedAt: data.updatedAt ?? ""
17090
+ };
17091
+ }
17092
+
17093
+ // src/resources/finance-tax/tax.repository.ts
17094
+ var import_utils88 = require("@goweekdays/utils");
17095
+ var import_mongodb41 = require("mongodb");
17096
+ var import_joi70 = __toESM(require("joi"));
17097
+ function useTaxRepo() {
17098
+ const db = import_utils88.useAtlas.getDb();
17099
+ if (!db) {
17100
+ throw new import_utils88.BadRequestError("Unable to connect to server.");
17101
+ }
17102
+ const namespace_collection = "finance.taxes";
17103
+ const collection = db.collection(namespace_collection);
17104
+ const { getCache, setCache, delNamespace } = (0, import_utils88.useCache)(namespace_collection);
17105
+ function delCachedData() {
17106
+ delNamespace().then(() => {
17107
+ import_utils88.logger.log({
17108
+ level: "info",
17109
+ message: `Cache namespace cleared for ${namespace_collection}`
17110
+ });
17111
+ }).catch((err) => {
17112
+ import_utils88.logger.log({
17113
+ level: "error",
17114
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
17115
+ });
17116
+ });
17117
+ }
17118
+ async function createIndexes() {
17119
+ try {
17120
+ await collection.createIndexes([
17121
+ { key: { name: 1 } },
17122
+ { key: { org: 1 } },
17123
+ {
17124
+ key: { name: 1, org: 1 },
17125
+ partialFilterExpression: { status: "active" },
17126
+ unique: true,
17127
+ name: "unique_name_per_org"
17128
+ }
17129
+ ]);
17130
+ } catch (error) {
17131
+ throw new Error("Failed to create index on tax.");
17132
+ }
17133
+ }
17134
+ async function add(value, session) {
17135
+ try {
17136
+ value = modelTax(value);
17137
+ const res = await collection.insertOne(value, { session });
17138
+ delCachedData();
17139
+ return res.insertedId;
17140
+ } catch (error) {
17141
+ import_utils88.logger.log({
17142
+ level: "error",
17143
+ message: error.message
17144
+ });
17145
+ throw new import_utils88.BadRequestError(`Failed to create tax: ${error.message}`);
17146
+ }
17147
+ }
17148
+ async function getAll(options) {
17149
+ options.page = options.page && options.page > 0 ? options.page - 1 : 0;
17150
+ options.status = options.status ?? "active";
17151
+ options.limit = options.limit ?? 10;
17152
+ const query = { status: options.status };
17153
+ try {
17154
+ query.org = new import_mongodb41.ObjectId(options.org);
17155
+ } catch (error) {
17156
+ throw new import_utils88.BadRequestError("Invalid organization ID.");
17157
+ }
17158
+ if (options.search) {
17159
+ query.$text = { $search: options.search };
17160
+ }
17161
+ const cacheKey = (0, import_utils88.makeCacheKey)(namespace_collection, {
17162
+ search: options.search,
17163
+ page: options.page,
17164
+ limit: options.limit,
17165
+ status: options.status
17166
+ });
17167
+ import_utils88.logger.log({
17168
+ level: "info",
17169
+ message: `Cache key for getAll taxes: ${cacheKey}`
17170
+ });
17171
+ try {
17172
+ const cached = await getCache(cacheKey);
17173
+ if (cached) {
17174
+ import_utils88.logger.log({
17175
+ level: "info",
17176
+ message: `Cache hit for getAll taxes: ${cacheKey}`
17177
+ });
17178
+ return cached;
17179
+ }
17180
+ const items = await collection.aggregate([
17181
+ { $match: query },
17182
+ { $skip: options.page * options.limit },
17183
+ { $limit: options.limit },
17184
+ {
17185
+ $project: {
17186
+ _id: 1,
17187
+ org: 1,
17188
+ name: 1,
17189
+ rate: 1,
17190
+ direction: 1,
17191
+ status: 1,
17192
+ createdAt: 1
17193
+ }
17194
+ }
17195
+ ]).toArray();
17196
+ const length = await collection.countDocuments(query);
17197
+ const data = (0, import_utils88.paginate)(items, options.page, options.limit, length);
17198
+ setCache(cacheKey, data, 600).then(() => {
17199
+ import_utils88.logger.log({
17200
+ level: "info",
17201
+ message: `Cache set for getAll taxes: ${cacheKey}`
17202
+ });
17203
+ }).catch((err) => {
17204
+ import_utils88.logger.log({
17205
+ level: "error",
17206
+ message: `Failed to set cache for getAll taxes: ${err.message}`
17207
+ });
17208
+ });
17209
+ return data;
17210
+ } catch (error) {
17211
+ import_utils88.logger.log({ level: "error", message: `${error}` });
17212
+ throw error;
17213
+ }
17214
+ }
17215
+ async function getTaxesByOrg({ search = "", page = 1, limit = 10, org = "", status: status2 = "active" } = {}) {
17216
+ page = page > 0 ? page - 1 : 0;
17217
+ try {
17218
+ org = new import_mongodb41.ObjectId(org);
17219
+ } catch (error) {
17220
+ throw new import_utils88.BadRequestError("Invalid organization ID.");
17221
+ }
17222
+ const query = { org, status: status2 };
17223
+ const cacheKeyOptions = {
17224
+ org: String(org),
17225
+ status: status2,
17226
+ limit,
17227
+ page
17228
+ };
17229
+ if (search) {
17230
+ cacheKeyOptions.search = search;
17231
+ query.$text = { $search: search };
17232
+ }
17233
+ try {
17234
+ const cacheKey = (0, import_utils88.makeCacheKey)(namespace_collection, cacheKeyOptions);
17235
+ const cached = await getCache(
17236
+ cacheKey
17237
+ );
17238
+ if (cached) {
17239
+ import_utils88.logger.log({
17240
+ level: "info",
17241
+ message: `Cache hit for getTaxesByOrg : ${cacheKey}`
17242
+ });
17243
+ return cached;
17244
+ }
17245
+ const items = await collection.aggregate([
17246
+ { $match: query },
17247
+ { $skip: page * limit },
17248
+ { $limit: limit },
17249
+ {
17250
+ $project: {
17251
+ _id: 1,
17252
+ name: 1,
17253
+ rate: 1,
17254
+ direction: 1,
17255
+ status: 1,
17256
+ createdAt: 1
17257
+ }
17258
+ }
17259
+ ]).toArray();
17260
+ const length = await collection.countDocuments(query);
17261
+ const data = (0, import_utils88.paginate)(items, page, limit, length);
17262
+ setCache(cacheKey, data, 300).then(() => {
17263
+ import_utils88.logger.log({
17264
+ level: "info",
17265
+ message: `Cache set for getTaxesByOrg: ${cacheKey}`
17266
+ });
17267
+ }).catch((err) => {
17268
+ import_utils88.logger.log({
17269
+ level: "error",
17270
+ message: `Failed to set cache for getTaxesByOrg: ${err.message}`
17271
+ });
17272
+ });
17273
+ return data;
17274
+ } catch (error) {
17275
+ throw new import_utils88.InternalServerError(
17276
+ "Internal server error, failed to retrieve taxes."
17277
+ );
17278
+ }
17279
+ }
17280
+ async function getById(_id) {
17281
+ try {
17282
+ _id = new import_mongodb41.ObjectId(_id);
17283
+ } catch (error) {
17284
+ throw new import_utils88.BadRequestError("Invalid ID.");
17285
+ }
17286
+ const cacheKey = (0, import_utils88.makeCacheKey)(namespace_collection, { _id: String(_id) });
17287
+ try {
17288
+ const cached = await getCache(cacheKey);
17289
+ if (cached) {
17290
+ import_utils88.logger.log({
17291
+ level: "info",
17292
+ message: `Cache hit for getById tax: ${cacheKey}`
17293
+ });
17294
+ return cached;
17295
+ }
17296
+ const result = await collection.findOne({ _id });
17297
+ if (!result) {
17298
+ throw new import_utils88.BadRequestError("Tax not found.");
17299
+ }
17300
+ setCache(cacheKey, result, 300).then(() => {
17301
+ import_utils88.logger.log({
17302
+ level: "info",
17303
+ message: `Cache set for tax by id: ${cacheKey}`
17304
+ });
17305
+ }).catch((err) => {
17306
+ import_utils88.logger.log({
17307
+ level: "error",
17308
+ message: `Failed to set cache for tax by id: ${err.message}`
17309
+ });
17310
+ });
17311
+ return result;
17312
+ } catch (error) {
17313
+ if (error instanceof import_utils88.AppError) {
17314
+ throw error;
17315
+ } else {
17316
+ throw new import_utils88.InternalServerError("Failed to get tax.");
17317
+ }
17318
+ }
17319
+ }
17320
+ async function updateById(_id, options) {
17321
+ const { error: errorId } = import_joi70.default.string().hex().required().validate(String(_id));
17322
+ if (errorId) {
17323
+ throw new import_utils88.BadRequestError("Invalid Tax ID.");
17324
+ }
17325
+ const { error } = schemaTaxUpdate.validate(options);
17326
+ if (error) {
17327
+ throw new import_utils88.BadRequestError(`Invalid tax update data: ${error.message}`);
17328
+ }
17329
+ try {
17330
+ _id = new import_mongodb41.ObjectId(_id);
17331
+ } catch (error2) {
17332
+ throw new import_utils88.BadRequestError("Invalid Tax ID.");
17333
+ }
17334
+ try {
17335
+ await collection.updateOne(
17336
+ { _id },
17337
+ { $set: { ...options, updatedAt: /* @__PURE__ */ new Date() } }
17338
+ );
17339
+ delCachedData();
17340
+ return "Successfully updated tax.";
17341
+ } catch (error2) {
17342
+ throw new import_utils88.InternalServerError("Failed to update tax.");
17343
+ }
17344
+ }
17345
+ async function deleteById(_id, session) {
17346
+ try {
17347
+ _id = new import_mongodb41.ObjectId(_id);
17348
+ } catch (error) {
17349
+ throw new import_utils88.BadRequestError("Invalid ID.");
17350
+ }
17351
+ try {
17352
+ await collection.updateOne(
17353
+ { _id },
17354
+ {
17355
+ $set: {
17356
+ status: "deleted",
17357
+ updatedAt: /* @__PURE__ */ new Date(),
17358
+ deletedAt: /* @__PURE__ */ new Date()
17359
+ }
17360
+ },
17361
+ { session }
17362
+ );
17363
+ delCachedData();
17364
+ return "Successfully deleted tax.";
17365
+ } catch (error) {
17366
+ throw new import_utils88.InternalServerError("Failed to delete tax.");
17367
+ }
17368
+ }
17369
+ async function updateStatusById(_id, status2) {
17370
+ try {
17371
+ _id = new import_mongodb41.ObjectId(_id);
17372
+ } catch (error) {
17373
+ throw new import_utils88.BadRequestError("Invalid ID.");
17374
+ }
17375
+ try {
17376
+ const result = await collection.updateOne(
17377
+ { _id },
17378
+ {
17379
+ $set: {
17380
+ status: status2,
17381
+ updatedAt: /* @__PURE__ */ new Date()
17382
+ }
17383
+ }
17384
+ );
17385
+ if (result.matchedCount === 0) {
17386
+ throw new import_utils88.BadRequestError("Tax not found.");
17387
+ }
17388
+ delCachedData();
17389
+ return "Successfully updated tax status.";
17390
+ } catch (error) {
17391
+ if (error instanceof import_utils88.AppError) {
17392
+ throw error;
17393
+ }
17394
+ throw new import_utils88.InternalServerError("Failed to update tax status.");
17395
+ }
17396
+ }
17397
+ return {
17398
+ createIndexes,
17399
+ add,
17400
+ getAll,
17401
+ getTaxesByOrg,
17402
+ getById,
17403
+ updateById,
17404
+ deleteById,
17405
+ updateStatusById
17406
+ };
17407
+ }
17408
+
17409
+ // src/resources/finance-tax/tax.controller.ts
17410
+ var import_joi71 = __toESM(require("joi"));
17411
+ var import_utils89 = require("@goweekdays/utils");
17412
+ function useTaxController() {
17413
+ const {
17414
+ getAll: _getAll,
17415
+ getTaxesByOrg: _getTaxesByOrg,
17416
+ getById: _getById,
17417
+ updateById: _updateById,
17418
+ deleteById: _deleteById,
17419
+ updateStatusById: _updateStatusById,
17420
+ add: _add
17421
+ } = useTaxRepo();
17422
+ async function add(req, res, next) {
17423
+ const value = req.body;
17424
+ const { error } = schemaTax.validate(value);
17425
+ if (error) {
17426
+ next(new import_utils89.BadRequestError(error.message));
17427
+ import_utils89.logger.info(`Controller: ${error.message}`);
17428
+ return;
17429
+ }
17430
+ try {
17431
+ const message = await _add(value);
17432
+ res.json({ message });
17433
+ return;
17434
+ } catch (error2) {
17435
+ next(error2);
17436
+ }
17437
+ }
17438
+ async function getAll(req, res, next) {
17439
+ const query = req.query;
17440
+ const validation = import_joi71.default.object({
17441
+ org: import_joi71.default.string().hex().required(),
17442
+ page: import_joi71.default.number().min(1).optional().allow("", null),
17443
+ limit: import_joi71.default.number().min(1).optional().allow("", null),
17444
+ search: import_joi71.default.string().optional().allow("", null),
17445
+ status: import_joi71.default.string().optional()
17446
+ });
17447
+ const org = req.params.org ?? "";
17448
+ const { error } = validation.validate({ ...query, org });
17449
+ const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
17450
+ const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
17451
+ const search = req.query.search ?? "";
17452
+ const status2 = req.query.status ?? "active";
17453
+ const isPageNumber = isFinite(page);
17454
+ if (!isPageNumber) {
17455
+ next(new import_utils89.BadRequestError("Invalid page number."));
17456
+ return;
17457
+ }
17458
+ const isLimitNumber = isFinite(limit);
17459
+ if (!isLimitNumber) {
17460
+ next(new import_utils89.BadRequestError("Invalid limit number."));
17461
+ return;
17462
+ }
17463
+ if (error) {
17464
+ next(new import_utils89.BadRequestError(error.message));
17465
+ return;
17466
+ }
17467
+ try {
17468
+ const taxes = await _getAll({ org, page, limit, search, status: status2 });
17469
+ res.json(taxes);
17470
+ return;
17471
+ } catch (error2) {
17472
+ next(error2);
17473
+ }
17474
+ }
17475
+ async function getTaxesByOrg(req, res, next) {
17476
+ const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
17477
+ const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
17478
+ const search = req.query.search ?? "";
17479
+ const status2 = req.query.status ?? "active";
17480
+ const org = req.params.org ?? "";
17481
+ const isPageNumber = isFinite(page);
17482
+ if (!isPageNumber) {
17483
+ next(new import_utils89.BadRequestError("Invalid page number."));
17484
+ return;
17485
+ }
17486
+ const isLimitNumber = isFinite(limit);
17487
+ if (!isLimitNumber) {
17488
+ next(new import_utils89.BadRequestError("Invalid limit number."));
17489
+ return;
17490
+ }
17491
+ const validation = import_joi71.default.object({
17492
+ org: import_joi71.default.string().hex().required(),
17493
+ page: import_joi71.default.number().min(1).optional().allow("", null),
17494
+ limit: import_joi71.default.number().min(1).optional().allow("", null),
17495
+ search: import_joi71.default.string().optional().allow("", null),
17496
+ status: import_joi71.default.string().optional()
17497
+ });
17498
+ const { error } = validation.validate({ org, page, limit, search, status: status2 });
17499
+ if (error) {
17500
+ next(new import_utils89.BadRequestError(error.message));
17501
+ return;
17502
+ }
17503
+ try {
17504
+ const taxes = await _getTaxesByOrg({ org, page, limit, search, status: status2 });
17505
+ res.json(taxes);
17506
+ return;
17507
+ } catch (error2) {
17508
+ next(error2);
17509
+ }
17510
+ }
17511
+ async function getById(req, res, next) {
17512
+ const id = req.params.id;
17513
+ const validation = import_joi71.default.object({
17514
+ id: import_joi71.default.string().hex().required()
17515
+ });
17516
+ const { error } = validation.validate({ id });
17517
+ if (error) {
17518
+ next(new import_utils89.BadRequestError(error.message));
17519
+ return;
17520
+ }
17521
+ try {
17522
+ const tax = await _getById(id);
17523
+ res.json(tax);
17524
+ return;
17525
+ } catch (error2) {
17526
+ next(error2);
17527
+ }
17528
+ }
17529
+ async function updateById(req, res, next) {
17530
+ const _id = req.params.id ?? "";
17531
+ const { error: errorId } = import_joi71.default.string().hex().required().validate(_id);
17532
+ if (errorId) {
17533
+ next(new import_utils89.BadRequestError("Invalid Tax ID."));
17534
+ return;
17535
+ }
17536
+ const payload = req.body;
17537
+ const { error } = schemaTaxUpdate.validate(payload);
17538
+ if (error) {
17539
+ next(new import_utils89.BadRequestError(`Invalid tax update data: ${error.message}`));
17540
+ return;
17541
+ }
17542
+ try {
17543
+ const message = await _updateById(_id, payload);
17544
+ res.json({ message });
17545
+ return;
17546
+ } catch (error2) {
17547
+ next(error2);
17548
+ }
17549
+ }
17550
+ async function deleteById(req, res, next) {
17551
+ const id = req.params.id;
17552
+ if (!id) {
17553
+ next(new import_utils89.BadRequestError("Tax ID is required."));
17554
+ return;
17555
+ }
17556
+ try {
17557
+ const message = await _deleteById(id);
17558
+ res.json(message);
17559
+ return;
17560
+ } catch (error) {
17561
+ next(error);
17562
+ }
17563
+ }
17564
+ async function updateStatusById(req, res, next) {
17565
+ const id = req.params.id;
17566
+ const status2 = req.params.status;
17567
+ const validation = import_joi71.default.object({
17568
+ id: import_joi71.default.string().hex().required(),
17569
+ status: import_joi71.default.string().required()
17570
+ });
17571
+ const { error } = validation.validate({ id, status: status2 });
17572
+ if (error) {
17573
+ next(new import_utils89.BadRequestError(error.message));
17574
+ return;
17575
+ }
17576
+ try {
17577
+ const message = await _updateStatusById(id, status2);
17578
+ res.json({ message });
17579
+ return;
17580
+ } catch (error2) {
17581
+ next(error2);
17582
+ }
17583
+ }
17584
+ return {
17585
+ add,
17586
+ getAll,
17587
+ getTaxesByOrg,
17588
+ getById,
17589
+ updateById,
17590
+ deleteById,
17591
+ updateStatusById
17592
+ };
17593
+ }
17594
+
17595
+ // src/resources/finance-account/chart-of-account.model.ts
17596
+ var import_joi72 = __toESM(require("joi"));
17597
+ var import_mongodb42 = require("mongodb");
17598
+ var chartOfAccountTypes = [
17599
+ "asset",
17600
+ "liability",
17601
+ "equity",
17602
+ "income",
17603
+ "expense"
17604
+ ];
17605
+ var chartOfAccountNormalBalances = [
17606
+ "debit",
17607
+ "credit"
17608
+ ];
17609
+ var schemaChartOfAccount = {
17610
+ type: import_joi72.default.string().valid(...chartOfAccountTypes).required(),
17611
+ normalBalance: import_joi72.default.string().valid(...chartOfAccountNormalBalances).required(),
17612
+ parent: import_joi72.default.string().hex().optional().allow("", null),
17613
+ name: import_joi72.default.string().required(),
17614
+ code: import_joi72.default.string().required(),
17615
+ tax: import_joi72.default.string().hex().optional().allow("", null)
17616
+ };
17617
+ var schemaChartOfAccountBase = import_joi72.default.object({
17618
+ ...schemaChartOfAccount,
17619
+ org: import_joi72.default.string().hex().required(),
17620
+ isContra: import_joi72.default.boolean().required()
17621
+ });
17622
+ var schemaChartOfAccountStd = import_joi72.default.object({
17623
+ ...schemaChartOfAccount,
17624
+ org: import_joi72.default.string().hex().required(),
17625
+ isContra: import_joi72.default.boolean().required(),
17626
+ path: import_joi72.default.string().required(),
17627
+ parentName: import_joi72.default.string().optional().allow("", null)
17628
+ });
17629
+ var schemaChartOfAccountUpdate = import_joi72.default.object({
17630
+ ...schemaChartOfAccount,
17631
+ isContra: import_joi72.default.boolean().required()
17632
+ });
17633
+ function modelChartOfAccount(data) {
17634
+ const { error } = schemaChartOfAccountStd.validate(data);
17635
+ if (error) {
17636
+ throw new Error(`Invalid chart of account data: ${error.message}`);
17637
+ }
17638
+ try {
17639
+ data.org = new import_mongodb42.ObjectId(data.org);
17640
+ } catch (error2) {
17641
+ throw new Error(`Invalid org ID: ${data.org}`);
17642
+ }
17643
+ if (data.parent) {
17644
+ try {
17645
+ data.parent = new import_mongodb42.ObjectId(data.parent);
17646
+ } catch (error2) {
17647
+ throw new Error(`Invalid parent ID: ${data.parent}`);
17648
+ }
17649
+ }
17650
+ if (data.tax) {
17651
+ try {
17652
+ data.tax = new import_mongodb42.ObjectId(data.tax);
17653
+ } catch (error2) {
17654
+ throw new Error(`Invalid tax ID: ${data.tax}`);
17655
+ }
17656
+ }
17657
+ return {
17658
+ _id: data._id,
17659
+ org: data.org,
17660
+ type: data.type,
17661
+ normalBalance: data.normalBalance,
17662
+ parent: data.parent,
17663
+ parentName: data.parentName ?? "",
17664
+ path: data.path,
17665
+ name: data.name,
17666
+ code: data.code,
17667
+ tax: data.tax,
17668
+ isContra: data.isContra,
17669
+ status: data.status ?? "active",
17670
+ createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
17671
+ updatedAt: data.updatedAt ?? ""
17672
+ };
17673
+ }
17674
+
17675
+ // src/resources/finance-account/chart-of-account.repository.ts
17676
+ var import_utils90 = require("@goweekdays/utils");
17677
+ var import_mongodb43 = require("mongodb");
17678
+ var import_joi73 = __toESM(require("joi"));
17679
+ function useChartOfAccountRepo() {
17680
+ const db = import_utils90.useAtlas.getDb();
17681
+ if (!db) {
17682
+ throw new import_utils90.BadRequestError("Unable to connect to server.");
17683
+ }
17684
+ const namespace_collection = "finance.accounts";
17685
+ const collection = db.collection(namespace_collection);
17686
+ const { getCache, setCache, delNamespace } = (0, import_utils90.useCache)(namespace_collection);
17687
+ function delCachedData() {
17688
+ delNamespace().then(() => {
17689
+ import_utils90.logger.log({
17690
+ level: "info",
17691
+ message: `Cache namespace cleared for ${namespace_collection}`
17692
+ });
17693
+ }).catch((err) => {
17694
+ import_utils90.logger.log({
17695
+ level: "error",
17696
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
17697
+ });
17698
+ });
17699
+ }
17700
+ async function createIndexes() {
17701
+ try {
17702
+ await collection.createIndexes([
17703
+ { key: { name: 1 } },
17704
+ { key: { org: 1 } },
17705
+ { key: { code: 1 } },
17706
+ { key: { path: 1 } },
17707
+ { key: { name: 1, org: 1 }, unique: true, name: "unique_name_per_org" },
17708
+ { key: { code: 1, org: 1 }, unique: true, name: "unique_code_per_org" }
17709
+ ]);
17710
+ } catch (error) {
17711
+ throw new Error("Failed to create index on chart of account.");
17712
+ }
17713
+ }
17714
+ async function add(value, session) {
17715
+ try {
17716
+ value = modelChartOfAccount(value);
17717
+ const res = await collection.insertOne(value, { session });
17718
+ delCachedData();
17719
+ return res.insertedId;
17720
+ } catch (error) {
17721
+ import_utils90.logger.log({
17722
+ level: "error",
17723
+ message: error.message
17724
+ });
17725
+ throw new import_utils90.BadRequestError(
17726
+ `Failed to create chart of account: ${error.message}`
17727
+ );
17728
+ }
17729
+ }
17730
+ async function getAll(options) {
17731
+ const validation = import_joi73.default.object({
17732
+ org: import_joi73.default.string().hex().required(),
17733
+ page: import_joi73.default.number().min(1).optional().allow("", null),
17734
+ limit: import_joi73.default.number().min(1).optional().allow("", null),
17735
+ search: import_joi73.default.string().optional().allow("", null),
17736
+ status: import_joi73.default.string().optional().allow("", null)
17737
+ });
17738
+ const { error } = validation.validate(options);
17739
+ if (error) {
17740
+ throw new import_utils90.BadRequestError(error.message);
17741
+ }
17742
+ options.page = options.page && options.page > 0 ? options.page - 1 : 0;
17743
+ options.status = options.status ?? "active";
17744
+ options.limit = options.limit ?? 10;
17745
+ const query = { status: options.status };
17746
+ try {
17747
+ query.org = new import_mongodb43.ObjectId(options.org);
17748
+ } catch (error2) {
17749
+ throw new import_utils90.BadRequestError("Invalid organization ID.");
17750
+ }
17751
+ if (options.search) {
17752
+ query.$text = { $search: options.search };
17753
+ }
17754
+ const cacheKey = (0, import_utils90.makeCacheKey)(namespace_collection, {
17755
+ search: options.search,
17756
+ page: options.page,
17757
+ limit: options.limit,
17758
+ status: options.status
17759
+ });
17760
+ import_utils90.logger.log({
17761
+ level: "info",
17762
+ message: `Cache key for getAll chart of accounts: ${cacheKey}`
17763
+ });
17764
+ try {
17765
+ const cached = await getCache(cacheKey);
17766
+ if (cached) {
17767
+ import_utils90.logger.log({
17768
+ level: "info",
17769
+ message: `Cache hit for getAll chart of accounts: ${cacheKey}`
17770
+ });
17771
+ return cached;
17772
+ }
17773
+ const items = await collection.aggregate([
17774
+ { $match: query },
17775
+ { $sort: { path: 1 } },
17776
+ { $skip: options.page * options.limit },
17777
+ { $limit: options.limit },
17778
+ {
17779
+ $project: {
17780
+ _id: 1,
17781
+ type: 1,
17782
+ normalBalance: 1,
17783
+ parent: 1,
17784
+ parentName: 1,
17785
+ path: 1,
17786
+ name: 1,
17787
+ code: 1,
17788
+ tax: 1,
17789
+ status: 1
17790
+ }
17791
+ }
17792
+ ]).toArray();
17793
+ const length = await collection.countDocuments(query);
17794
+ const data = (0, import_utils90.paginate)(items, options.page, options.limit, length);
17795
+ setCache(cacheKey, data, 600).then(() => {
17796
+ import_utils90.logger.log({
17797
+ level: "info",
17798
+ message: `Cache set for getAll chart of accounts: ${cacheKey}`
17799
+ });
17800
+ }).catch((err) => {
17801
+ import_utils90.logger.log({
17802
+ level: "error",
17803
+ message: `Failed to set cache for getAll chart of accounts: ${err.message}`
17804
+ });
17805
+ });
17806
+ return data;
17807
+ } catch (error2) {
17808
+ import_utils90.logger.log({ level: "error", message: `${error2}` });
17809
+ throw error2;
17810
+ }
17811
+ }
17812
+ async function getByOrg({ search = "", page = 1, limit = 10, org = "", status: status2 = "active" } = {}) {
17813
+ page = page > 0 ? page - 1 : 0;
17814
+ try {
17815
+ org = new import_mongodb43.ObjectId(org);
17816
+ } catch (error) {
17817
+ throw new import_utils90.BadRequestError("Invalid organization ID.");
17818
+ }
17819
+ const query = { org, status: status2 };
17820
+ const cacheKeyOptions = {
17821
+ org: String(org),
17822
+ status: status2,
17823
+ limit,
17824
+ page
17825
+ };
17826
+ if (search) {
17827
+ cacheKeyOptions.search = search;
17828
+ query.$text = { $search: search };
17829
+ }
17830
+ try {
17831
+ const cacheKey = (0, import_utils90.makeCacheKey)(namespace_collection, cacheKeyOptions);
17832
+ const cached = await getCache(
17833
+ cacheKey
17834
+ );
17835
+ if (cached) {
17836
+ import_utils90.logger.log({
17837
+ level: "info",
17838
+ message: `Cache hit for getByOrg: ${cacheKey}`
17839
+ });
17840
+ return cached;
17841
+ }
17842
+ const items = await collection.aggregate([
17843
+ { $match: query },
17844
+ { $skip: page * limit },
17845
+ { $limit: limit },
17846
+ {
17847
+ $project: {
17848
+ _id: 1,
17849
+ org: 1,
17850
+ type: 1,
17851
+ normalBalance: 1,
17852
+ parent: 1,
17853
+ name: 1,
17854
+ code: 1,
17855
+ tax: 1,
17856
+ status: 1,
17857
+ createdAt: 1,
17858
+ updatedAt: 1
17859
+ }
17860
+ }
17861
+ ]).toArray();
17862
+ const length = await collection.countDocuments(query);
17863
+ const data = (0, import_utils90.paginate)(items, page, limit, length);
17864
+ setCache(cacheKey, data, 300).then(() => {
17865
+ import_utils90.logger.log({
17866
+ level: "info",
17867
+ message: `Cache set for getByOrg: ${cacheKey}`
17868
+ });
17869
+ }).catch((err) => {
17870
+ import_utils90.logger.log({
17871
+ level: "error",
17872
+ message: `Failed to set cache for getByOrg: ${err.message}`
17873
+ });
17874
+ });
17875
+ return data;
17876
+ } catch (error) {
17877
+ throw new import_utils90.InternalServerError(
17878
+ "Internal server error, failed to retrieve chart of accounts."
17879
+ );
17880
+ }
17881
+ }
17882
+ async function getById(_id) {
17883
+ try {
17884
+ _id = new import_mongodb43.ObjectId(_id);
17885
+ } catch (error) {
17886
+ throw new import_utils90.BadRequestError("Invalid ID.");
17887
+ }
17888
+ const cacheKey = (0, import_utils90.makeCacheKey)(namespace_collection, { _id: String(_id) });
17889
+ try {
17890
+ const cached = await getCache(cacheKey);
17891
+ if (cached) {
17892
+ import_utils90.logger.log({
17893
+ level: "info",
17894
+ message: `Cache hit for getById chart of account: ${cacheKey}`
17895
+ });
17896
+ return cached;
17897
+ }
17898
+ const result = await collection.findOne({ _id });
17899
+ if (!result) {
17900
+ throw new import_utils90.BadRequestError("Chart of account not found.");
17901
+ }
17902
+ setCache(cacheKey, result, 300).then(() => {
17903
+ import_utils90.logger.log({
17904
+ level: "info",
17905
+ message: `Cache set for chart of account by id: ${cacheKey}`
17906
+ });
17907
+ }).catch((err) => {
17908
+ import_utils90.logger.log({
17909
+ level: "error",
17910
+ message: `Failed to set cache for chart of account by id: ${err.message}`
17911
+ });
17912
+ });
17913
+ return result;
17914
+ } catch (error) {
17915
+ if (error instanceof import_utils90.AppError) {
17916
+ throw error;
17917
+ } else {
17918
+ throw new import_utils90.InternalServerError("Failed to get chart of account.");
17919
+ }
17920
+ }
17921
+ }
17922
+ async function updateById(_id, options, session) {
17923
+ try {
17924
+ _id = new import_mongodb43.ObjectId(_id);
17925
+ } catch (error) {
17926
+ throw new import_utils90.BadRequestError("Invalid Chart of Account ID.");
17927
+ }
17928
+ try {
17929
+ await collection.updateOne(
17930
+ { _id },
17931
+ { $set: { ...options, updatedAt: /* @__PURE__ */ new Date() } }
17932
+ );
17933
+ delCachedData();
17934
+ return "Successfully updated chart of account.";
17935
+ } catch (error) {
17936
+ throw new import_utils90.InternalServerError("Failed to update chart of account.");
17937
+ }
17938
+ }
17939
+ async function deleteById(_id, session) {
17940
+ try {
17941
+ _id = new import_mongodb43.ObjectId(_id);
17942
+ } catch (error) {
17943
+ throw new import_utils90.BadRequestError("Invalid ID.");
17944
+ }
17945
+ try {
17946
+ await collection.updateOne(
17947
+ { _id },
17948
+ {
17949
+ $set: {
17950
+ status: "archived",
17951
+ updatedAt: /* @__PURE__ */ new Date(),
17952
+ deletedAt: /* @__PURE__ */ new Date()
17953
+ }
17954
+ },
17955
+ { session }
17956
+ );
17957
+ delCachedData();
17958
+ return "Successfully archived chart of account.";
17959
+ } catch (error) {
17960
+ throw new import_utils90.InternalServerError("Failed to archive chart of account.");
17961
+ }
17962
+ }
17963
+ async function updateStatusById(_id, status2) {
17964
+ try {
17965
+ _id = new import_mongodb43.ObjectId(_id);
17966
+ } catch (error) {
17967
+ throw new import_utils90.BadRequestError("Invalid ID.");
17968
+ }
17969
+ try {
17970
+ const result = await collection.updateOne(
17971
+ { _id },
17972
+ {
17973
+ $set: {
17974
+ status: status2,
17975
+ updatedAt: /* @__PURE__ */ new Date()
17976
+ }
17977
+ }
17978
+ );
17979
+ if (result.matchedCount === 0) {
17980
+ throw new import_utils90.BadRequestError("Chart of account not found.");
17981
+ }
17982
+ delCachedData();
17983
+ return "Successfully updated chart of account status.";
17984
+ } catch (error) {
17985
+ if (error instanceof import_utils90.AppError) {
17986
+ throw error;
17987
+ }
17988
+ throw new import_utils90.InternalServerError(
17989
+ "Failed to update chart of account status."
17990
+ );
17991
+ }
17992
+ }
17993
+ async function countByPath(path) {
17994
+ const { error } = import_joi73.default.string().required().validate(path);
17995
+ if (error) {
17996
+ throw new import_utils90.BadRequestError("Path is required and must be a string.");
17997
+ }
17998
+ try {
17999
+ const count = await collection.countDocuments({
18000
+ path: { $regex: `^${path}(-|$)` }
18001
+ });
18002
+ return count;
18003
+ } catch (error2) {
18004
+ throw new import_utils90.InternalServerError(
18005
+ "Failed to count chart of accounts by path."
18006
+ );
18007
+ }
18008
+ }
18009
+ return {
18010
+ createIndexes,
18011
+ add,
18012
+ getAll,
18013
+ getByOrg,
18014
+ getById,
18015
+ updateById,
18016
+ deleteById,
18017
+ updateStatusById,
18018
+ countByPath
18019
+ };
18020
+ }
18021
+
18022
+ // src/resources/finance-account/chart-of-account.controller.ts
18023
+ var import_joi75 = __toESM(require("joi"));
18024
+ var import_utils92 = require("@goweekdays/utils");
18025
+
18026
+ // src/resources/finance-account/chart-of-account.service.ts
18027
+ var import_utils91 = require("@goweekdays/utils");
18028
+ var import_joi74 = __toESM(require("joi"));
18029
+ function useChartOfAccountService() {
18030
+ const {
18031
+ add: _add,
18032
+ getById: _getById,
18033
+ updateById: _updateById,
18034
+ deleteById: _deleteById,
18035
+ countByPath
18036
+ } = useChartOfAccountRepo();
18037
+ async function add(value) {
18038
+ const { error } = schemaChartOfAccountBase.validate(value);
18039
+ if (error) {
18040
+ throw new import_utils91.BadRequestError(error.message);
18041
+ }
18042
+ const session = import_utils91.useAtlas.getClient()?.startSession();
18043
+ if (!session) {
18044
+ throw new Error("Failed to start database session.");
18045
+ }
18046
+ try {
18047
+ session.startTransaction();
18048
+ const data = {
18049
+ org: value.org,
18050
+ name: value.name,
18051
+ code: value.code,
18052
+ type: value.type,
18053
+ normalBalance: value.normalBalance,
18054
+ parent: value.parent,
18055
+ path: value.code,
18056
+ tax: value.tax,
18057
+ isContra: value.isContra
18058
+ };
18059
+ let parentAccount = null;
18060
+ if (value.parent) {
18061
+ parentAccount = await _getById(value.parent);
18062
+ if (!parentAccount) {
18063
+ throw new import_utils91.BadRequestError("Parent account not found.");
18064
+ }
18065
+ data.path = `${parentAccount.path}-${data.code}`;
18066
+ data.parentName = parentAccount.name;
18067
+ data.type = parentAccount.type;
18068
+ data.normalBalance = parentAccount.normalBalance;
18069
+ }
18070
+ const message = await _add(data, session);
18071
+ await session.commitTransaction();
18072
+ return message;
18073
+ } catch (error2) {
18074
+ await session.abortTransaction();
18075
+ throw error2;
18076
+ } finally {
18077
+ session.endSession();
18078
+ }
18079
+ }
18080
+ async function updateById(id, value) {
18081
+ const { error: errorId } = import_joi74.default.string().hex().required().validate(id);
18082
+ if (errorId) {
18083
+ throw new import_utils91.BadRequestError("Invalid Chart of Account ID.");
18084
+ }
18085
+ const { error } = schemaChartOfAccountUpdate.validate(value);
18086
+ if (error) {
18087
+ throw new import_utils91.BadRequestError(
18088
+ `Invalid chart of account update data: ${error.message}`
18089
+ );
18090
+ }
18091
+ const session = import_utils91.useAtlas.getClient()?.startSession();
18092
+ if (!session) {
18093
+ throw new Error("Failed to start database session.");
18094
+ }
18095
+ try {
18096
+ session.startTransaction();
18097
+ const existingAccount = await _getById(id);
18098
+ if (!existingAccount) {
18099
+ throw new import_utils91.BadRequestError("Chart of Account not found.");
18100
+ }
18101
+ const updatedData = {
18102
+ org: existingAccount.org,
18103
+ name: value.name,
18104
+ code: value.code,
18105
+ type: value.type,
18106
+ normalBalance: value.normalBalance,
18107
+ parent: value.parent ?? "",
18108
+ parentName: "",
18109
+ tax: value.tax,
18110
+ path: existingAccount.path,
18111
+ isContra: value.isContra
18112
+ };
18113
+ if (value.parent) {
18114
+ const parentAccount = await _getById(value.parent);
18115
+ if (!parentAccount) {
18116
+ throw new import_utils91.BadRequestError("Parent account not found.");
18117
+ }
18118
+ updatedData.path = `${parentAccount.path}-${value.code}`;
18119
+ updatedData.parentName = parentAccount.name;
18120
+ updatedData.type = parentAccount.type;
18121
+ updatedData.normalBalance = parentAccount.normalBalance;
18122
+ } else {
18123
+ updatedData.path = value.code;
18124
+ updatedData.parentName = "";
18125
+ }
18126
+ const message = await _updateById(id, updatedData, session);
18127
+ await session.commitTransaction();
18128
+ return message;
18129
+ } catch (error2) {
18130
+ await session.abortTransaction();
18131
+ throw error2;
18132
+ } finally {
18133
+ session.endSession();
18134
+ }
18135
+ }
18136
+ async function deleteById(id) {
18137
+ const { error } = import_joi74.default.string().hex().required().validate(id);
18138
+ if (error) {
18139
+ throw new import_utils91.BadRequestError("Invalid Chart of Account ID.");
18140
+ }
18141
+ const session = import_utils91.useAtlas.getClient()?.startSession();
18142
+ if (!session) {
18143
+ throw new Error("Failed to start database session.");
18144
+ }
18145
+ try {
18146
+ session.startTransaction();
18147
+ const existingAccount = await _getById(id);
18148
+ if (!existingAccount) {
18149
+ throw new import_utils91.BadRequestError("Chart of Account not found.");
18150
+ }
18151
+ const childCount = await countByPath(existingAccount.path);
18152
+ if (childCount > 1) {
18153
+ throw new import_utils91.BadRequestError(
18154
+ "Cannot delete account with child accounts. Please delete child accounts first."
18155
+ );
18156
+ }
18157
+ const message = await _deleteById(id, session);
18158
+ await session.commitTransaction();
18159
+ return message;
18160
+ } catch (error2) {
18161
+ await session.abortTransaction();
18162
+ throw error2;
18163
+ } finally {
18164
+ session.endSession();
18165
+ }
18166
+ }
18167
+ return {
18168
+ add,
18169
+ updateById,
18170
+ deleteById
18171
+ };
18172
+ }
18173
+
18174
+ // src/resources/finance-account/chart-of-account.controller.ts
18175
+ function useChartOfAccountController() {
18176
+ const {
18177
+ getAll: _getAll,
18178
+ getByOrg: _getByOrg,
18179
+ getById: _getById,
18180
+ updateStatusById: _updateStatusById
18181
+ } = useChartOfAccountRepo();
18182
+ const {
18183
+ add: _add,
18184
+ updateById: _updateById,
18185
+ deleteById: _deleteById
18186
+ } = useChartOfAccountService();
18187
+ async function add(req, res, next) {
18188
+ const value = req.body;
18189
+ const { error } = schemaChartOfAccountBase.validate(value);
18190
+ if (error) {
18191
+ next(new import_utils92.BadRequestError(error.message));
18192
+ import_utils92.logger.info(`Controller: ${error.message}`);
18193
+ return;
18194
+ }
18195
+ try {
18196
+ const message = await _add(value);
18197
+ res.json({ message });
18198
+ return;
18199
+ } catch (error2) {
18200
+ next(error2);
18201
+ }
18202
+ }
18203
+ async function getAll(req, res, next) {
18204
+ const query = req.query;
18205
+ const validation = import_joi75.default.object({
18206
+ org: import_joi75.default.string().hex().required(),
18207
+ page: import_joi75.default.number().min(1).optional().allow("", null),
18208
+ limit: import_joi75.default.number().min(1).optional().allow("", null),
18209
+ search: import_joi75.default.string().optional().allow("", null),
18210
+ status: import_joi75.default.string().optional().allow("", null)
18211
+ });
18212
+ const org = req.params.org ?? "";
18213
+ const { error } = validation.validate({ ...query, org });
18214
+ const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
18215
+ const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
18216
+ const search = req.query.search ?? "";
18217
+ const status2 = req.query.status ?? "active";
18218
+ const isPageNumber = isFinite(page);
18219
+ if (!isPageNumber) {
18220
+ next(new import_utils92.BadRequestError("Invalid page number."));
18221
+ return;
18222
+ }
18223
+ const isLimitNumber = isFinite(limit);
18224
+ if (!isLimitNumber) {
18225
+ next(new import_utils92.BadRequestError("Invalid limit number."));
18226
+ return;
18227
+ }
18228
+ if (error) {
18229
+ next(new import_utils92.BadRequestError(error.message));
18230
+ return;
18231
+ }
18232
+ try {
18233
+ const accounts = await _getAll({ org, page, limit, search, status: status2 });
18234
+ res.json(accounts);
18235
+ return;
18236
+ } catch (error2) {
18237
+ next(error2);
18238
+ }
18239
+ }
18240
+ async function getByOrg(req, res, next) {
18241
+ const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
18242
+ const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
18243
+ const search = req.query.search ?? "";
18244
+ const status2 = req.query.status ?? "active";
18245
+ const org = req.params.org ?? "";
18246
+ const isPageNumber = isFinite(page);
18247
+ if (!isPageNumber) {
18248
+ next(new import_utils92.BadRequestError("Invalid page number."));
18249
+ return;
18250
+ }
18251
+ const isLimitNumber = isFinite(limit);
18252
+ if (!isLimitNumber) {
18253
+ next(new import_utils92.BadRequestError("Invalid limit number."));
18254
+ return;
18255
+ }
18256
+ const validation = import_joi75.default.object({
18257
+ org: import_joi75.default.string().hex().required(),
18258
+ page: import_joi75.default.number().min(1).optional().allow("", null),
18259
+ limit: import_joi75.default.number().min(1).optional().allow("", null),
18260
+ search: import_joi75.default.string().optional().allow("", null),
18261
+ status: import_joi75.default.string().optional()
18262
+ });
18263
+ const { error } = validation.validate({ org, page, limit, search, status: status2 });
18264
+ if (error) {
18265
+ next(new import_utils92.BadRequestError(error.message));
18266
+ return;
18267
+ }
18268
+ try {
18269
+ const accounts = await _getByOrg({ org, page, limit, search, status: status2 });
18270
+ res.json(accounts);
18271
+ return;
18272
+ } catch (error2) {
18273
+ next(error2);
18274
+ }
18275
+ }
18276
+ async function getById(req, res, next) {
18277
+ const id = req.params.id;
18278
+ const validation = import_joi75.default.object({
18279
+ id: import_joi75.default.string().hex().required()
18280
+ });
18281
+ const { error } = validation.validate({ id });
18282
+ if (error) {
18283
+ next(new import_utils92.BadRequestError(error.message));
18284
+ return;
18285
+ }
18286
+ try {
18287
+ const account = await _getById(id);
18288
+ res.json(account);
18289
+ return;
18290
+ } catch (error2) {
18291
+ next(error2);
18292
+ }
18293
+ }
18294
+ async function updateById(req, res, next) {
18295
+ const _id = req.params.id;
18296
+ const { error: errorId } = import_joi75.default.string().hex().required().validate(_id);
18297
+ if (errorId) {
18298
+ next(new import_utils92.BadRequestError("Invalid Chart of Account ID."));
18299
+ return;
18300
+ }
18301
+ const payload = req.body;
18302
+ const { error } = schemaChartOfAccountUpdate.validate(payload);
18303
+ if (error) {
18304
+ next(new import_utils92.BadRequestError(error.message));
18305
+ return;
18306
+ }
18307
+ try {
18308
+ const message = await _updateById(_id, payload);
18309
+ res.json({ message });
18310
+ return;
18311
+ } catch (error2) {
18312
+ next(error2);
18313
+ }
18314
+ }
18315
+ async function deleteById(req, res, next) {
18316
+ const id = req.params.id;
18317
+ if (!id) {
18318
+ next(new import_utils92.BadRequestError("Chart of Account ID is required."));
18319
+ return;
18320
+ }
18321
+ try {
18322
+ const message = await _deleteById(id);
18323
+ res.json(message);
18324
+ return;
18325
+ } catch (error) {
18326
+ next(error);
18327
+ }
18328
+ }
18329
+ async function updateStatusById(req, res, next) {
18330
+ const id = req.params.id;
18331
+ const status2 = req.params.status;
18332
+ const validation = import_joi75.default.object({
18333
+ id: import_joi75.default.string().hex().required(),
18334
+ status: import_joi75.default.string().required()
18335
+ });
18336
+ const { error } = validation.validate({ id, status: status2 });
18337
+ if (error) {
18338
+ next(new import_utils92.BadRequestError(error.message));
18339
+ return;
18340
+ }
18341
+ try {
18342
+ const message = await _updateStatusById(id, status2);
18343
+ res.json({ message });
18344
+ return;
18345
+ } catch (error2) {
18346
+ next(error2);
18347
+ }
18348
+ }
18349
+ return {
18350
+ add,
18351
+ getAll,
18352
+ getByOrg,
18353
+ getById,
18354
+ updateById,
18355
+ deleteById,
18356
+ updateStatusById
18357
+ };
18358
+ }
18359
+
18360
+ // src/resources/finance-journal/finance.journal.entry.model.ts
18361
+ var import_utils93 = require("@goweekdays/utils");
18362
+ var import_joi76 = __toESM(require("joi"));
18363
+ var import_mongodb44 = require("mongodb");
18364
+ var journalEntryStatuses = [
18365
+ "draft",
18366
+ "posted",
18367
+ "voided"
18368
+ ];
18369
+ var journalEntryTypes = [
18370
+ "general",
18371
+ "sales",
18372
+ "purchases",
18373
+ "cash-receipts",
18374
+ "cash-disbursements"
18375
+ ];
18376
+ var schemaJournalEntryBase = {
18377
+ org: import_joi76.default.string().hex().required(),
18378
+ book: import_joi76.default.string().valid(...journalEntryTypes).required(),
18379
+ date: import_joi76.default.date().required(),
18380
+ type: import_joi76.default.string().required(),
18381
+ description: import_joi76.default.string().required(),
18382
+ createdBy: import_joi76.default.string().hex().required(),
18383
+ metadata: import_joi76.default.object({
18384
+ customerId: import_joi76.default.string().hex().optional().allow("", null),
18385
+ supplierId: import_joi76.default.string().hex().optional().allow("", null),
18386
+ itemId: import_joi76.default.string().hex().optional().allow("", null),
18387
+ assetId: import_joi76.default.string().hex().optional().allow("", null),
18388
+ purchaseOrderId: import_joi76.default.string().hex().optional().allow("", null),
18389
+ salesOrderId: import_joi76.default.string().hex().optional().allow("", null)
18390
+ }).optional()
18391
+ };
18392
+ var schemaJournalEntryCtrl = import_joi76.default.object(schemaJournalEntryBase);
18393
+ var schemaJournalEntryRepo = import_joi76.default.object({
18394
+ ...schemaJournalEntryBase,
18395
+ id: import_joi76.default.string().required(),
18396
+ createdByName: import_joi76.default.string().required(),
18397
+ status: import_joi76.default.string().valid(...journalEntryStatuses).required()
18398
+ });
18399
+ var schemaJournalEntryGetAll = import_joi76.default.object({
18400
+ org: import_joi76.default.string().hex().required(),
18401
+ page: import_joi76.default.number().optional().allow("", null),
18402
+ limit: import_joi76.default.number().max(100).optional().allow("", null),
18403
+ book: import_joi76.default.string().required().allow("", null),
18404
+ type: import_joi76.default.string().optional().allow("", null),
18405
+ search: import_joi76.default.string().optional().allow("", null),
18406
+ status: import_joi76.default.string().optional().allow("", null)
18407
+ });
18408
+ function modelJournalEntry(data) {
18409
+ const { error } = schemaJournalEntryRepo.validate(data);
18410
+ if (error) {
18411
+ throw new Error(`Invalid journal entry data: ${error.message}`);
18412
+ }
18413
+ try {
18414
+ data.org = new import_mongodb44.ObjectId(data.org);
18415
+ } catch (error2) {
18416
+ throw new import_utils93.BadRequestError(`Invalid org ID: ${data.org}`);
18417
+ }
18418
+ try {
18419
+ data.createdBy = new import_mongodb44.ObjectId(data.createdBy);
18420
+ } catch (error2) {
18421
+ throw new import_utils93.BadRequestError(`Invalid createdBy ID: ${data.createdBy}`);
18422
+ }
18423
+ const date = /* @__PURE__ */ new Date();
18424
+ if (data.metadata) {
18425
+ if (data.metadata.customerId) {
18426
+ try {
18427
+ data.metadata.customerId = new import_mongodb44.ObjectId(data.metadata.customerId);
18428
+ } catch (error2) {
18429
+ throw new import_utils93.BadRequestError(
18430
+ `Invalid customer ID: ${data.metadata.customerId}`
18431
+ );
18432
+ }
18433
+ }
18434
+ if (data.metadata.supplierId) {
18435
+ try {
18436
+ data.metadata.supplierId = new import_mongodb44.ObjectId(data.metadata.supplierId);
18437
+ } catch (error2) {
18438
+ throw new import_utils93.BadRequestError(
18439
+ `Invalid supplier ID: ${data.metadata.supplierId}`
18440
+ );
18441
+ }
18442
+ }
18443
+ if (data.metadata.itemId) {
18444
+ try {
18445
+ data.metadata.itemId = new import_mongodb44.ObjectId(data.metadata.itemId);
18446
+ } catch (error2) {
18447
+ throw new import_utils93.BadRequestError(`Invalid item ID: ${data.metadata.itemId}`);
18448
+ }
18449
+ }
18450
+ if (data.metadata.assetId) {
18451
+ try {
18452
+ data.metadata.assetId = new import_mongodb44.ObjectId(data.metadata.assetId);
18453
+ } catch (error2) {
18454
+ throw new import_utils93.BadRequestError(`Invalid asset ID: ${data.metadata.assetId}`);
18455
+ }
18456
+ }
18457
+ if (data.metadata.purchaseOrderId) {
18458
+ try {
18459
+ data.metadata.purchaseOrderId = new import_mongodb44.ObjectId(
18460
+ data.metadata.purchaseOrderId
18461
+ );
18462
+ } catch (error2) {
18463
+ throw new import_utils93.BadRequestError(
18464
+ `Invalid purchase order ID: ${data.metadata.purchaseOrderId}`
18465
+ );
18466
+ }
18467
+ }
18468
+ if (data.metadata.salesOrderId) {
18469
+ try {
18470
+ data.metadata.salesOrderId = new import_mongodb44.ObjectId(data.metadata.salesOrderId);
18471
+ } catch (error2) {
18472
+ throw new import_utils93.BadRequestError(
18473
+ `Invalid sales order ID: ${data.metadata.salesOrderId}`
18474
+ );
18475
+ }
18476
+ }
18477
+ }
18478
+ return {
18479
+ _id: data._id,
18480
+ id: data.id,
18481
+ org: data.org,
18482
+ type: data.type,
18483
+ date,
18484
+ book: data.book,
18485
+ description: data.description,
18486
+ metadata: data.metadata ?? {
18487
+ customerId: "",
18488
+ supplierId: "",
18489
+ itemId: "",
18490
+ assetId: "",
18491
+ purchaseOrderId: "",
18492
+ salesOrderId: ""
18493
+ },
18494
+ status: data.status,
18495
+ postedAt: data.postedAt ?? "",
18496
+ createdBy: data.createdBy,
18497
+ createdByName: data.createdByName,
18498
+ createdAt: data.createdAt ?? date,
18499
+ updatedAt: data.updatedAt ?? ""
18500
+ };
18501
+ }
18502
+
18503
+ // src/resources/finance-journal/finance.journal.entry.repository.ts
18504
+ var import_utils94 = require("@goweekdays/utils");
18505
+ var import_mongodb45 = require("mongodb");
18506
+ var import_joi77 = __toESM(require("joi"));
18507
+ function useJournalEntryRepo() {
18508
+ const db = import_utils94.useAtlas.getDb();
18509
+ if (!db) {
18510
+ throw new import_utils94.BadRequestError("Unable to connect to server.");
18511
+ }
18512
+ const namespace_collection = "finance.journal.entries";
18513
+ const collection = db.collection(namespace_collection);
18514
+ const { getCache, setCache, delNamespace } = (0, import_utils94.useCache)(namespace_collection);
18515
+ function delCachedData() {
18516
+ delNamespace().then(() => {
18517
+ import_utils94.logger.log({
18518
+ level: "info",
18519
+ message: `Cache namespace cleared for ${namespace_collection}`
18520
+ });
18521
+ }).catch((err) => {
18522
+ import_utils94.logger.log({
18523
+ level: "error",
18524
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
18525
+ });
18526
+ });
18527
+ }
18528
+ async function add(value, session) {
18529
+ try {
18530
+ value = modelJournalEntry(value);
18531
+ const res = await collection.insertOne(value, { session });
18532
+ delCachedData();
18533
+ return res.insertedId;
18534
+ } catch (error) {
18535
+ import_utils94.logger.log({
18536
+ level: "error",
18537
+ message: error.message
18538
+ });
18539
+ throw new import_utils94.BadRequestError(
18540
+ `Failed to create journal entry: ${error.message}`
18541
+ );
18542
+ }
18543
+ }
18544
+ async function getAll(options) {
18545
+ options.page = options.page && options.page > 0 ? options.page - 1 : 0;
18546
+ options.status = options.status ?? "posted";
18547
+ options.limit = options.limit ?? 10;
18548
+ options.book = options.book ?? "general";
18549
+ const { error } = schemaJournalEntryGetAll.validate(options);
18550
+ if (error) {
18551
+ throw new import_utils94.BadRequestError(`Invalid query parameters: ${error.message}`);
18552
+ }
18553
+ const query = {
18554
+ status: options.status,
18555
+ book: options.book
18556
+ };
18557
+ const cacheKeyOptions = {
18558
+ page: options.page,
18559
+ limit: options.limit,
18560
+ book: options.book,
18561
+ status: options.status
18562
+ };
18563
+ try {
18564
+ query.org = new import_mongodb45.ObjectId(options.org);
18565
+ cacheKeyOptions.org = String(options.org);
18566
+ } catch (error2) {
18567
+ throw new import_utils94.BadRequestError("Invalid organization ID.");
18568
+ }
18569
+ if (options.search) {
18570
+ query.$text = { $search: options.search };
18571
+ cacheKeyOptions.search = options.search;
18572
+ }
18573
+ if (options.type) {
18574
+ query.type = options.type;
18575
+ cacheKeyOptions.type = options.type;
18576
+ }
18577
+ const cacheKey = (0, import_utils94.makeCacheKey)(namespace_collection, cacheKeyOptions);
18578
+ import_utils94.logger.log({
18579
+ level: "info",
18580
+ message: `Cache key for getAll journal entries: ${cacheKey}`
18581
+ });
18582
+ try {
18583
+ const cached = await getCache(cacheKey);
18584
+ if (cached) {
18585
+ import_utils94.logger.log({
18586
+ level: "info",
18587
+ message: `Cache hit for getAll journal entries: ${cacheKey}`
18588
+ });
18589
+ return cached;
18590
+ }
18591
+ const items = await collection.aggregate([
18592
+ { $match: query },
18593
+ { $skip: options.page * options.limit },
18594
+ { $limit: options.limit },
18595
+ {
18596
+ $lookup: {
18597
+ from: "finance.journal.lines",
18598
+ let: { journalId: "$_id" },
18599
+ pipeline: [
18600
+ {
18601
+ $match: {
18602
+ $expr: { $eq: ["$journalEntry", "$$journalId"] }
18603
+ }
18604
+ },
18605
+ {
18606
+ $sort: { debit: -1 }
18607
+ }
18608
+ ],
18609
+ as: "lines"
18610
+ }
18611
+ }
18612
+ ]).toArray();
18613
+ const length = await collection.countDocuments(query);
18614
+ const data = (0, import_utils94.paginate)(items, options.page, options.limit, length);
18615
+ setCache(cacheKey, data, 600).then(() => {
18616
+ import_utils94.logger.log({
18617
+ level: "info",
18618
+ message: `Cache set for getAll journal entries: ${cacheKey}`
18619
+ });
18620
+ }).catch((err) => {
18621
+ import_utils94.logger.log({
18622
+ level: "error",
18623
+ message: `Failed to set cache for getAll journal entries: ${err.message}`
18624
+ });
18625
+ });
18626
+ return data;
18627
+ } catch (error2) {
18628
+ import_utils94.logger.log({ level: "error", message: `${error2}` });
18629
+ throw error2;
18630
+ }
18631
+ }
18632
+ async function getById(_id) {
18633
+ try {
18634
+ _id = new import_mongodb45.ObjectId(_id);
18635
+ } catch (error) {
18636
+ throw new import_utils94.BadRequestError("Invalid ID.");
18637
+ }
18638
+ const cacheKey = (0, import_utils94.makeCacheKey)(namespace_collection, { _id: String(_id) });
18639
+ try {
18640
+ const cached = await getCache(cacheKey);
18641
+ if (cached) {
18642
+ import_utils94.logger.log({
18643
+ level: "info",
18644
+ message: `Cache hit for getById journal entry: ${cacheKey}`
18645
+ });
18646
+ return cached;
18647
+ }
18648
+ const result = await collection.findOne({ _id });
18649
+ if (!result) {
18650
+ throw new import_utils94.BadRequestError("Journal entry not found.");
18651
+ }
18652
+ setCache(cacheKey, result, 300).then(() => {
18653
+ import_utils94.logger.log({
18654
+ level: "info",
18655
+ message: `Cache set for journal entry by id: ${cacheKey}`
18656
+ });
18657
+ }).catch((err) => {
18658
+ import_utils94.logger.log({
18659
+ level: "error",
18660
+ message: `Failed to set cache for journal entry by id: ${err.message}`
18661
+ });
18662
+ });
18663
+ return result;
18664
+ } catch (error) {
18665
+ if (error instanceof import_utils94.AppError) {
18666
+ throw error;
18667
+ } else {
18668
+ throw new import_utils94.InternalServerError("Failed to get journal entry.");
18669
+ }
18670
+ }
18671
+ }
18672
+ async function updateById(_id, options) {
18673
+ const { error: errorId } = import_joi77.default.string().hex().required().validate(String(_id));
18674
+ if (errorId) {
18675
+ throw new import_utils94.BadRequestError("Invalid Journal Entry ID.");
18676
+ }
18677
+ const { error } = schemaJournalEntryRepo.validate(options);
18678
+ if (error) {
18679
+ throw new import_utils94.BadRequestError(
18680
+ `Invalid journal entry update data: ${error.message}`
18681
+ );
18682
+ }
18683
+ try {
18684
+ _id = new import_mongodb45.ObjectId(_id);
18685
+ } catch (error2) {
18686
+ throw new import_utils94.BadRequestError("Invalid Journal Entry ID.");
18687
+ }
18688
+ try {
18689
+ await collection.updateOne(
18690
+ { _id },
18691
+ { $set: { ...options, updatedAt: /* @__PURE__ */ new Date() } }
18692
+ );
18693
+ delCachedData();
18694
+ return "Successfully updated journal entry.";
18695
+ } catch (error2) {
18696
+ throw new import_utils94.InternalServerError("Failed to update journal entry.");
18697
+ }
18698
+ }
18699
+ async function deleteById(_id, session) {
18700
+ try {
18701
+ _id = new import_mongodb45.ObjectId(_id);
18702
+ } catch (error) {
18703
+ throw new import_utils94.BadRequestError("Invalid ID.");
18704
+ }
18705
+ try {
18706
+ await collection.updateOne(
18707
+ { _id },
18708
+ {
18709
+ $set: {
18710
+ status: "voided",
18711
+ updatedAt: /* @__PURE__ */ new Date()
18712
+ }
18713
+ },
18714
+ { session }
18715
+ );
18716
+ delCachedData();
18717
+ return "Successfully voided journal entry.";
18718
+ } catch (error) {
18719
+ throw new import_utils94.InternalServerError("Failed to void journal entry.");
18720
+ }
18721
+ }
18722
+ async function updateStatusById(_id, status2) {
18723
+ try {
18724
+ _id = new import_mongodb45.ObjectId(_id);
18725
+ } catch (error) {
18726
+ throw new import_utils94.BadRequestError("Invalid ID.");
18727
+ }
18728
+ try {
18729
+ const result = await collection.updateOne(
18730
+ { _id },
18731
+ {
18732
+ $set: {
18733
+ status: status2,
18734
+ updatedAt: /* @__PURE__ */ new Date()
18735
+ }
18736
+ }
18737
+ );
18738
+ if (result.matchedCount === 0) {
18739
+ throw new import_utils94.BadRequestError("Journal entry not found.");
18740
+ }
18741
+ delCachedData();
18742
+ return "Successfully updated journal entry status.";
18743
+ } catch (error) {
18744
+ if (error instanceof import_utils94.AppError) {
18745
+ throw error;
18746
+ }
18747
+ throw new import_utils94.InternalServerError("Failed to update journal entry status.");
18748
+ }
18749
+ }
18750
+ return {
18751
+ add,
18752
+ getAll,
18753
+ getById,
18754
+ updateById,
18755
+ deleteById,
18756
+ updateStatusById
18757
+ };
18758
+ }
18759
+
18760
+ // src/resources/finance-journal/finance.journal.entry.service.ts
18761
+ var import_joi80 = __toESM(require("joi"));
18762
+
18763
+ // src/resources/finance-journal/finance.journal.line.model.ts
18764
+ var import_utils95 = require("@goweekdays/utils");
18765
+ var import_joi78 = __toESM(require("joi"));
18766
+ var import_mongodb46 = require("mongodb");
18767
+ var schemaJournalLineBase = {
18768
+ org: import_joi78.default.string().hex().required(),
18769
+ account: import_joi78.default.string().hex().required(),
18770
+ debit: import_joi78.default.number().min(0).required(),
18771
+ credit: import_joi78.default.number().min(0).required()
18772
+ };
18773
+ var schemaJournalLineCtrl = import_joi78.default.object(schemaJournalLineBase);
18774
+ var schemaJournalLineRepo = import_joi78.default.object({
18775
+ ...schemaJournalLineBase,
18776
+ journalEntry: import_joi78.default.string().hex().required(),
18777
+ accountName: import_joi78.default.string().required()
18778
+ });
18779
+ function modelJournalLine(data) {
18780
+ const { error } = schemaJournalLineRepo.validate(data);
18781
+ if (error) {
18782
+ throw new import_utils95.BadRequestError(`Invalid journal line data: ${error.message}`);
18783
+ }
18784
+ try {
18785
+ data.org = new import_mongodb46.ObjectId(data.org);
18786
+ } catch (error2) {
18787
+ throw new import_utils95.BadRequestError(`Invalid org ID: ${data.org}`);
18788
+ }
18789
+ try {
18790
+ data.journalEntry = new import_mongodb46.ObjectId(data.journalEntry);
18791
+ } catch (error2) {
18792
+ throw new import_utils95.BadRequestError(`Invalid journal entry ID: ${data.journalEntry}`);
18793
+ }
18794
+ try {
18795
+ data.account = new import_mongodb46.ObjectId(data.account);
18796
+ } catch (error2) {
18797
+ throw new import_utils95.BadRequestError(`Invalid account ID: ${data.account}`);
18798
+ }
18799
+ return {
18800
+ _id: data._id,
18801
+ org: data.org,
18802
+ journalEntry: data.journalEntry,
18803
+ account: data.account,
18804
+ accountName: data.accountName,
18805
+ debit: data.debit,
18806
+ credit: data.credit,
18807
+ postReference: data.postReference ?? "",
18808
+ createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
18809
+ updatedAt: data.updatedAt ?? ""
18810
+ };
18811
+ }
18812
+
18813
+ // src/resources/finance-journal/finance.journal.line.repository.ts
18814
+ var import_utils96 = require("@goweekdays/utils");
18815
+ var import_mongodb47 = require("mongodb");
18816
+ var import_joi79 = __toESM(require("joi"));
18817
+ function useJournalLineRepo() {
18818
+ const db = import_utils96.useAtlas.getDb();
18819
+ if (!db) {
18820
+ throw new import_utils96.BadRequestError("Unable to connect to server.");
18821
+ }
18822
+ const namespace_collection = "finance.journal.lines";
18823
+ const collection = db.collection(namespace_collection);
18824
+ const { getCache, setCache, delNamespace } = (0, import_utils96.useCache)(namespace_collection);
18825
+ function delCachedData() {
18826
+ delNamespace().then(() => {
18827
+ import_utils96.logger.log({
18828
+ level: "info",
18829
+ message: `Cache namespace cleared for ${namespace_collection}`
18830
+ });
18831
+ }).catch((err) => {
18832
+ import_utils96.logger.log({
18833
+ level: "error",
18834
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
18835
+ });
18836
+ });
18837
+ }
18838
+ async function add(value, session) {
18839
+ try {
18840
+ value = modelJournalLine(value);
18841
+ const res = await collection.insertOne(value, { session });
18842
+ delCachedData();
18843
+ return res.insertedId;
18844
+ } catch (error) {
18845
+ import_utils96.logger.log({
18846
+ level: "error",
18847
+ message: error.message
18848
+ });
18849
+ throw new import_utils96.BadRequestError(
18850
+ `Failed to create journal line: ${error.message}`
18851
+ );
18852
+ }
18853
+ }
18854
+ async function getAll(options) {
18855
+ options.page = options.page && options.page > 0 ? options.page - 1 : 0;
18856
+ options.limit = options.limit ?? 10;
18857
+ const query = {};
18858
+ try {
18859
+ query.org = new import_mongodb47.ObjectId(options.org);
18860
+ } catch (error) {
18861
+ throw new import_utils96.BadRequestError("Invalid organization ID.");
18862
+ }
18863
+ if (options.journalEntry) {
18864
+ try {
18865
+ query.journalEntry = new import_mongodb47.ObjectId(options.journalEntry);
18866
+ } catch (error) {
18867
+ throw new import_utils96.BadRequestError("Invalid journal entry ID.");
18868
+ }
18869
+ }
18870
+ const cacheKey = (0, import_utils96.makeCacheKey)(namespace_collection, {
18871
+ org: String(options.org),
18872
+ journalEntry: String(options.journalEntry ?? ""),
18873
+ page: options.page,
18874
+ limit: options.limit
18875
+ });
18876
+ import_utils96.logger.log({
18877
+ level: "info",
18878
+ message: `Cache key for getAll journal lines: ${cacheKey}`
18879
+ });
18880
+ try {
18881
+ const cached = await getCache(cacheKey);
18882
+ if (cached) {
18883
+ import_utils96.logger.log({
18884
+ level: "info",
18885
+ message: `Cache hit for getAll journal lines: ${cacheKey}`
18886
+ });
18887
+ return cached;
18888
+ }
18889
+ const items = await collection.aggregate([
18890
+ { $match: query },
18891
+ { $skip: options.page * options.limit },
18892
+ { $limit: options.limit },
18893
+ {
18894
+ $project: {
18895
+ _id: 1,
18896
+ org: 1,
18897
+ journalEntry: 1,
18898
+ account: 1,
18899
+ debit: 1,
18900
+ credit: 1,
18901
+ description: 1,
18902
+ createdAt: 1
18903
+ }
18904
+ }
18905
+ ]).toArray();
18906
+ const length = await collection.countDocuments(query);
18907
+ const data = (0, import_utils96.paginate)(items, options.page, options.limit, length);
18908
+ setCache(cacheKey, data, 600).then(() => {
18909
+ import_utils96.logger.log({
18910
+ level: "info",
18911
+ message: `Cache set for getAll journal lines: ${cacheKey}`
18912
+ });
18913
+ }).catch((err) => {
18914
+ import_utils96.logger.log({
18915
+ level: "error",
18916
+ message: `Failed to set cache for getAll journal lines: ${err.message}`
18917
+ });
18918
+ });
18919
+ return data;
18920
+ } catch (error) {
18921
+ import_utils96.logger.log({ level: "error", message: `${error}` });
18922
+ throw error;
18923
+ }
18924
+ }
18925
+ async function getById(_id) {
18926
+ try {
18927
+ _id = new import_mongodb47.ObjectId(_id);
18928
+ } catch (error) {
18929
+ throw new import_utils96.BadRequestError("Invalid ID.");
18930
+ }
18931
+ const cacheKey = (0, import_utils96.makeCacheKey)(namespace_collection, { _id: String(_id) });
18932
+ try {
18933
+ const cached = await getCache(cacheKey);
18934
+ if (cached) {
18935
+ import_utils96.logger.log({
18936
+ level: "info",
18937
+ message: `Cache hit for getById journal line: ${cacheKey}`
18938
+ });
18939
+ return cached;
18940
+ }
18941
+ const result = await collection.findOne({ _id });
18942
+ if (!result) {
18943
+ throw new import_utils96.BadRequestError("Journal line not found.");
18944
+ }
18945
+ setCache(cacheKey, result, 300).then(() => {
18946
+ import_utils96.logger.log({
18947
+ level: "info",
18948
+ message: `Cache set for journal line by id: ${cacheKey}`
18949
+ });
18950
+ }).catch((err) => {
18951
+ import_utils96.logger.log({
18952
+ level: "error",
18953
+ message: `Failed to set cache for journal line by id: ${err.message}`
18954
+ });
18955
+ });
18956
+ return result;
18957
+ } catch (error) {
18958
+ if (error instanceof import_utils96.AppError) {
18959
+ throw error;
18960
+ } else {
18961
+ throw new import_utils96.InternalServerError("Failed to get journal line.");
18962
+ }
18963
+ }
18964
+ }
18965
+ async function updateById(_id, options) {
18966
+ const { error: errorId } = import_joi79.default.string().hex().required().validate(String(_id));
18967
+ if (errorId) {
18968
+ throw new import_utils96.BadRequestError("Invalid Journal Line ID.");
18969
+ }
18970
+ const { error } = schemaJournalLineRepo.validate(options);
18971
+ if (error) {
18972
+ throw new import_utils96.BadRequestError(
18973
+ `Invalid journal line update data: ${error.message}`
18974
+ );
18975
+ }
18976
+ try {
18977
+ _id = new import_mongodb47.ObjectId(_id);
18978
+ } catch (error2) {
18979
+ throw new import_utils96.BadRequestError("Invalid Journal Line ID.");
18980
+ }
18981
+ try {
18982
+ await collection.updateOne(
18983
+ { _id },
18984
+ { $set: { ...options, updatedAt: /* @__PURE__ */ new Date() } }
18985
+ );
18986
+ delCachedData();
18987
+ return "Successfully updated journal line.";
18988
+ } catch (error2) {
18989
+ throw new import_utils96.InternalServerError("Failed to update journal line.");
18990
+ }
18991
+ }
18992
+ async function deleteById(_id, session) {
18993
+ try {
18994
+ _id = new import_mongodb47.ObjectId(_id);
18995
+ } catch (error) {
18996
+ throw new import_utils96.BadRequestError("Invalid ID.");
18997
+ }
18998
+ try {
18999
+ await collection.deleteOne({ _id }, { session });
19000
+ delCachedData();
19001
+ return "Successfully deleted journal line.";
19002
+ } catch (error) {
19003
+ throw new import_utils96.InternalServerError("Failed to delete journal line.");
19004
+ }
19005
+ }
19006
+ return {
19007
+ add,
19008
+ getAll,
19009
+ getById,
19010
+ updateById,
19011
+ deleteById
19012
+ };
19013
+ }
19014
+
19015
+ // src/resources/finance-journal/finance.journal.entry.service.ts
19016
+ var import_utils97 = require("@goweekdays/utils");
19017
+ function useJournalEntryService() {
19018
+ const { add: _add } = useJournalEntryRepo();
19019
+ const { add: addLine } = useJournalLineRepo();
19020
+ const { getUserById } = useUserRepo();
19021
+ const { getById: getAccountById } = useChartOfAccountRepo();
19022
+ const {
19023
+ getByType: getCounterByType,
19024
+ add: addCounter,
19025
+ incrementByType
19026
+ } = useCounterRepo();
19027
+ async function add(entry, lines) {
19028
+ const { error } = import_joi80.default.object({
19029
+ journalEntry: schemaJournalEntryCtrl.required(),
19030
+ journalLines: import_joi80.default.array().items(schemaJournalLineCtrl).min(1).required()
19031
+ }).validate({ journalEntry: entry, journalLines: lines });
19032
+ if (error) {
19033
+ throw new import_utils97.BadRequestError(`Invalid journal entry data: ${error.message}`);
19034
+ }
19035
+ const session = import_utils97.useAtlas.getClient()?.startSession();
19036
+ if (!session) {
19037
+ throw new import_utils97.BadRequestError("Unable to start database session.");
19038
+ }
19039
+ try {
19040
+ session.startTransaction();
19041
+ const counterName = `${entry.org.toString()}.journal.entry.${entry.book}`;
19042
+ const counter = await getCounterByType(counterName);
19043
+ if (!counter) {
19044
+ await addCounter(counterName, session);
19045
+ }
19046
+ const entryNumber = counter ? counter.count + 1 : 1;
19047
+ entry.id = entryNumber.toString().padStart(6, "0");
19048
+ await incrementByType(counterName, session);
19049
+ const totalDebit = lines.reduce((sum, line) => sum + line.debit, 0);
19050
+ const totalCredit = lines.reduce((sum, line) => sum + line.credit, 0);
19051
+ if (totalDebit !== totalCredit) {
19052
+ throw new import_utils97.BadRequestError(
19053
+ `Total debit (${totalDebit}) must equal total credit (${totalCredit}).`
19054
+ );
19055
+ }
19056
+ const user = await getUserById(entry.createdBy);
19057
+ if (!user) {
19058
+ throw new import_utils97.NotFoundError("User not found.");
19059
+ }
19060
+ entry.createdByName = `${user.firstName} ${user.lastName}`;
19061
+ entry.status = "draft";
19062
+ const entryId = await _add(entry, session);
19063
+ for (const line of lines) {
19064
+ line.journalEntry = entryId.toString();
19065
+ const account = await getAccountById(String(line.account));
19066
+ if (!account) {
19067
+ throw new import_utils97.NotFoundError(`Account not found: ${line.account}`);
19068
+ }
19069
+ line.accountName = account.name;
19070
+ await addLine(line, session);
19071
+ }
19072
+ await session.commitTransaction();
19073
+ return "Journal entry created successfully.";
19074
+ } catch (error2) {
19075
+ await session.abortTransaction();
19076
+ if (error2 instanceof import_utils97.AppError) {
19077
+ throw error2;
19078
+ }
19079
+ throw new import_utils97.InternalServerError(
19080
+ `Failed to create journal entry: ${error2.message}`
19081
+ );
19082
+ } finally {
19083
+ session.endSession();
19084
+ }
19085
+ }
19086
+ return {
19087
+ add
19088
+ };
19089
+ }
19090
+
19091
+ // src/resources/finance-journal/finance.journal.entry.controller.ts
19092
+ var import_joi81 = __toESM(require("joi"));
19093
+ var import_utils98 = require("@goweekdays/utils");
19094
+ function useJournalEntryController() {
19095
+ const {
19096
+ getAll: _getAll,
19097
+ getById: _getById,
19098
+ updateById: _updateById,
19099
+ deleteById: _deleteById,
19100
+ updateStatusById: _updateStatusById
19101
+ } = useJournalEntryRepo();
19102
+ const { add: _add } = useJournalEntryService();
19103
+ async function add(req, res, next) {
19104
+ const value = req.body;
19105
+ const { error } = import_joi81.default.object({
19106
+ journalEntry: schemaJournalEntryCtrl.required(),
19107
+ journalLines: import_joi81.default.array().items(schemaJournalLineCtrl).min(1).required()
19108
+ }).validate(value);
19109
+ if (error) {
19110
+ next(new import_utils98.BadRequestError(error.message));
19111
+ import_utils98.logger.info(`Controller: ${error.message}`);
19112
+ return;
19113
+ }
19114
+ try {
19115
+ const message = await _add(value.journalEntry, value.journalLines);
19116
+ res.json({ message });
19117
+ return;
19118
+ } catch (error2) {
19119
+ next(error2);
19120
+ }
19121
+ }
19122
+ async function getAll(req, res, next) {
19123
+ const query = req.query;
19124
+ const org = req.params.org ?? "";
19125
+ const { error } = schemaJournalEntryGetAll.validate({ ...query, org });
19126
+ const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
19127
+ const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
19128
+ const book = req.query.book ?? "general";
19129
+ const type = req.query.type ?? "";
19130
+ const search = req.query.search ?? "";
19131
+ const status2 = req.query.status ?? "posted";
19132
+ if (!isFinite(page)) {
19133
+ next(new import_utils98.BadRequestError("Invalid page number."));
19134
+ return;
19135
+ }
19136
+ if (!isFinite(limit)) {
19137
+ next(new import_utils98.BadRequestError("Invalid limit number."));
19138
+ return;
19139
+ }
19140
+ if (error) {
19141
+ next(new import_utils98.BadRequestError(error.message));
19142
+ return;
19143
+ }
19144
+ try {
19145
+ const entries = await _getAll({
19146
+ org,
19147
+ page,
19148
+ limit,
19149
+ book,
19150
+ type,
19151
+ search,
19152
+ status: status2
19153
+ });
19154
+ res.json(entries);
19155
+ return;
19156
+ } catch (error2) {
19157
+ next(error2);
19158
+ }
19159
+ }
19160
+ async function getById(req, res, next) {
19161
+ const id = req.params.id;
19162
+ const validation = import_joi81.default.object({
19163
+ id: import_joi81.default.string().hex().required()
19164
+ });
19165
+ const { error } = validation.validate({ id });
19166
+ if (error) {
19167
+ next(new import_utils98.BadRequestError(error.message));
19168
+ return;
19169
+ }
19170
+ try {
19171
+ const entry = await _getById(id);
19172
+ res.json(entry);
19173
+ return;
19174
+ } catch (error2) {
19175
+ next(error2);
19176
+ }
19177
+ }
19178
+ async function updateById(req, res, next) {
19179
+ const _id = req.params.id ?? "";
19180
+ const { error: errorId } = import_joi81.default.string().hex().required().validate(_id);
19181
+ if (errorId) {
19182
+ next(new import_utils98.BadRequestError("Invalid Journal Entry ID."));
19183
+ return;
19184
+ }
19185
+ const payload = req.body;
19186
+ const { error } = schemaJournalEntryCtrl.validate(payload);
19187
+ if (error) {
19188
+ next(
19189
+ new import_utils98.BadRequestError(
19190
+ `Invalid journal entry update data: ${error.message}`
19191
+ )
19192
+ );
19193
+ return;
19194
+ }
19195
+ try {
19196
+ const message = await _updateById(_id, payload);
19197
+ res.json({ message });
19198
+ return;
19199
+ } catch (error2) {
19200
+ next(error2);
19201
+ }
19202
+ }
19203
+ async function deleteById(req, res, next) {
19204
+ const id = req.params.id;
19205
+ if (!id) {
19206
+ next(new import_utils98.BadRequestError("Journal Entry ID is required."));
19207
+ return;
19208
+ }
19209
+ try {
19210
+ const message = await _deleteById(id);
19211
+ res.json(message);
19212
+ return;
19213
+ } catch (error) {
19214
+ next(error);
19215
+ }
19216
+ }
19217
+ async function updateStatusById(req, res, next) {
19218
+ const id = req.params.id;
19219
+ const status2 = req.params.status;
19220
+ const validation = import_joi81.default.object({
19221
+ id: import_joi81.default.string().hex().required(),
19222
+ status: import_joi81.default.string().required()
19223
+ });
19224
+ const { error } = validation.validate({ id, status: status2 });
19225
+ if (error) {
19226
+ next(new import_utils98.BadRequestError(error.message));
19227
+ return;
19228
+ }
19229
+ try {
19230
+ const message = await _updateStatusById(id, status2);
19231
+ res.json({ message });
19232
+ return;
19233
+ } catch (error2) {
19234
+ next(error2);
19235
+ }
19236
+ }
19237
+ return {
19238
+ add,
19239
+ getAll,
19240
+ getById,
19241
+ updateById,
19242
+ deleteById,
19243
+ updateStatusById
19244
+ };
19245
+ }
19246
+
19247
+ // src/resources/finance-journal/finance.journal.line.controller.ts
19248
+ var import_joi82 = __toESM(require("joi"));
19249
+ var import_utils99 = require("@goweekdays/utils");
19250
+ function useJournalLineController() {
19251
+ const {
19252
+ getAll: _getAll,
19253
+ getById: _getById,
19254
+ updateById: _updateById,
19255
+ deleteById: _deleteById,
19256
+ add: _add
19257
+ } = useJournalLineRepo();
19258
+ async function getAll(req, res, next) {
19259
+ const query = req.query;
19260
+ const validation = import_joi82.default.object({
19261
+ org: import_joi82.default.string().hex().required(),
19262
+ journalEntry: import_joi82.default.string().hex().optional(),
19263
+ page: import_joi82.default.number().min(1).optional().allow("", null),
19264
+ limit: import_joi82.default.number().min(1).optional().allow("", null)
19265
+ });
19266
+ const org = req.params.org ?? "";
19267
+ const journalEntry = req.query.journalEntry;
19268
+ const { error } = validation.validate({ ...query, org, journalEntry });
19269
+ const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
19270
+ const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
19271
+ if (!isFinite(page)) {
19272
+ next(new import_utils99.BadRequestError("Invalid page number."));
19273
+ return;
19274
+ }
19275
+ if (!isFinite(limit)) {
19276
+ next(new import_utils99.BadRequestError("Invalid limit number."));
19277
+ return;
19278
+ }
19279
+ if (error) {
19280
+ next(new import_utils99.BadRequestError(error.message));
19281
+ return;
19282
+ }
19283
+ try {
19284
+ const lines = await _getAll({ org, journalEntry, page, limit });
19285
+ res.json(lines);
19286
+ return;
19287
+ } catch (error2) {
19288
+ next(error2);
19289
+ }
19290
+ }
19291
+ async function getById(req, res, next) {
19292
+ const id = req.params.id;
19293
+ const validation = import_joi82.default.object({
19294
+ id: import_joi82.default.string().hex().required()
19295
+ });
19296
+ const { error } = validation.validate({ id });
19297
+ if (error) {
19298
+ next(new import_utils99.BadRequestError(error.message));
19299
+ return;
19300
+ }
19301
+ try {
19302
+ const line = await _getById(id);
19303
+ res.json(line);
19304
+ return;
19305
+ } catch (error2) {
19306
+ next(error2);
19307
+ }
19308
+ }
19309
+ async function updateById(req, res, next) {
19310
+ const _id = req.params.id ?? "";
19311
+ const { error: errorId } = import_joi82.default.string().hex().required().validate(_id);
19312
+ if (errorId) {
19313
+ next(new import_utils99.BadRequestError("Invalid Journal Line ID."));
19314
+ return;
19315
+ }
19316
+ const payload = req.body;
19317
+ const { error } = schemaJournalLineCtrl.validate(payload);
19318
+ if (error) {
19319
+ next(
19320
+ new import_utils99.BadRequestError(
19321
+ `Invalid journal line update data: ${error.message}`
19322
+ )
19323
+ );
19324
+ return;
19325
+ }
19326
+ try {
19327
+ const message = await _updateById(_id, payload);
19328
+ res.json({ message });
19329
+ return;
19330
+ } catch (error2) {
19331
+ next(error2);
19332
+ }
19333
+ }
19334
+ async function deleteById(req, res, next) {
19335
+ const id = req.params.id;
19336
+ if (!id) {
19337
+ next(new import_utils99.BadRequestError("Journal Line ID is required."));
19338
+ return;
19339
+ }
19340
+ try {
19341
+ const message = await _deleteById(id);
19342
+ res.json(message);
19343
+ return;
19344
+ } catch (error) {
19345
+ next(error);
19346
+ }
19347
+ }
19348
+ return {
19349
+ getAll,
19350
+ getById,
19351
+ updateById,
19352
+ deleteById
19353
+ };
19354
+ }
17007
19355
  // Annotate the CommonJS export names for ESM import in node:
17008
19356
  0 && (module.exports = {
17009
19357
  ACCESS_TOKEN_EXPIRY,
@@ -17047,12 +19395,17 @@ function useJobSummaryCtrl() {
17047
19395
  VERIFICATION_USER_INVITE_DURATION,
17048
19396
  XENDIT_BASE_URL,
17049
19397
  XENDIT_SECRET_KEY,
19398
+ chartOfAccountNormalBalances,
19399
+ chartOfAccountTypes,
17050
19400
  currencies,
17051
19401
  isDev,
17052
19402
  jobApplicationStatuses,
19403
+ journalEntryStatuses,
19404
+ journalEntryTypes,
17053
19405
  ledgerBillStatuses,
17054
19406
  ledgerBillTypes,
17055
19407
  modelApp,
19408
+ modelChartOfAccount,
17056
19409
  modelJobApplication,
17057
19410
  modelJobPost,
17058
19411
  modelJobProfile,
@@ -17064,6 +19417,8 @@ function useJobSummaryCtrl() {
17064
19417
  modelJobStatusSetup,
17065
19418
  modelJobStatusTrans,
17066
19419
  modelJobSummary,
19420
+ modelJournalEntry,
19421
+ modelJournalLine,
17067
19422
  modelLedgerBill,
17068
19423
  modelMember,
17069
19424
  modelOption,
@@ -17075,6 +19430,7 @@ function useJobSummaryCtrl() {
17075
19430
  modelRole,
17076
19431
  modelSubscription,
17077
19432
  modelSubscriptionTransaction,
19433
+ modelTax,
17078
19434
  modelUser,
17079
19435
  modelVerification,
17080
19436
  schemaApp,
@@ -17083,6 +19439,9 @@ function useJobSummaryCtrl() {
17083
19439
  schemaBuilding,
17084
19440
  schemaBuildingUnit,
17085
19441
  schemaCertification,
19442
+ schemaChartOfAccountBase,
19443
+ schemaChartOfAccountStd,
19444
+ schemaChartOfAccountUpdate,
17086
19445
  schemaEducation,
17087
19446
  schemaGroup,
17088
19447
  schemaInviteMember,
@@ -17109,6 +19468,11 @@ function useJobSummaryCtrl() {
17109
19468
  schemaJobStatusTrans,
17110
19469
  schemaJobSummary,
17111
19470
  schemaJobSummaryInc,
19471
+ schemaJournalEntryCtrl,
19472
+ schemaJournalEntryGetAll,
19473
+ schemaJournalEntryRepo,
19474
+ schemaJournalLineCtrl,
19475
+ schemaJournalLineRepo,
17112
19476
  schemaLanguage,
17113
19477
  schemaLedgerBill,
17114
19478
  schemaLedgerBillingSummary,
@@ -17139,11 +19503,14 @@ function useJobSummaryCtrl() {
17139
19503
  schemaSubscriptionSeats,
17140
19504
  schemaSubscriptionTransaction,
17141
19505
  schemaSubscriptionUpdate,
19506
+ schemaTax,
19507
+ schemaTaxUpdate,
17142
19508
  schemaUpdateOptions,
17143
19509
  schemaUser,
17144
19510
  schemaVerification,
17145
19511
  schemaVerificationOrgInvite,
17146
19512
  schemaWorkExp,
19513
+ taxDirections,
17147
19514
  transactionSchema,
17148
19515
  useAppController,
17149
19516
  useAppRepo,
@@ -17156,6 +19523,8 @@ function useJobSummaryCtrl() {
17156
19523
  useBuildingUnitController,
17157
19524
  useBuildingUnitRepo,
17158
19525
  useBuildingUnitService,
19526
+ useChartOfAccountController,
19527
+ useChartOfAccountRepo,
17159
19528
  useCounterModel,
17160
19529
  useCounterRepo,
17161
19530
  useFileController,
@@ -17174,6 +19543,11 @@ function useJobSummaryCtrl() {
17174
19543
  useJobSummaryCtrl,
17175
19544
  useJobSummaryRepo,
17176
19545
  useJobSummarySvc,
19546
+ useJournalEntryController,
19547
+ useJournalEntryRepo,
19548
+ useJournalEntryService,
19549
+ useJournalLineController,
19550
+ useJournalLineRepo,
17177
19551
  useLedgerBillingController,
17178
19552
  useLedgerBillingRepo,
17179
19553
  useMemberController,
@@ -17204,6 +19578,8 @@ function useJobSummaryCtrl() {
17204
19578
  useSubscriptionService,
17205
19579
  useSubscriptionTransactionController,
17206
19580
  useSubscriptionTransactionRepo,
19581
+ useTaxController,
19582
+ useTaxRepo,
17207
19583
  useUserController,
17208
19584
  useUserRepo,
17209
19585
  useUserService,