@classytic/payroll 2.0.0 → 2.3.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.
Potentially problematic release.
This version of @classytic/payroll might be problematic. Click here for more details.
- package/README.md +2599 -253
- package/dist/calculators/index.d.ts +433 -0
- package/dist/calculators/index.js +283 -0
- package/dist/calculators/index.js.map +1 -0
- package/dist/core/index.d.ts +85 -251
- package/dist/core/index.js +286 -91
- package/dist/core/index.js.map +1 -1
- package/dist/employee-identity-DXhgOgXE.d.ts +473 -0
- package/dist/employee.factory-BlZqhiCk.d.ts +189 -0
- package/dist/idempotency-Cw2CWicb.d.ts +52 -0
- package/dist/index.d.ts +618 -683
- package/dist/index.js +8336 -3580
- package/dist/index.js.map +1 -1
- package/dist/jurisdiction/index.d.ts +660 -0
- package/dist/jurisdiction/index.js +533 -0
- package/dist/jurisdiction/index.js.map +1 -0
- package/dist/payroll.d.ts +261 -65
- package/dist/payroll.js +4164 -1075
- package/dist/payroll.js.map +1 -1
- package/dist/schemas/index.d.ts +1176 -783
- package/dist/schemas/index.js +368 -28
- package/dist/schemas/index.js.map +1 -1
- package/dist/services/index.d.ts +582 -3
- package/dist/services/index.js +572 -96
- package/dist/services/index.js.map +1 -1
- package/dist/shift-compliance/index.d.ts +1171 -0
- package/dist/shift-compliance/index.js +1479 -0
- package/dist/shift-compliance/index.js.map +1 -0
- package/dist/types-BN3K_Uhr.d.ts +1842 -0
- package/dist/utils/index.d.ts +22 -2
- package/dist/utils/index.js +470 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +24 -6
- package/dist/index-CTjHlCzz.d.ts +0 -721
- package/dist/plugin-D9mOr3_d.d.ts +0 -333
- package/dist/types-BSYyX2KJ.d.ts +0 -671
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as Logger, aT as PayPeriodInfo, N as Allowance, Q as Deduction, X as Compensation, aO as CompensationBreakdownResult, aU as ProRatingResult, aV as TaxCalculationResult, aK as EmployeeStatus, V as BankDetails, F as EmploymentType, aW as EmployeeValidationResult, O as ObjectIdLike, I as Department, aX as PayrollStatus } from '../types-BN3K_Uhr.js';
|
|
2
2
|
import { Types } from 'mongoose';
|
|
3
|
+
export { C as ContainerLike, a as DEFAULT_CARRY_OVER, D as DEFAULT_LEAVE_ALLOCATIONS, E as EmployeeIdMode, z as EmployeeIdType, A as EmployeeQueryFilter, R as ResolveOrganizationIdParams, S as SecureEmployeeLookupOptions, l as accrueLeaveToBalance, k as calculateCarryOver, c as calculateLeaveDays, f as calculateUnpaidLeaveDeduction, s as detectEmployeeIdType, n as employeeExistsSecure, m as findEmployeeSecure, o as findEmployeesSecure, y as formatEmployeeId, d as getAvailableDays, g as getLeaveBalance, b as getLeaveBalances, e as getLeaveSummary, j as getUnpaidLeaveDays, h as hasLeaveBalance, i as initializeLeaveBalances, x as isObjectIdEmployeeId, w as isStringEmployeeId, _ as leaveUtils, u as normalizeEmployeeId, p as proRateAllocation, r as requireOrganizationId, q as resolveOrganizationId, t as tryResolveOrganizationId, v as validateOrganizationId } from '../employee-identity-DXhgOgXE.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @classytic/payroll - Logger
|
|
@@ -685,6 +686,22 @@ declare class EmployeeQueryBuilder extends QueryBuilder {
|
|
|
685
686
|
* Filter by user
|
|
686
687
|
*/
|
|
687
688
|
forUser(userId: ObjectIdLike): this;
|
|
689
|
+
/**
|
|
690
|
+
* Filter by employeeId (human-readable ID)
|
|
691
|
+
*/
|
|
692
|
+
forEmployeeId(employeeId: string): this;
|
|
693
|
+
/**
|
|
694
|
+
* Filter by email (for guest employees)
|
|
695
|
+
*/
|
|
696
|
+
forEmail(email: string): this;
|
|
697
|
+
/**
|
|
698
|
+
* Filter guest employees (no userId)
|
|
699
|
+
*/
|
|
700
|
+
guestEmployees(): this;
|
|
701
|
+
/**
|
|
702
|
+
* Filter user-linked employees (has userId)
|
|
703
|
+
*/
|
|
704
|
+
userLinkedEmployees(): this;
|
|
688
705
|
/**
|
|
689
706
|
* Filter by status(es)
|
|
690
707
|
*/
|
|
@@ -741,8 +758,11 @@ declare class PayrollQueryBuilder extends QueryBuilder {
|
|
|
741
758
|
forOrganization(organizationId: ObjectIdLike): this;
|
|
742
759
|
/**
|
|
743
760
|
* Filter by employee
|
|
761
|
+
*
|
|
762
|
+
* Note: PayrollRecord.employeeId is always ObjectId _id
|
|
763
|
+
* If passing a string business ID, resolve to _id first
|
|
744
764
|
*/
|
|
745
|
-
forEmployee(employeeId: ObjectIdLike): this;
|
|
765
|
+
forEmployee(employeeId: ObjectIdLike | string): this;
|
|
746
766
|
/**
|
|
747
767
|
* Filter by period
|
|
748
768
|
*/
|
package/dist/utils/index.js
CHANGED
|
@@ -804,6 +804,30 @@ var EmployeeQueryBuilder = class extends QueryBuilder {
|
|
|
804
804
|
forUser(userId) {
|
|
805
805
|
return this.where("userId", toObjectId(userId));
|
|
806
806
|
}
|
|
807
|
+
/**
|
|
808
|
+
* Filter by employeeId (human-readable ID)
|
|
809
|
+
*/
|
|
810
|
+
forEmployeeId(employeeId) {
|
|
811
|
+
return this.where("employeeId", employeeId);
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Filter by email (for guest employees)
|
|
815
|
+
*/
|
|
816
|
+
forEmail(email) {
|
|
817
|
+
return this.where("email", email.toLowerCase().trim());
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* Filter guest employees (no userId)
|
|
821
|
+
*/
|
|
822
|
+
guestEmployees() {
|
|
823
|
+
return this.where("userId", null);
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Filter user-linked employees (has userId)
|
|
827
|
+
*/
|
|
828
|
+
userLinkedEmployees() {
|
|
829
|
+
return this.where("userId", { $ne: null });
|
|
830
|
+
}
|
|
807
831
|
/**
|
|
808
832
|
* Filter by status(es)
|
|
809
833
|
*/
|
|
@@ -889,6 +913,9 @@ var PayrollQueryBuilder = class extends QueryBuilder {
|
|
|
889
913
|
}
|
|
890
914
|
/**
|
|
891
915
|
* Filter by employee
|
|
916
|
+
*
|
|
917
|
+
* Note: PayrollRecord.employeeId is always ObjectId _id
|
|
918
|
+
* If passing a string business ID, resolve to _id first
|
|
892
919
|
*/
|
|
893
920
|
forEmployee(employeeId) {
|
|
894
921
|
return this.where("employeeId", toObjectId(employeeId));
|
|
@@ -1041,6 +1068,448 @@ var query_builders_default = {
|
|
|
1041
1068
|
unwindStage
|
|
1042
1069
|
};
|
|
1043
1070
|
|
|
1044
|
-
|
|
1071
|
+
// src/utils/leave.ts
|
|
1072
|
+
var DEFAULT_LEAVE_ALLOCATIONS = {
|
|
1073
|
+
annual: 20,
|
|
1074
|
+
sick: 10,
|
|
1075
|
+
unpaid: 0,
|
|
1076
|
+
// Unlimited
|
|
1077
|
+
maternity: 90,
|
|
1078
|
+
paternity: 10,
|
|
1079
|
+
bereavement: 5,
|
|
1080
|
+
compensatory: 0,
|
|
1081
|
+
other: 0
|
|
1082
|
+
};
|
|
1083
|
+
var DEFAULT_CARRY_OVER = {
|
|
1084
|
+
annual: 5,
|
|
1085
|
+
sick: 0,
|
|
1086
|
+
unpaid: 0,
|
|
1087
|
+
maternity: 0,
|
|
1088
|
+
paternity: 0,
|
|
1089
|
+
bereavement: 0,
|
|
1090
|
+
compensatory: 5,
|
|
1091
|
+
other: 0
|
|
1092
|
+
};
|
|
1093
|
+
function calculateLeaveDays(startDate, endDate, options = {}) {
|
|
1094
|
+
const {
|
|
1095
|
+
workingDays = [1, 2, 3, 4, 5],
|
|
1096
|
+
// Mon-Fri by default
|
|
1097
|
+
holidays = [],
|
|
1098
|
+
includeEndDate = true
|
|
1099
|
+
} = options;
|
|
1100
|
+
const holidaySet = new Set(holidays.map((d) => new Date(d).toDateString()));
|
|
1101
|
+
let count = 0;
|
|
1102
|
+
const current = new Date(startDate);
|
|
1103
|
+
current.setHours(0, 0, 0, 0);
|
|
1104
|
+
const end = new Date(endDate);
|
|
1105
|
+
end.setHours(0, 0, 0, 0);
|
|
1106
|
+
if (!includeEndDate) {
|
|
1107
|
+
end.setDate(end.getDate() - 1);
|
|
1108
|
+
}
|
|
1109
|
+
while (current <= end) {
|
|
1110
|
+
const isWorkDay = workingDays.includes(current.getDay());
|
|
1111
|
+
const isHoliday = holidaySet.has(current.toDateString());
|
|
1112
|
+
if (isWorkDay && !isHoliday) {
|
|
1113
|
+
count++;
|
|
1114
|
+
}
|
|
1115
|
+
current.setDate(current.getDate() + 1);
|
|
1116
|
+
}
|
|
1117
|
+
return count;
|
|
1118
|
+
}
|
|
1119
|
+
function hasLeaveBalance(employee2, type, days, year = (/* @__PURE__ */ new Date()).getFullYear()) {
|
|
1120
|
+
if (type === "unpaid") return true;
|
|
1121
|
+
const balance = getLeaveBalance(employee2, type, year);
|
|
1122
|
+
if (!balance) return false;
|
|
1123
|
+
const available = balance.allocated + balance.carriedOver - balance.used - balance.pending;
|
|
1124
|
+
return available >= days;
|
|
1125
|
+
}
|
|
1126
|
+
function getLeaveBalance(employee2, type, year = (/* @__PURE__ */ new Date()).getFullYear()) {
|
|
1127
|
+
return employee2.leaveBalances?.find((b) => b.type === type && b.year === year);
|
|
1128
|
+
}
|
|
1129
|
+
function getLeaveBalances(employee2, year = (/* @__PURE__ */ new Date()).getFullYear()) {
|
|
1130
|
+
return (employee2.leaveBalances || []).filter((b) => b.year === year);
|
|
1131
|
+
}
|
|
1132
|
+
function getAvailableDays(employee2, type, year = (/* @__PURE__ */ new Date()).getFullYear()) {
|
|
1133
|
+
if (type === "unpaid") return Infinity;
|
|
1134
|
+
const balance = getLeaveBalance(employee2, type, year);
|
|
1135
|
+
if (!balance) return 0;
|
|
1136
|
+
return Math.max(
|
|
1137
|
+
0,
|
|
1138
|
+
balance.allocated + balance.carriedOver - balance.used - balance.pending
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
function getLeaveSummary(employee2, year = (/* @__PURE__ */ new Date()).getFullYear()) {
|
|
1142
|
+
const balances = getLeaveBalances(employee2, year);
|
|
1143
|
+
const byType = {};
|
|
1144
|
+
let totalAllocated = 0;
|
|
1145
|
+
let totalUsed = 0;
|
|
1146
|
+
let totalPending = 0;
|
|
1147
|
+
for (const balance of balances) {
|
|
1148
|
+
const available = Math.max(
|
|
1149
|
+
0,
|
|
1150
|
+
balance.allocated + balance.carriedOver - balance.used - balance.pending
|
|
1151
|
+
);
|
|
1152
|
+
byType[balance.type] = {
|
|
1153
|
+
allocated: balance.allocated + balance.carriedOver,
|
|
1154
|
+
used: balance.used,
|
|
1155
|
+
pending: balance.pending,
|
|
1156
|
+
available
|
|
1157
|
+
};
|
|
1158
|
+
totalAllocated += balance.allocated + balance.carriedOver;
|
|
1159
|
+
totalUsed += balance.used;
|
|
1160
|
+
totalPending += balance.pending;
|
|
1161
|
+
}
|
|
1162
|
+
return {
|
|
1163
|
+
year,
|
|
1164
|
+
balances,
|
|
1165
|
+
totalAllocated,
|
|
1166
|
+
totalUsed,
|
|
1167
|
+
totalPending,
|
|
1168
|
+
totalAvailable: Math.max(0, totalAllocated - totalUsed - totalPending),
|
|
1169
|
+
byType
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
function initializeLeaveBalances(hireDate, config = {}, year = (/* @__PURE__ */ new Date()).getFullYear()) {
|
|
1173
|
+
const {
|
|
1174
|
+
defaultAllocations = DEFAULT_LEAVE_ALLOCATIONS,
|
|
1175
|
+
proRateNewHires = true,
|
|
1176
|
+
fiscalYearStartMonth = 1
|
|
1177
|
+
} = config;
|
|
1178
|
+
const fiscalYearStart = new Date(year, fiscalYearStartMonth - 1, 1);
|
|
1179
|
+
const fiscalYearEnd = new Date(year + 1, fiscalYearStartMonth - 1, 0);
|
|
1180
|
+
let prorationRatio = 1;
|
|
1181
|
+
if (proRateNewHires && hireDate > fiscalYearStart) {
|
|
1182
|
+
const totalDays = diffInDays2(fiscalYearStart, fiscalYearEnd);
|
|
1183
|
+
const remainingDays = diffInDays2(hireDate, fiscalYearEnd);
|
|
1184
|
+
prorationRatio = Math.max(0, Math.min(1, remainingDays / totalDays));
|
|
1185
|
+
}
|
|
1186
|
+
const balances = [];
|
|
1187
|
+
for (const [type, allocation] of Object.entries(defaultAllocations)) {
|
|
1188
|
+
if (allocation > 0) {
|
|
1189
|
+
balances.push({
|
|
1190
|
+
type,
|
|
1191
|
+
allocated: Math.round(allocation * prorationRatio),
|
|
1192
|
+
used: 0,
|
|
1193
|
+
pending: 0,
|
|
1194
|
+
carriedOver: 0,
|
|
1195
|
+
year
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
return balances;
|
|
1200
|
+
}
|
|
1201
|
+
function proRateAllocation(fullAllocation, hireDate, fiscalYearStartMonth = 1, year = (/* @__PURE__ */ new Date()).getFullYear()) {
|
|
1202
|
+
const fiscalYearStart = new Date(year, fiscalYearStartMonth - 1, 1);
|
|
1203
|
+
if (hireDate <= fiscalYearStart) {
|
|
1204
|
+
return fullAllocation;
|
|
1205
|
+
}
|
|
1206
|
+
const fiscalYearEnd = new Date(year + 1, fiscalYearStartMonth - 1, 0);
|
|
1207
|
+
const totalDays = diffInDays2(fiscalYearStart, fiscalYearEnd);
|
|
1208
|
+
const remainingDays = Math.max(0, diffInDays2(hireDate, fiscalYearEnd));
|
|
1209
|
+
return Math.round(fullAllocation * remainingDays / totalDays);
|
|
1210
|
+
}
|
|
1211
|
+
function calculateUnpaidLeaveDeduction(baseSalary, unpaidDays, workingDaysInMonth) {
|
|
1212
|
+
if (unpaidDays <= 0 || workingDaysInMonth <= 0) return 0;
|
|
1213
|
+
const dailyRate = baseSalary / workingDaysInMonth;
|
|
1214
|
+
return Math.round(dailyRate * unpaidDays);
|
|
1215
|
+
}
|
|
1216
|
+
function getUnpaidLeaveDays(leaveRequests, status = "approved") {
|
|
1217
|
+
return leaveRequests.filter((r) => r.type === "unpaid" && r.status === status).reduce((sum2, r) => sum2 + r.days, 0);
|
|
1218
|
+
}
|
|
1219
|
+
function calculateCarryOver(balances, maxCarryOver = DEFAULT_CARRY_OVER, newYearAllocations = DEFAULT_LEAVE_ALLOCATIONS) {
|
|
1220
|
+
if (!balances.length) return [];
|
|
1221
|
+
const currentYear = balances[0].year;
|
|
1222
|
+
const newYear = currentYear + 1;
|
|
1223
|
+
return balances.map((balance) => {
|
|
1224
|
+
const available = balance.allocated + balance.carriedOver - balance.used - balance.pending;
|
|
1225
|
+
const maxForType = maxCarryOver[balance.type] ?? 0;
|
|
1226
|
+
const carryOver = maxForType > 0 ? Math.min(Math.max(0, available), maxForType) : 0;
|
|
1227
|
+
return {
|
|
1228
|
+
type: balance.type,
|
|
1229
|
+
allocated: newYearAllocations[balance.type] ?? DEFAULT_LEAVE_ALLOCATIONS[balance.type] ?? 0,
|
|
1230
|
+
used: 0,
|
|
1231
|
+
pending: 0,
|
|
1232
|
+
carriedOver: carryOver,
|
|
1233
|
+
year: newYear
|
|
1234
|
+
};
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1237
|
+
function accrueLeaveToBalance(balances, type, amount, year = (/* @__PURE__ */ new Date()).getFullYear()) {
|
|
1238
|
+
const existingIdx = balances.findIndex((b) => b.type === type && b.year === year);
|
|
1239
|
+
if (existingIdx >= 0) {
|
|
1240
|
+
balances[existingIdx].allocated += amount;
|
|
1241
|
+
} else {
|
|
1242
|
+
balances.push({
|
|
1243
|
+
type,
|
|
1244
|
+
allocated: amount,
|
|
1245
|
+
used: 0,
|
|
1246
|
+
pending: 0,
|
|
1247
|
+
carriedOver: 0,
|
|
1248
|
+
year
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
return balances;
|
|
1252
|
+
}
|
|
1253
|
+
function diffInDays2(start, end) {
|
|
1254
|
+
const startDate = new Date(start);
|
|
1255
|
+
const endDate = new Date(end);
|
|
1256
|
+
startDate.setHours(0, 0, 0, 0);
|
|
1257
|
+
endDate.setHours(0, 0, 0, 0);
|
|
1258
|
+
return Math.ceil((endDate.getTime() - startDate.getTime()) / (1e3 * 60 * 60 * 24));
|
|
1259
|
+
}
|
|
1260
|
+
var leave_default = {
|
|
1261
|
+
DEFAULT_LEAVE_ALLOCATIONS,
|
|
1262
|
+
DEFAULT_CARRY_OVER,
|
|
1263
|
+
calculateLeaveDays,
|
|
1264
|
+
hasLeaveBalance,
|
|
1265
|
+
getLeaveBalance,
|
|
1266
|
+
getLeaveBalances,
|
|
1267
|
+
getAvailableDays,
|
|
1268
|
+
getLeaveSummary,
|
|
1269
|
+
initializeLeaveBalances,
|
|
1270
|
+
proRateAllocation,
|
|
1271
|
+
calculateUnpaidLeaveDeduction,
|
|
1272
|
+
getUnpaidLeaveDays,
|
|
1273
|
+
calculateCarryOver,
|
|
1274
|
+
accrueLeaveToBalance
|
|
1275
|
+
};
|
|
1276
|
+
|
|
1277
|
+
// src/errors/index.ts
|
|
1278
|
+
var PayrollError = class extends Error {
|
|
1279
|
+
code;
|
|
1280
|
+
status;
|
|
1281
|
+
context;
|
|
1282
|
+
timestamp;
|
|
1283
|
+
/**
|
|
1284
|
+
* Create a PayrollError.
|
|
1285
|
+
*
|
|
1286
|
+
* Supports BOTH constructor styles for backwards compatibility:
|
|
1287
|
+
* - new PayrollError(message, code?, status?, context?)
|
|
1288
|
+
* - new PayrollError(code, status, message, context?)
|
|
1289
|
+
*/
|
|
1290
|
+
constructor(messageOrCode, codeOrStatus = "PAYROLL_ERROR", statusOrMessage = 500, context = {}) {
|
|
1291
|
+
const isLegacySignature = typeof messageOrCode === "string" && typeof codeOrStatus === "string";
|
|
1292
|
+
const message = isLegacySignature ? messageOrCode : statusOrMessage;
|
|
1293
|
+
super(message);
|
|
1294
|
+
this.name = this.constructor.name;
|
|
1295
|
+
this.code = isLegacySignature ? codeOrStatus : messageOrCode;
|
|
1296
|
+
this.status = isLegacySignature ? statusOrMessage : codeOrStatus;
|
|
1297
|
+
this.context = context ?? {};
|
|
1298
|
+
this.timestamp = /* @__PURE__ */ new Date();
|
|
1299
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Convert error to JSON for API responses (ClockIn-compatible shape)
|
|
1303
|
+
*/
|
|
1304
|
+
toJSON() {
|
|
1305
|
+
return {
|
|
1306
|
+
error: {
|
|
1307
|
+
type: this.name,
|
|
1308
|
+
code: this.code,
|
|
1309
|
+
message: this.message,
|
|
1310
|
+
status: this.status,
|
|
1311
|
+
context: this.context,
|
|
1312
|
+
timestamp: this.timestamp.toISOString()
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Check if error is operational (expected) vs programmer error
|
|
1318
|
+
*/
|
|
1319
|
+
isOperational() {
|
|
1320
|
+
return true;
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
var EmployeeNotFoundError = class extends PayrollError {
|
|
1324
|
+
constructor(employeeId, context) {
|
|
1325
|
+
super(
|
|
1326
|
+
employeeId ? `Employee not found: ${employeeId}` : "Employee not found",
|
|
1327
|
+
"EMPLOYEE_NOT_FOUND",
|
|
1328
|
+
404,
|
|
1329
|
+
context ?? {}
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
|
|
1334
|
+
// src/utils/employee-lookup.ts
|
|
1335
|
+
async function findEmployeeSecure(model, options) {
|
|
1336
|
+
const {
|
|
1337
|
+
organizationId,
|
|
1338
|
+
_id,
|
|
1339
|
+
employeeId,
|
|
1340
|
+
employeeIdMode = "auto",
|
|
1341
|
+
userId,
|
|
1342
|
+
email,
|
|
1343
|
+
session,
|
|
1344
|
+
populate
|
|
1345
|
+
} = options;
|
|
1346
|
+
const query = {};
|
|
1347
|
+
if (organizationId) {
|
|
1348
|
+
query.organizationId = toObjectId(organizationId);
|
|
1349
|
+
}
|
|
1350
|
+
if (_id) {
|
|
1351
|
+
query._id = toObjectId(_id);
|
|
1352
|
+
} else if (employeeId !== void 0) {
|
|
1353
|
+
const shouldTreatAsObjectId = employeeIdMode === "objectId" || employeeIdMode === "auto" && isValidObjectId(employeeId);
|
|
1354
|
+
const shouldTreatAsBusinessId = employeeIdMode === "businessId" || employeeIdMode === "auto" && !isValidObjectId(employeeId);
|
|
1355
|
+
if (shouldTreatAsObjectId) {
|
|
1356
|
+
query._id = toObjectId(employeeId);
|
|
1357
|
+
} else if (shouldTreatAsBusinessId) {
|
|
1358
|
+
query.employeeId = employeeId;
|
|
1359
|
+
}
|
|
1360
|
+
} else if (userId) {
|
|
1361
|
+
query.userId = toObjectId(userId);
|
|
1362
|
+
} else if (email) {
|
|
1363
|
+
query.email = email;
|
|
1364
|
+
} else {
|
|
1365
|
+
throw new Error(
|
|
1366
|
+
"findEmployeeSecure requires at least one identifier: _id, employeeId, userId, or email"
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
let mongooseQuery = model.findOne(query);
|
|
1370
|
+
if (session) {
|
|
1371
|
+
mongooseQuery = mongooseQuery.session(session);
|
|
1372
|
+
}
|
|
1373
|
+
if (populate) {
|
|
1374
|
+
const fields = Array.isArray(populate) ? populate : [populate];
|
|
1375
|
+
for (const field of fields) {
|
|
1376
|
+
mongooseQuery = mongooseQuery.populate(field);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
const employee2 = await mongooseQuery;
|
|
1380
|
+
if (!employee2) {
|
|
1381
|
+
const identifier = _id ? `_id=${_id}` : employeeId ? `employeeId=${employeeId}` : userId ? `userId=${userId}` : `email=${email}`;
|
|
1382
|
+
throw new EmployeeNotFoundError(
|
|
1383
|
+
`Employee not found: ${identifier}${organizationId ? ` in organization ${organizationId}` : ""}`
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
return employee2;
|
|
1387
|
+
}
|
|
1388
|
+
async function employeeExistsSecure(model, options) {
|
|
1389
|
+
try {
|
|
1390
|
+
await findEmployeeSecure(model, options);
|
|
1391
|
+
return true;
|
|
1392
|
+
} catch (error) {
|
|
1393
|
+
if (error instanceof EmployeeNotFoundError) {
|
|
1394
|
+
return false;
|
|
1395
|
+
}
|
|
1396
|
+
throw error;
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
async function findEmployeesSecure(model, options) {
|
|
1400
|
+
const { organizationId, filter = {}, session, limit, skip, sort } = options;
|
|
1401
|
+
const query = {
|
|
1402
|
+
organizationId: toObjectId(organizationId),
|
|
1403
|
+
...filter
|
|
1404
|
+
};
|
|
1405
|
+
let mongooseQuery = model.find(query);
|
|
1406
|
+
if (session) {
|
|
1407
|
+
mongooseQuery = mongooseQuery.session(session);
|
|
1408
|
+
}
|
|
1409
|
+
if (limit) {
|
|
1410
|
+
mongooseQuery = mongooseQuery.limit(limit);
|
|
1411
|
+
}
|
|
1412
|
+
if (skip) {
|
|
1413
|
+
mongooseQuery = mongooseQuery.skip(skip);
|
|
1414
|
+
}
|
|
1415
|
+
if (sort) {
|
|
1416
|
+
mongooseQuery = mongooseQuery.sort(sort);
|
|
1417
|
+
}
|
|
1418
|
+
return mongooseQuery;
|
|
1419
|
+
}
|
|
1420
|
+
function requireOrganizationId(organizationId, operation) {
|
|
1421
|
+
if (!organizationId) {
|
|
1422
|
+
throw new Error(
|
|
1423
|
+
`${operation} requires organizationId. In multi-tenant mode, you must explicitly provide organizationId. In single-tenant mode, ensure autoInject is enabled in configuration.`
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// src/utils/org-resolution.ts
|
|
1429
|
+
function resolveOrganizationId(params) {
|
|
1430
|
+
const { explicit, context, container, operation } = params;
|
|
1431
|
+
if (explicit) {
|
|
1432
|
+
return toObjectId(explicit);
|
|
1433
|
+
}
|
|
1434
|
+
if (context?.organizationId) {
|
|
1435
|
+
return toObjectId(context.organizationId);
|
|
1436
|
+
}
|
|
1437
|
+
if (container?.isSingleTenant()) {
|
|
1438
|
+
const singleTenantConfig = container.getSingleTenantConfig();
|
|
1439
|
+
if (singleTenantConfig?.autoInject) {
|
|
1440
|
+
const orgId = container.getOrganizationId();
|
|
1441
|
+
if (orgId) {
|
|
1442
|
+
return toObjectId(orgId);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
const operationName = operation || "Operation";
|
|
1447
|
+
throw new Error(
|
|
1448
|
+
`${operationName} requires organizationId. Options:
|
|
1449
|
+
1. Provide it explicitly in parameters
|
|
1450
|
+
2. Pass it via context (from middleware/auth)
|
|
1451
|
+
3. Enable single-tenant mode with autoInject: true
|
|
1452
|
+
|
|
1453
|
+
Example (multi-tenant):
|
|
1454
|
+
await payroll.${operation || "method"}({ organizationId: org._id, ... });
|
|
1455
|
+
|
|
1456
|
+
Example (single-tenant):
|
|
1457
|
+
const payroll = createPayrollInstance()
|
|
1458
|
+
.withModels({ ... })
|
|
1459
|
+
.forSingleTenant({ organizationId: myOrg._id, autoInject: true })
|
|
1460
|
+
.build();`
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
function validateOrganizationId(organizationId, operation) {
|
|
1464
|
+
if (!organizationId) {
|
|
1465
|
+
throw new Error(
|
|
1466
|
+
`${operation} requires organizationId. Provide it explicitly, via context, or enable single-tenant mode with autoInject.`
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1469
|
+
try {
|
|
1470
|
+
return toObjectId(organizationId);
|
|
1471
|
+
} catch (error) {
|
|
1472
|
+
throw new Error(
|
|
1473
|
+
`${operation} received invalid organizationId: ${organizationId}. Must be a valid ObjectId, ObjectId string, or ObjectId-like object.`
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
function tryResolveOrganizationId(params) {
|
|
1478
|
+
try {
|
|
1479
|
+
return resolveOrganizationId(params);
|
|
1480
|
+
} catch {
|
|
1481
|
+
return null;
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// src/utils/employee-identity.ts
|
|
1486
|
+
function detectEmployeeIdType(employeeId) {
|
|
1487
|
+
if (isValidObjectId(employeeId)) {
|
|
1488
|
+
return "objectId";
|
|
1489
|
+
}
|
|
1490
|
+
return "string";
|
|
1491
|
+
}
|
|
1492
|
+
function normalizeEmployeeId(employeeId) {
|
|
1493
|
+
const idType = detectEmployeeIdType(employeeId);
|
|
1494
|
+
if (idType === "objectId") {
|
|
1495
|
+
return toObjectId(employeeId);
|
|
1496
|
+
}
|
|
1497
|
+
return employeeId;
|
|
1498
|
+
}
|
|
1499
|
+
function isStringEmployeeId(value) {
|
|
1500
|
+
return typeof value === "string" && !isValidObjectId(value);
|
|
1501
|
+
}
|
|
1502
|
+
function isObjectIdEmployeeId(value) {
|
|
1503
|
+
return isValidObjectId(value);
|
|
1504
|
+
}
|
|
1505
|
+
function formatEmployeeId(employeeId) {
|
|
1506
|
+
const idType = detectEmployeeIdType(employeeId);
|
|
1507
|
+
if (idType === "objectId") {
|
|
1508
|
+
return `_id=${toObjectId(employeeId).toString()}`;
|
|
1509
|
+
}
|
|
1510
|
+
return `employeeId=${employeeId}`;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
export { DEFAULT_CARRY_OVER, DEFAULT_LEAVE_ALLOCATIONS, EmployeeQueryBuilder, PayrollQueryBuilder, QueryBuilder, accrueLeaveToBalance, addDays, addMonths, addYears, applyPercentage, applyProRating, applyTaxBrackets, buildAggregationPipeline, buildEmployeeQuery, buildPayrollQuery, calculateAllowanceAmount, calculateAllowances, calculateCarryOver, calculateCompensationBreakdown, calculateDailyRate, calculateDeductionAmount, calculateDeductions, calculateGross, calculateHourlyRate, calculateLeaveDays, calculateNet, calculateOvertime, calculatePercentage, calculateProRatedSalary, calculateProRating, calculateProbationEnd, calculateTax, calculateTotalCompensation, calculateUnpaidLeaveDeduction, calculateYearsOfService, calculation_default as calculationUtils, canReceiveSalary, canUpdateEmployment, compose, composeValidators, createAllowanceCalculator, createChildLogger, createDeductionCalculator, createQueryBuilder, createSilentLogger, createValidator, date_default as dateUtils, daysBetween, detectEmployeeIdType, diffInDays, diffInMonths, diffInYears, disableLogging, employee, employeeExistsSecure, enableLogging, endOfDay, endOfMonth, endOfYear, findEmployeeSecure, findEmployeesSecure, formatDateForDB, formatEmployeeId, formatPeriod, getAvailableDays, getCurrentPeriod, getDayName, getDayOfWeek, getDaysInMonth, getLeaveBalance, getLeaveBalances, getLeaveSummary, getLogger, getMonthName, getPayPeriod, getPayPeriodDateRange, getShortMonthName, getUnpaidLeaveDays, getWorkingDaysInMonth, groupStage, hasCompensation, hasCompletedProbation, hasLeaveBalance, hasRequiredFields, inRange, initializeLeaveBalances, isActive, isDateInRange, isEligibleForBonus, isEligibleForPayroll, isEmployed, isInProbation, isInRange, isLoggingEnabled, isObjectIdEmployeeId, isOnLeave, isOnProbation, isPositive, isStringEmployeeId, isSuspended, isTerminated, isValidBankDetails, isValidCompensation, isValidEmploymentType, isValidObjectId, isValidStatus, isWeekday, isWeekend, leave_default as leaveUtils, limitStage, logger, lookupStage, matchStage, max, maxValue, min, minValue, monthsBetween, normalizeEmployeeId, oneOf, parseDBDate, parsePeriod, payroll, pipe, proRateAllocation, projectStage, query_builders_default as queryBuilders, requireOrganizationId, required, resetLogger, resolveOrganizationId, roundTo, safeToObjectId, setLogger, skipStage, sortStage, startOfDay, startOfMonth, startOfYear, subDays, subMonths, sum, sumAllowances, sumBy, sumDeductions, toObjectId, tryResolveOrganizationId, unwindStage, validateOrganizationId, validation_default as validationUtils };
|
|
1045
1514
|
//# sourceMappingURL=index.js.map
|
|
1046
1515
|
//# sourceMappingURL=index.js.map
|