@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/CHANGELOG.md +6 -0
- package/dist/index.d.ts +232 -3
- package/dist/index.js +2379 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2393 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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,
|