@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.

@@ -1,5 +1,6 @@
1
- import { o as Logger, $ as PayPeriodInfo, a0 as ProRatingResult, y as Allowance, z as Deduction, C as Compensation, F as CompensationBreakdownResult, a1 as TaxCalculationResult, G as EmployeeStatus, a2 as EmployeeValidationResult, Q as BankDetails, t as EmploymentType, O as ObjectIdLike, s as Department, K as PayrollStatus } from '../types-BSYyX2KJ.js';
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
  */
@@ -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
- export { EmployeeQueryBuilder, PayrollQueryBuilder, QueryBuilder, addDays, addMonths, addYears, applyPercentage, applyProRating, applyTaxBrackets, buildAggregationPipeline, buildEmployeeQuery, buildPayrollQuery, calculateAllowanceAmount, calculateAllowances, calculateCompensationBreakdown, calculateDailyRate, calculateDeductionAmount, calculateDeductions, calculateGross, calculateHourlyRate, calculateNet, calculateOvertime, calculatePercentage, calculateProRatedSalary, calculateProRating, calculateProbationEnd, calculateTax, calculateTotalCompensation, calculateYearsOfService, calculation_default as calculationUtils, canReceiveSalary, canUpdateEmployment, compose, composeValidators, createAllowanceCalculator, createChildLogger, createDeductionCalculator, createQueryBuilder, createSilentLogger, createValidator, date_default as dateUtils, daysBetween, diffInDays, diffInMonths, diffInYears, disableLogging, employee, enableLogging, endOfDay, endOfMonth, endOfYear, formatDateForDB, formatPeriod, getCurrentPeriod, getDayName, getDayOfWeek, getDaysInMonth, getLogger, getMonthName, getPayPeriod, getPayPeriodDateRange, getShortMonthName, getWorkingDaysInMonth, groupStage, hasCompensation, hasCompletedProbation, hasRequiredFields, inRange, isActive, isDateInRange, isEligibleForBonus, isEligibleForPayroll, isEmployed, isInProbation, isInRange, isLoggingEnabled, isOnLeave, isOnProbation, isPositive, isSuspended, isTerminated, isValidBankDetails, isValidCompensation, isValidEmploymentType, isValidObjectId, isValidStatus, isWeekday, isWeekend, limitStage, logger, lookupStage, matchStage, max, maxValue, min, minValue, monthsBetween, oneOf, parseDBDate, parsePeriod, payroll, pipe, projectStage, query_builders_default as queryBuilders, required, resetLogger, roundTo, safeToObjectId, setLogger, skipStage, sortStage, startOfDay, startOfMonth, startOfYear, subDays, subMonths, sum, sumAllowances, sumBy, sumDeductions, toObjectId, unwindStage, validation_default as validationUtils };
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