@classytic/payroll 1.0.2 → 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.

Files changed (78) hide show
  1. package/README.md +2599 -574
  2. package/dist/calculators/index.d.ts +433 -0
  3. package/dist/calculators/index.js +283 -0
  4. package/dist/calculators/index.js.map +1 -0
  5. package/dist/core/index.d.ts +314 -0
  6. package/dist/core/index.js +1166 -0
  7. package/dist/core/index.js.map +1 -0
  8. package/dist/employee-identity-DXhgOgXE.d.ts +473 -0
  9. package/dist/employee.factory-BlZqhiCk.d.ts +189 -0
  10. package/dist/idempotency-Cw2CWicb.d.ts +52 -0
  11. package/dist/index.d.ts +902 -0
  12. package/dist/index.js +9108 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/jurisdiction/index.d.ts +660 -0
  15. package/dist/jurisdiction/index.js +533 -0
  16. package/dist/jurisdiction/index.js.map +1 -0
  17. package/dist/payroll.d.ts +429 -0
  18. package/dist/payroll.js +5192 -0
  19. package/dist/payroll.js.map +1 -0
  20. package/dist/schemas/index.d.ts +3262 -0
  21. package/dist/schemas/index.js +780 -0
  22. package/dist/schemas/index.js.map +1 -0
  23. package/dist/services/index.d.ts +582 -0
  24. package/dist/services/index.js +2172 -0
  25. package/dist/services/index.js.map +1 -0
  26. package/dist/shift-compliance/index.d.ts +1171 -0
  27. package/dist/shift-compliance/index.js +1479 -0
  28. package/dist/shift-compliance/index.js.map +1 -0
  29. package/dist/types-BN3K_Uhr.d.ts +1842 -0
  30. package/dist/utils/index.d.ts +893 -0
  31. package/dist/utils/index.js +1515 -0
  32. package/dist/utils/index.js.map +1 -0
  33. package/package.json +72 -37
  34. package/dist/types/config.d.ts +0 -162
  35. package/dist/types/core/compensation.manager.d.ts +0 -54
  36. package/dist/types/core/employment.manager.d.ts +0 -49
  37. package/dist/types/core/payroll.manager.d.ts +0 -60
  38. package/dist/types/enums.d.ts +0 -117
  39. package/dist/types/factories/compensation.factory.d.ts +0 -196
  40. package/dist/types/factories/employee.factory.d.ts +0 -149
  41. package/dist/types/factories/payroll.factory.d.ts +0 -319
  42. package/dist/types/hrm.orchestrator.d.ts +0 -47
  43. package/dist/types/index.d.ts +0 -20
  44. package/dist/types/init.d.ts +0 -30
  45. package/dist/types/models/payroll-record.model.d.ts +0 -3
  46. package/dist/types/plugins/employee.plugin.d.ts +0 -2
  47. package/dist/types/schemas/employment.schema.d.ts +0 -959
  48. package/dist/types/services/compensation.service.d.ts +0 -94
  49. package/dist/types/services/employee.service.d.ts +0 -28
  50. package/dist/types/services/payroll.service.d.ts +0 -30
  51. package/dist/types/utils/calculation.utils.d.ts +0 -26
  52. package/dist/types/utils/date.utils.d.ts +0 -35
  53. package/dist/types/utils/logger.d.ts +0 -12
  54. package/dist/types/utils/query-builders.d.ts +0 -83
  55. package/dist/types/utils/validation.utils.d.ts +0 -33
  56. package/payroll.d.ts +0 -241
  57. package/src/config.js +0 -177
  58. package/src/core/compensation.manager.js +0 -242
  59. package/src/core/employment.manager.js +0 -224
  60. package/src/core/payroll.manager.js +0 -499
  61. package/src/enums.js +0 -141
  62. package/src/factories/compensation.factory.js +0 -198
  63. package/src/factories/employee.factory.js +0 -173
  64. package/src/factories/payroll.factory.js +0 -413
  65. package/src/hrm.orchestrator.js +0 -139
  66. package/src/index.js +0 -172
  67. package/src/init.js +0 -62
  68. package/src/models/payroll-record.model.js +0 -126
  69. package/src/plugins/employee.plugin.js +0 -164
  70. package/src/schemas/employment.schema.js +0 -126
  71. package/src/services/compensation.service.js +0 -231
  72. package/src/services/employee.service.js +0 -162
  73. package/src/services/payroll.service.js +0 -213
  74. package/src/utils/calculation.utils.js +0 -91
  75. package/src/utils/date.utils.js +0 -120
  76. package/src/utils/logger.js +0 -36
  77. package/src/utils/query-builders.js +0 -185
  78. package/src/utils/validation.utils.js +0 -122
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/logger.ts","../src/utils/query-builders.ts","../src/errors/index.ts","../src/utils/employee-lookup.ts","../src/utils/org-resolution.ts","../src/utils/date.ts","../src/enums.ts","../src/utils/validation.ts","../src/utils/calculation.ts","../src/utils/leave.ts","../src/utils/employee-identity.ts","../src/utils/index.ts","../src/services/tax-withholding.service.ts","../src/core/container.ts","../src/config.ts","../src/core/events.ts","../src/core/plugin.ts","../src/core/idempotency.ts","../src/core/webhooks.ts","../src/payroll.ts","../src/factories/employee.factory.ts","../src/services/employee.service.ts","../src/factories/payroll.factory.ts","../src/services/payroll.service.ts","../src/factories/compensation.factory.ts","../src/services/compensation.service.ts","../src/calculators/salary.calculator.ts","../src/core/config.ts","../src/calculators/prorating.calculator.ts","../src/calculators/attendance.calculator.ts"],"names":["logger","min","max","employee","sum","payroll","periodWorkingDays","config","mongoose","TaxWithholdingService"],"mappings":"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","file":"payroll.js","sourcesContent":["/**\n * @classytic/payroll - Logger\n *\n * Pluggable logger abstraction\n * Defaults to console, can be replaced with pino, winston, etc.\n */\n\nimport type { Logger } from '../types.js';\n\n// ============================================================================\n// Default Logger Implementation\n// ============================================================================\n\nconst createConsoleLogger = (): Logger => ({\n info: (message: string, meta?: Record<string, unknown>) => {\n if (meta) {\n console.log(`[Payroll] INFO: ${message}`, meta);\n } else {\n console.log(`[Payroll] INFO: ${message}`);\n }\n },\n error: (message: string, meta?: Record<string, unknown>) => {\n if (meta) {\n console.error(`[Payroll] ERROR: ${message}`, meta);\n } else {\n console.error(`[Payroll] ERROR: ${message}`);\n }\n },\n warn: (message: string, meta?: Record<string, unknown>) => {\n if (meta) {\n console.warn(`[Payroll] WARN: ${message}`, meta);\n } else {\n console.warn(`[Payroll] WARN: ${message}`);\n }\n },\n debug: (message: string, meta?: Record<string, unknown>) => {\n if (process.env.NODE_ENV !== 'production') {\n if (meta) {\n console.log(`[Payroll] DEBUG: ${message}`, meta);\n } else {\n console.log(`[Payroll] DEBUG: ${message}`);\n }\n }\n },\n});\n\n// ============================================================================\n// Logger State\n// ============================================================================\n\nlet currentLogger: Logger = createConsoleLogger();\nlet loggingEnabled = true;\n\n// ============================================================================\n// Logger Functions\n// ============================================================================\n\n/**\n * Get the current logger instance\n */\nexport function getLogger(): Logger {\n return currentLogger;\n}\n\n/**\n * Set a custom logger instance\n */\nexport function setLogger(logger: Logger): void {\n currentLogger = logger;\n}\n\n/**\n * Reset to default console logger\n */\nexport function resetLogger(): void {\n currentLogger = createConsoleLogger();\n}\n\n/**\n * Create a child logger with prefix\n */\nexport function createChildLogger(prefix: string): Logger {\n const parent = currentLogger;\n return {\n info: (message: string, meta?: Record<string, unknown>) =>\n parent.info(`[${prefix}] ${message}`, meta),\n error: (message: string, meta?: Record<string, unknown>) =>\n parent.error(`[${prefix}] ${message}`, meta),\n warn: (message: string, meta?: Record<string, unknown>) =>\n parent.warn(`[${prefix}] ${message}`, meta),\n debug: (message: string, meta?: Record<string, unknown>) =>\n parent.debug(`[${prefix}] ${message}`, meta),\n };\n}\n\n/**\n * Create a silent logger (for testing)\n */\nexport function createSilentLogger(): Logger {\n return {\n info: () => {},\n error: () => {},\n warn: () => {},\n debug: () => {},\n };\n}\n\n/**\n * Enable logging globally\n */\nexport function enableLogging(): void {\n loggingEnabled = true;\n}\n\n/**\n * Disable logging globally (useful for production)\n */\nexport function disableLogging(): void {\n loggingEnabled = false;\n}\n\n/**\n * Check if logging is enabled\n */\nexport function isLoggingEnabled(): boolean {\n return loggingEnabled;\n}\n\n// ============================================================================\n// Logger Proxy Object\n// ============================================================================\n\n/**\n * Logger proxy that always delegates to currentLogger\n * Respects global logging enabled/disabled state\n */\nexport const logger: Logger = {\n info: (message: string, meta?: Record<string, unknown>) => {\n if (loggingEnabled) currentLogger.info(message, meta);\n },\n error: (message: string, meta?: Record<string, unknown>) => {\n if (loggingEnabled) currentLogger.error(message, meta);\n },\n warn: (message: string, meta?: Record<string, unknown>) => {\n if (loggingEnabled) currentLogger.warn(message, meta);\n },\n debug: (message: string, meta?: Record<string, unknown>) => {\n if (loggingEnabled) currentLogger.debug(message, meta);\n },\n};\n\nexport default logger;\n\n","/**\n * @classytic/payroll - Query Builders\n *\n * Fluent API for building MongoDB queries\n * Type-safe, chainable, beautiful\n */\n\nimport mongoose, { Types } from 'mongoose';\nimport type {\n ObjectIdLike,\n EmployeeStatus,\n PayrollStatus,\n Department,\n EmploymentType,\n} from '../types.js';\n\n// ============================================================================\n// ObjectId Helpers\n// ============================================================================\n\n/**\n * Convert string or ObjectId to ObjectId\n */\nexport function toObjectId(id: ObjectIdLike): Types.ObjectId {\n if (id instanceof Types.ObjectId) return id;\n return new Types.ObjectId(id);\n}\n\n/**\n * Safely convert to ObjectId (returns null if invalid)\n */\nexport function safeToObjectId(id: unknown): Types.ObjectId | null {\n if (id instanceof Types.ObjectId) return id;\n if (typeof id === 'string' && Types.ObjectId.isValid(id)) {\n return new Types.ObjectId(id);\n }\n return null;\n}\n\n/**\n * Check if value is valid ObjectId\n */\nexport function isValidObjectId(value: unknown): boolean {\n if (value instanceof Types.ObjectId) return true;\n if (typeof value === 'string') return Types.ObjectId.isValid(value);\n return false;\n}\n\n// ============================================================================\n// Base Query Builder\n// ============================================================================\n\nexport class QueryBuilder<T extends Record<string, unknown> = Record<string, unknown>> {\n protected query: T;\n\n constructor(initialQuery: T = {} as T) {\n this.query = { ...initialQuery };\n }\n\n /**\n * Add where condition\n */\n where<K extends string>(field: K, value: unknown): this {\n (this.query as Record<string, unknown>)[field] = value;\n return this;\n }\n\n /**\n * Add $in condition\n */\n whereIn<K extends string>(field: K, values: unknown[]): this {\n (this.query as Record<string, unknown>)[field] = { $in: values };\n return this;\n }\n\n /**\n * Add $nin condition\n */\n whereNotIn<K extends string>(field: K, values: unknown[]): this {\n (this.query as Record<string, unknown>)[field] = { $nin: values };\n return this;\n }\n\n /**\n * Add $gte condition\n */\n whereGte<K extends string>(field: K, value: unknown): this {\n const existing = (this.query as Record<string, Record<string, unknown>>)[field] || {};\n (this.query as Record<string, unknown>)[field] = { ...existing, $gte: value };\n return this;\n }\n\n /**\n * Add $lte condition\n */\n whereLte<K extends string>(field: K, value: unknown): this {\n const existing = (this.query as Record<string, Record<string, unknown>>)[field] || {};\n (this.query as Record<string, unknown>)[field] = { ...existing, $lte: value };\n return this;\n }\n\n /**\n * Add $gt condition\n */\n whereGt<K extends string>(field: K, value: unknown): this {\n const existing = (this.query as Record<string, Record<string, unknown>>)[field] || {};\n (this.query as Record<string, unknown>)[field] = { ...existing, $gt: value };\n return this;\n }\n\n /**\n * Add $lt condition\n */\n whereLt<K extends string>(field: K, value: unknown): this {\n const existing = (this.query as Record<string, Record<string, unknown>>)[field] || {};\n (this.query as Record<string, unknown>)[field] = { ...existing, $lt: value };\n return this;\n }\n\n /**\n * Add between condition\n */\n whereBetween<K extends string>(field: K, start: unknown, end: unknown): this {\n (this.query as Record<string, unknown>)[field] = { $gte: start, $lte: end };\n return this;\n }\n\n /**\n * Add $exists condition\n */\n whereExists<K extends string>(field: K): this {\n (this.query as Record<string, unknown>)[field] = { $exists: true };\n return this;\n }\n\n /**\n * Add $exists: false condition\n */\n whereNotExists<K extends string>(field: K): this {\n (this.query as Record<string, unknown>)[field] = { $exists: false };\n return this;\n }\n\n /**\n * Add $ne condition\n */\n whereNot<K extends string>(field: K, value: unknown): this {\n (this.query as Record<string, unknown>)[field] = { $ne: value };\n return this;\n }\n\n /**\n * Add regex condition\n */\n whereRegex<K extends string>(field: K, pattern: string, flags = 'i'): this {\n (this.query as Record<string, unknown>)[field] = { $regex: pattern, $options: flags };\n return this;\n }\n\n /**\n * Merge another query\n */\n merge(otherQuery: Record<string, unknown>): this {\n this.query = { ...this.query, ...otherQuery } as T;\n return this;\n }\n\n /**\n * Build and return the query\n */\n build(): T {\n return { ...this.query };\n }\n}\n\n// ============================================================================\n// Employee Query Builder\n// ============================================================================\n\nexport class EmployeeQueryBuilder extends QueryBuilder {\n /**\n * Filter by organization\n */\n forOrganization(organizationId: ObjectIdLike): this {\n return this.where('organizationId', toObjectId(organizationId));\n }\n\n /**\n * Filter by user\n */\n forUser(userId: ObjectIdLike): this {\n return this.where('userId', toObjectId(userId));\n }\n\n /**\n * Filter by employeeId (human-readable ID)\n */\n forEmployeeId(employeeId: string): this {\n return this.where('employeeId', employeeId);\n }\n\n /**\n * Filter by email (for guest employees)\n */\n forEmail(email: string): this {\n return this.where('email', email.toLowerCase().trim());\n }\n\n /**\n * Filter guest employees (no userId)\n */\n guestEmployees(): this {\n return this.where('userId', null);\n }\n\n /**\n * Filter user-linked employees (has userId)\n */\n userLinkedEmployees(): this {\n return this.where('userId', { $ne: null } as unknown as mongoose.Types.ObjectId);\n }\n\n /**\n * Filter by status(es)\n */\n withStatus(...statuses: EmployeeStatus[]): this {\n if (statuses.length === 1) {\n return this.where('status', statuses[0]);\n }\n return this.whereIn('status', statuses);\n }\n\n /**\n * Filter active employees\n */\n active(): this {\n return this.withStatus('active');\n }\n\n /**\n * Filter employed employees (not terminated)\n */\n employed(): this {\n return this.whereIn('status', ['active', 'on_leave', 'suspended']);\n }\n\n /**\n * Filter terminated employees\n */\n terminated(): this {\n return this.withStatus('terminated');\n }\n\n /**\n * Filter by department\n */\n inDepartment(department: Department | string): this {\n return this.where('department', department);\n }\n\n /**\n * Filter by position\n */\n inPosition(position: string): this {\n return this.where('position', position);\n }\n\n /**\n * Filter by employment type\n */\n withEmploymentType(type: EmploymentType | string): this {\n return this.where('employmentType', type);\n }\n\n /**\n * Filter by hire date (after)\n */\n hiredAfter(date: Date): this {\n return this.whereGte('hireDate', date);\n }\n\n /**\n * Filter by hire date (before)\n */\n hiredBefore(date: Date): this {\n return this.whereLte('hireDate', date);\n }\n\n /**\n * Filter by minimum salary\n */\n withMinSalary(amount: number): this {\n return this.whereGte('compensation.netSalary', amount);\n }\n\n /**\n * Filter by maximum salary\n */\n withMaxSalary(amount: number): this {\n return this.whereLte('compensation.netSalary', amount);\n }\n\n /**\n * Filter by salary range\n */\n withSalaryRange(min: number, max: number): this {\n return this.whereBetween('compensation.netSalary', min, max);\n }\n}\n\n// ============================================================================\n// Payroll Query Builder\n// ============================================================================\n\nexport class PayrollQueryBuilder extends QueryBuilder {\n /**\n * Filter by organization\n */\n forOrganization(organizationId: ObjectIdLike): this {\n return this.where('organizationId', toObjectId(organizationId));\n }\n\n /**\n * Filter by employee\n *\n * Note: PayrollRecord.employeeId is always ObjectId _id\n * If passing a string business ID, resolve to _id first\n */\n forEmployee(employeeId: ObjectIdLike | string): this {\n // For payroll queries, employeeId field is always the ObjectId _id\n // If a string business ID is passed, caller should resolve to _id first\n return this.where('employeeId', toObjectId(employeeId as ObjectIdLike));\n }\n\n /**\n * Filter by period\n */\n forPeriod(month?: number, year?: number): this {\n if (month !== undefined) {\n this.where('period.month', month);\n }\n if (year !== undefined) {\n this.where('period.year', year);\n }\n return this;\n }\n\n /**\n * Filter by status(es)\n */\n withStatus(...statuses: PayrollStatus[]): this {\n if (statuses.length === 1) {\n return this.where('status', statuses[0]);\n }\n return this.whereIn('status', statuses);\n }\n\n /**\n * Filter paid records\n */\n paid(): this {\n return this.withStatus('paid');\n }\n\n /**\n * Filter pending records\n */\n pending(): this {\n return this.whereIn('status', ['pending', 'processing']);\n }\n\n /**\n * Filter by date range\n */\n inDateRange(start: Date, end: Date): this {\n return this.whereBetween('period.payDate', start, end);\n }\n\n /**\n * Filter exported records\n */\n exported(): this {\n return this.where('exported', true);\n }\n\n /**\n * Filter not exported records\n */\n notExported(): this {\n return this.where('exported', false);\n }\n}\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\n/**\n * Create employee query builder\n */\nexport function employee(): EmployeeQueryBuilder {\n return new EmployeeQueryBuilder();\n}\n\n/**\n * Create payroll query builder\n */\nexport function payroll(): PayrollQueryBuilder {\n return new PayrollQueryBuilder();\n}\n\n/**\n * Create generic query builder\n */\nexport function createQueryBuilder<T extends Record<string, unknown> = Record<string, unknown>>(\n initialQuery?: T\n): QueryBuilder<T> {\n return new QueryBuilder(initialQuery);\n}\n\n// ============================================================================\n// Convenience Query Builders\n// ============================================================================\n\n/**\n * Build employee query from options\n */\nexport function buildEmployeeQuery(options: {\n organizationId: ObjectIdLike;\n userId?: ObjectIdLike;\n statuses?: EmployeeStatus[];\n department?: Department | string;\n employmentType?: EmploymentType | string;\n}): Record<string, unknown> {\n const builder = employee().forOrganization(options.organizationId);\n\n if (options.userId) {\n builder.forUser(options.userId);\n }\n if (options.statuses) {\n builder.withStatus(...options.statuses);\n }\n if (options.department) {\n builder.inDepartment(options.department);\n }\n if (options.employmentType) {\n builder.withEmploymentType(options.employmentType);\n }\n\n return builder.build();\n}\n\n/**\n * Build payroll query from options\n */\nexport function buildPayrollQuery(options: {\n employeeId?: ObjectIdLike;\n organizationId?: ObjectIdLike;\n month?: number;\n year?: number;\n statuses?: PayrollStatus[];\n}): Record<string, unknown> {\n const builder = payroll();\n\n if (options.organizationId) {\n builder.forOrganization(options.organizationId);\n }\n if (options.employeeId) {\n builder.forEmployee(options.employeeId);\n }\n if (options.month || options.year) {\n builder.forPeriod(options.month, options.year);\n }\n if (options.statuses) {\n builder.withStatus(...options.statuses);\n }\n\n return builder.build();\n}\n\n// ============================================================================\n// Aggregation Pipeline Helpers\n// ============================================================================\n\n/**\n * Build aggregation pipeline from stages\n */\nexport function buildAggregationPipeline(\n ...stages: Array<Record<string, unknown> | undefined | null>\n): Record<string, unknown>[] {\n return stages.filter((stage): stage is Record<string, unknown> => !!stage);\n}\n\n/**\n * Match stage\n */\nexport function matchStage(query: Record<string, unknown>): Record<string, unknown> {\n return { $match: query };\n}\n\n/**\n * Group stage\n */\nexport function groupStage(\n groupBy: string | null,\n aggregations: Record<string, unknown>\n): Record<string, unknown> {\n return {\n $group: {\n _id: groupBy,\n ...aggregations,\n },\n };\n}\n\n/**\n * Sort stage\n */\nexport function sortStage(sortBy: Record<string, 1 | -1>): Record<string, unknown> {\n return { $sort: sortBy };\n}\n\n/**\n * Limit stage\n */\nexport function limitStage(limit: number): Record<string, unknown> {\n return { $limit: limit };\n}\n\n/**\n * Skip stage\n */\nexport function skipStage(skip: number): Record<string, unknown> {\n return { $skip: skip };\n}\n\n/**\n * Project stage\n */\nexport function projectStage(fields: Record<string, unknown>): Record<string, unknown> {\n return { $project: fields };\n}\n\n/**\n * Lookup stage\n */\nexport function lookupStage(options: {\n from: string;\n localField: string;\n foreignField: string;\n as: string;\n}): Record<string, unknown> {\n return { $lookup: options };\n}\n\n/**\n * Unwind stage\n */\nexport function unwindStage(\n path: string,\n options: { preserveNullAndEmptyArrays?: boolean } = {}\n): Record<string, unknown> {\n return { $unwind: { path, ...options } };\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n toObjectId,\n safeToObjectId,\n isValidObjectId,\n QueryBuilder,\n EmployeeQueryBuilder,\n PayrollQueryBuilder,\n employee,\n payroll,\n createQueryBuilder,\n buildEmployeeQuery,\n buildPayrollQuery,\n buildAggregationPipeline,\n matchStage,\n groupStage,\n sortStage,\n limitStage,\n skipStage,\n projectStage,\n lookupStage,\n unwindStage,\n};\n\n","/**\n * @classytic/payroll - Error Handling\n *\n * Custom error classes with error codes and HTTP status\n */\n\nimport type { ErrorCode, HttpError } from '../types.js';\n\n// ============================================================================\n// Base Error Class\n// ============================================================================\n\nexport class PayrollError extends Error implements HttpError {\n readonly code: ErrorCode;\n readonly status: number;\n readonly context: Record<string, unknown>;\n readonly timestamp: Date;\n\n /**\n * Create a PayrollError.\n *\n * Supports BOTH constructor styles for backwards compatibility:\n * - new PayrollError(message, code?, status?, context?)\n * - new PayrollError(code, status, message, context?)\n */\n constructor(\n messageOrCode: string | ErrorCode,\n codeOrStatus: ErrorCode | number = 'PAYROLL_ERROR',\n statusOrMessage: number | string = 500,\n context: Record<string, unknown> = {}\n ) {\n const isLegacySignature = typeof messageOrCode === 'string' && typeof codeOrStatus === 'string';\n\n const message = isLegacySignature ? (messageOrCode as string) : (statusOrMessage as string);\n super(message);\n\n this.name = this.constructor.name;\n this.code = isLegacySignature ? (codeOrStatus as ErrorCode) : (messageOrCode as ErrorCode);\n this.status = isLegacySignature ? (statusOrMessage as number) : (codeOrStatus as number);\n this.context = context ?? {};\n this.timestamp = new Date();\n\n // Maintains proper stack trace for where error was thrown\n Error.captureStackTrace?.(this, this.constructor);\n }\n\n /**\n * Convert error to JSON for API responses (ClockIn-compatible shape)\n */\n toJSON(): Record<string, unknown> {\n return {\n error: {\n type: this.name,\n code: this.code,\n message: this.message,\n status: this.status,\n context: this.context,\n timestamp: this.timestamp.toISOString(),\n },\n };\n }\n\n /**\n * Check if error is operational (expected) vs programmer error\n */\n isOperational(): boolean {\n return true;\n }\n}\n\n// ============================================================================\n// Specific Error Classes\n// ============================================================================\n\n/**\n * Not initialized error\n */\nexport class NotInitializedError extends PayrollError {\n constructor(message = 'Payroll not initialized. Call Payroll.initialize() first.') {\n super(message, 'NOT_INITIALIZED', 500);\n }\n}\n\n/**\n * Employee not found error\n */\nexport class EmployeeNotFoundError extends PayrollError {\n constructor(employeeId?: string, context?: Record<string, unknown>) {\n super(\n employeeId ? `Employee not found: ${employeeId}` : 'Employee not found',\n 'EMPLOYEE_NOT_FOUND',\n 404,\n context ?? {}\n );\n }\n}\n\n/**\n * Invalid employee error\n */\nexport class InvalidEmployeeError extends PayrollError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, 'INVALID_EMPLOYEE', 400, context ?? {});\n }\n}\n\n/**\n * Duplicate payroll error\n */\nexport class DuplicatePayrollError extends PayrollError {\n constructor(\n employeeId: string,\n month: number,\n year: number,\n context?: Record<string, unknown>\n ) {\n super(\n `Payroll already processed for employee ${employeeId} in ${month}/${year}`,\n 'DUPLICATE_PAYROLL',\n 409,\n { employeeId, month, year, ...context }\n );\n }\n}\n\n/**\n * Validation error\n */\nexport class ValidationError extends PayrollError {\n readonly errors: string[];\n\n constructor(errors: string | string[], context?: Record<string, unknown>) {\n const errorArray = Array.isArray(errors) ? errors : [errors];\n super(errorArray.join(', '), 'VALIDATION_ERROR', 400, context ?? {});\n this.errors = errorArray;\n }\n}\n\n/**\n * Employee terminated error\n */\nexport class EmployeeTerminatedError extends PayrollError {\n constructor(employeeId?: string, context?: Record<string, unknown>) {\n super(\n employeeId\n ? `Cannot perform operation on terminated employee: ${employeeId}`\n : 'Cannot perform operation on terminated employee',\n 'EMPLOYEE_TERMINATED',\n 400,\n context ?? {}\n );\n }\n}\n\n/**\n * Already processed error\n */\nexport class AlreadyProcessedError extends PayrollError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, 'ALREADY_PROCESSED', 409, context ?? {});\n }\n}\n\n/**\n * Not eligible error\n */\nexport class NotEligibleError extends PayrollError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, 'NOT_ELIGIBLE', 400, context ?? {});\n }\n}\n\n// ============================================================================\n// Error Factory\n// ============================================================================\n\n/**\n * Create error from code\n */\nexport function createError(\n code: ErrorCode,\n message: string,\n context?: Record<string, unknown>\n): PayrollError {\n const statusMap: Record<ErrorCode, number> = {\n PAYROLL_ERROR: 500,\n NOT_INITIALIZED: 500,\n EMPLOYEE_NOT_FOUND: 404,\n INVALID_EMPLOYEE: 400,\n DUPLICATE_PAYROLL: 409,\n VALIDATION_ERROR: 400,\n EMPLOYEE_TERMINATED: 400,\n ALREADY_PROCESSED: 409,\n NOT_ELIGIBLE: 400,\n };\n\n return new PayrollError(message, code, statusMap[code] || 500, context ?? {});\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Check if error is PayrollError\n */\nexport function isPayrollError(error: unknown): error is PayrollError {\n return error instanceof PayrollError;\n}\n\n/**\n * Check if error has specific code\n */\nexport function isErrorCode(error: unknown, code: ErrorCode): boolean {\n return isPayrollError(error) && error.code === code;\n}\n\n/**\n * Extract error info for logging\n */\nexport function extractErrorInfo(error: unknown): {\n code: string;\n status: number;\n message: string;\n context?: Record<string, unknown>;\n} {\n if (isPayrollError(error)) {\n return {\n code: error.code,\n status: error.status,\n message: error.message,\n context: error.context,\n };\n }\n\n if (error instanceof Error) {\n return {\n code: 'PAYROLL_ERROR',\n status: 500,\n message: error.message,\n };\n }\n\n return {\n code: 'PAYROLL_ERROR',\n status: 500,\n message: String(error),\n };\n}\n\n// ============================================================================\n// Error Handling Utilities\n// ============================================================================\n\n/**\n * Wrap async function with error handling\n */\nexport function withErrorHandling<T extends (...args: unknown[]) => Promise<unknown>>(\n fn: T,\n errorHandler?: (error: unknown) => void\n): T {\n return (async (...args: Parameters<T>) => {\n try {\n return await fn(...args);\n } catch (error) {\n if (errorHandler) {\n errorHandler(error);\n }\n throw error;\n }\n }) as T;\n}\n\n/**\n * Convert unknown error to PayrollError\n */\nexport function toPayrollError(error: unknown): PayrollError {\n if (isPayrollError(error)) {\n return error;\n }\n\n if (error instanceof Error) {\n return new PayrollError(error.message);\n }\n\n return new PayrollError(String(error));\n}\n\n// ============================================================================\n// Legacy Alias\n// ============================================================================\n\nexport { PayrollError as HRMError };\n\n","/**\n * @classytic/payroll - Secure Employee Lookup\n *\n * Multi-tenant safe employee lookup utilities\n * Enforces organizationId isolation on all queries\n */\n\nimport type { Model } from 'mongoose';\nimport type { EmployeeDocument, ObjectIdLike } from '../types.js';\nimport { toObjectId, isValidObjectId } from './query-builders.js';\nimport { EmployeeNotFoundError } from '../errors/index.js';\n\n/**\n * Employee ID mode for explicit disambiguation\n *\n * Controls how the employeeId parameter is interpreted:\n * - 'auto': Auto-detect via isValidObjectId() (default)\n * - 'objectId': Force treat as MongoDB _id (ObjectId)\n * - 'businessId': Force treat as business employeeId string\n *\n * @since v2.3.0\n */\nexport type EmployeeIdMode = 'auto' | 'objectId' | 'businessId';\n\n/**\n * Lookup options for secure employee queries\n */\nexport interface SecureEmployeeLookupOptions {\n /**\n * Organization ID (required for multi-tenant isolation)\n * Can be omitted only in single-tenant mode with auto-inject\n */\n organizationId?: ObjectIdLike;\n\n /**\n * Employee's Mongoose _id (ObjectId)\n * Use this when you have the database ID\n * Takes priority over employeeId if both are provided\n */\n _id?: ObjectIdLike;\n\n /**\n * Employee identifier (supports both formats):\n * - ObjectId: employee._id (MongoDB document ID)\n * - String: \"EMP-001\" (business identifier)\n *\n * System auto-detects type by default:\n * - If valid ObjectId → queries by _id field\n * - If string → queries by employeeId field\n *\n * Use employeeIdType to override auto-detection if your business\n * employeeIds look like ObjectIds (24 hex characters).\n *\n * Note: If _id parameter is also provided, _id takes priority\n */\n employeeId?: ObjectIdLike | string;\n\n /**\n * Explicit mode hint for employeeId disambiguation\n *\n * - 'auto' (default): Auto-detect via isValidObjectId()\n * - 'objectId': Force treat as MongoDB _id (ObjectId)\n * - 'businessId': Force treat as business employeeId string\n *\n * Use 'businessId' if your employeeIds are 24-hex strings like\n * \"507f1f77bcf86cd799439011\" to prevent ObjectId collision.\n *\n * @default 'auto'\n * @since v2.3.0\n */\n employeeIdMode?: EmployeeIdMode;\n\n /**\n * User ID reference (optional)\n */\n userId?: ObjectIdLike;\n\n /**\n * Email address (optional)\n */\n email?: string;\n\n /**\n * Mongoose session for transactions\n */\n session?: any;\n\n /**\n * Fields to populate\n */\n populate?: string | string[];\n}\n\n/**\n * Securely find an employee by various identifiers\n * ALWAYS enforces organizationId for multi-tenant isolation\n *\n * @param model - Employee model\n * @param options - Lookup options\n * @returns Employee document or throws EmployeeNotFoundError\n *\n * @example\n * // By ObjectId _id\n * const emp = await findEmployeeSecure(Employee, {\n * _id: employee._id,\n * organizationId: org._id\n * });\n *\n * @example\n * // By string employeeId\n * const emp = await findEmployeeSecure(Employee, {\n * employeeId: \"EMP-001\",\n * organizationId: org._id\n * });\n *\n * @example\n * // By 24-hex business employeeId (force businessId mode)\n * const emp = await findEmployeeSecure(Employee, {\n * employeeId: \"507f1f77bcf86cd799439011\", // Looks like ObjectId!\n * employeeIdMode: 'businessId', // Force treat as business ID\n * organizationId: org._id\n * });\n *\n * @example\n * // By userId\n * const emp = await findEmployeeSecure(Employee, {\n * userId: user._id,\n * organizationId: org._id\n * });\n */\nexport async function findEmployeeSecure<T extends EmployeeDocument>(\n model: Model<T>,\n options: SecureEmployeeLookupOptions\n): Promise<T> {\n const {\n organizationId,\n _id,\n employeeId,\n employeeIdMode = 'auto',\n userId,\n email,\n session,\n populate,\n } = options;\n\n // Build query with organizationId isolation\n const query: Record<string, any> = {};\n\n // CRITICAL: Always include organizationId for multi-tenant safety\n if (organizationId) {\n query.organizationId = toObjectId(organizationId);\n }\n\n // Add identifier filters (priority: _id > employeeId > userId > email)\n if (_id) {\n query._id = toObjectId(_id);\n } else if (employeeId !== undefined) {\n // Resolve employeeId mode based on explicit hint or auto-detection\n const shouldTreatAsObjectId =\n employeeIdMode === 'objectId' ||\n (employeeIdMode === 'auto' && isValidObjectId(employeeId));\n\n const shouldTreatAsBusinessId =\n employeeIdMode === 'businessId' ||\n (employeeIdMode === 'auto' && !isValidObjectId(employeeId));\n\n if (shouldTreatAsObjectId) {\n // It's an ObjectId → query by _id field\n query._id = toObjectId(employeeId as ObjectIdLike);\n } else if (shouldTreatAsBusinessId) {\n // It's a string business identifier → query by employeeId field\n query.employeeId = employeeId as string;\n }\n } else if (userId) {\n query.userId = toObjectId(userId);\n } else if (email) {\n query.email = email;\n } else {\n throw new Error(\n 'findEmployeeSecure requires at least one identifier: _id, employeeId, userId, or email'\n );\n }\n\n // Build Mongoose query\n let mongooseQuery = model.findOne(query);\n\n if (session) {\n mongooseQuery = mongooseQuery.session(session);\n }\n\n if (populate) {\n const fields = Array.isArray(populate) ? populate : [populate];\n for (const field of fields) {\n mongooseQuery = mongooseQuery.populate(field);\n }\n }\n\n const employee = await mongooseQuery;\n\n if (!employee) {\n // Provide helpful error message\n const identifier = _id\n ? `_id=${_id}`\n : employeeId\n ? `employeeId=${employeeId}`\n : userId\n ? `userId=${userId}`\n : `email=${email}`;\n\n throw new EmployeeNotFoundError(\n `Employee not found: ${identifier}${organizationId ? ` in organization ${organizationId}` : ''}`\n );\n }\n\n return employee;\n}\n\n/**\n * Check if an employee exists securely (with org isolation)\n *\n * @param model - Employee model\n * @param options - Lookup options\n * @returns true if employee exists, false otherwise\n */\nexport async function employeeExistsSecure<T extends EmployeeDocument>(\n model: Model<T>,\n options: SecureEmployeeLookupOptions\n): Promise<boolean> {\n try {\n await findEmployeeSecure(model, options);\n return true;\n } catch (error) {\n if (error instanceof EmployeeNotFoundError) {\n return false;\n }\n throw error;\n }\n}\n\n/**\n * Find multiple employees securely (with org isolation)\n *\n * @param model - Employee model\n * @param options - Query options\n * @returns Array of employee documents\n */\nexport async function findEmployeesSecure<T extends EmployeeDocument>(\n model: Model<T>,\n options: {\n organizationId: ObjectIdLike;\n filter?: Record<string, any>;\n session?: any;\n limit?: number;\n skip?: number;\n sort?: Record<string, 1 | -1>;\n }\n): Promise<T[]> {\n const { organizationId, filter = {}, session, limit, skip, sort } = options;\n\n // CRITICAL: Always include organizationId\n const query = {\n organizationId: toObjectId(organizationId),\n ...filter,\n };\n\n let mongooseQuery = model.find(query);\n\n if (session) {\n mongooseQuery = mongooseQuery.session(session);\n }\n\n if (limit) {\n mongooseQuery = mongooseQuery.limit(limit);\n }\n\n if (skip) {\n mongooseQuery = mongooseQuery.skip(skip);\n }\n\n if (sort) {\n mongooseQuery = mongooseQuery.sort(sort);\n }\n\n return mongooseQuery;\n}\n\n/**\n * Validate organizationId is provided (unless single-tenant with auto-inject)\n *\n * @param organizationId - Organization ID to validate\n * @param operation - Operation name for error message\n * @throws Error if organizationId is missing\n */\nexport function requireOrganizationId(\n organizationId: ObjectIdLike | undefined,\n operation: string\n): void {\n if (!organizationId) {\n throw new Error(\n `${operation} requires organizationId. ` +\n 'In multi-tenant mode, you must explicitly provide organizationId. ' +\n 'In single-tenant mode, ensure autoInject is enabled in configuration.'\n );\n }\n}\n","/**\n * @classytic/payroll - Organization Resolution Utility\n *\n * Smart organization ID resolution with priority chain:\n * 1. Explicit parameter (highest priority)\n * 2. Context.organizationId (from middleware/auth)\n * 3. Single-tenant config (if autoInject enabled)\n * 4. Error (if none found in multi-tenant mode)\n */\n\nimport type { ObjectIdLike, OperationContext } from '../types.js';\nimport type { Container } from '../core/container.js';\nimport { toObjectId } from './query-builders.js';\nimport { Types } from 'mongoose';\n\n/**\n * Container-like interface for organization resolution\n * Only requires the methods we need, allowing any generic Container type\n */\nexport interface ContainerLike {\n isSingleTenant(): boolean;\n getSingleTenantConfig(): { organizationId?: any; autoInject?: boolean } | null;\n getOrganizationId(): string | null;\n}\n\n/**\n * Organization resolution parameters\n */\nexport interface ResolveOrganizationIdParams {\n /**\n * Explicitly provided organizationId (highest priority)\n */\n explicit?: ObjectIdLike;\n\n /**\n * Operation context with possible organizationId\n */\n context?: OperationContext;\n\n /**\n * Container for single-tenant config access\n * Accepts any Container with any generic types\n */\n container?: ContainerLike;\n\n /**\n * Operation name for error messages\n */\n operation?: string;\n}\n\n/**\n * Smart organization ID resolution\n *\n * Priority Chain:\n * 1. Explicit param (highest)\n * 2. Context.organizationId (middleware/auth)\n * 3. Single-tenant config (if autoInject enabled)\n * 4. Error (if none found)\n *\n * @param params - Resolution parameters\n * @returns Resolved ObjectId\n * @throws Error if organizationId cannot be resolved\n *\n * @example\n * // Explicit param wins\n * const orgId = resolveOrganizationId({\n * explicit: org._id,\n * context: { organizationId: other._id },\n * operation: 'processSalary'\n * });\n * // Returns: org._id\n *\n * @example\n * // Context fallback\n * const orgId = resolveOrganizationId({\n * context: { organizationId: org._id },\n * operation: 'processSalary'\n * });\n * // Returns: org._id from context\n *\n * @example\n * // Single-tenant auto-inject\n * const orgId = resolveOrganizationId({\n * container: singleTenantContainer,\n * operation: 'processSalary'\n * });\n * // Returns: organizationId from container config\n */\nexport function resolveOrganizationId(\n params: ResolveOrganizationIdParams\n): Types.ObjectId {\n const { explicit, context, container, operation } = params;\n\n // 1. Explicit param wins\n if (explicit) {\n return toObjectId(explicit);\n }\n\n // 2. Context from middleware/auth\n if (context?.organizationId) {\n return toObjectId(context.organizationId);\n }\n\n // 3. Single-tenant auto-inject\n if (container?.isSingleTenant()) {\n const singleTenantConfig = container.getSingleTenantConfig();\n if (singleTenantConfig?.autoInject) {\n const orgId = container.getOrganizationId();\n if (orgId) {\n return toObjectId(orgId);\n }\n }\n }\n\n // 4. Error - no organizationId found\n const operationName = operation || 'Operation';\n throw new Error(\n `${operationName} requires organizationId. ` +\n 'Options:\\n' +\n '1. Provide it explicitly in parameters\\n' +\n '2. Pass it via context (from middleware/auth)\\n' +\n '3. Enable single-tenant mode with autoInject: true\\n\\n' +\n 'Example (multi-tenant):\\n' +\n ` await payroll.${operation || 'method'}({ organizationId: org._id, ... });\\n\\n` +\n 'Example (single-tenant):\\n' +\n ' const payroll = createPayrollInstance()\\n' +\n ' .withModels({ ... })\\n' +\n ' .forSingleTenant({ organizationId: myOrg._id, autoInject: true })\\n' +\n ' .build();'\n );\n}\n\n/**\n * Validate that organizationId is present\n *\n * @param organizationId - Organization ID to validate\n * @param operation - Operation name for error message\n * @returns ObjectId if valid\n * @throws Error if organizationId is missing or invalid\n */\nexport function validateOrganizationId(\n organizationId: ObjectIdLike | undefined,\n operation: string\n): Types.ObjectId {\n if (!organizationId) {\n throw new Error(\n `${operation} requires organizationId. ` +\n 'Provide it explicitly, via context, or enable single-tenant mode with autoInject.'\n );\n }\n\n try {\n return toObjectId(organizationId);\n } catch (error) {\n throw new Error(\n `${operation} received invalid organizationId: ${organizationId}. ` +\n 'Must be a valid ObjectId, ObjectId string, or ObjectId-like object.'\n );\n }\n}\n\n/**\n * Try to resolve organizationId without throwing\n *\n * @param params - Resolution parameters\n * @returns ObjectId if resolved, null otherwise\n */\nexport function tryResolveOrganizationId(\n params: ResolveOrganizationIdParams\n): Types.ObjectId | null {\n try {\n return resolveOrganizationId(params);\n } catch {\n return null;\n }\n}\n","/**\n * @classytic/payroll - Date Utilities\n *\n * Pure, composable, testable date operations\n * No side effects, no mutations\n */\n\nimport type { PayPeriodInfo, PaymentFrequency } from '../types.js';\n\n// ============================================================================\n// Date Arithmetic\n// ============================================================================\n\n/**\n * Add days to a date\n */\nexport function addDays(date: Date, days: number): Date {\n const result = new Date(date);\n result.setDate(result.getDate() + days);\n return result;\n}\n\n/**\n * Add months to a date\n */\nexport function addMonths(date: Date, months: number): Date {\n const result = new Date(date);\n result.setMonth(result.getMonth() + months);\n return result;\n}\n\n/**\n * Add years to a date\n */\nexport function addYears(date: Date, years: number): Date {\n const result = new Date(date);\n result.setFullYear(result.getFullYear() + years);\n return result;\n}\n\n/**\n * Subtract days from a date\n */\nexport function subDays(date: Date, days: number): Date {\n return addDays(date, -days);\n}\n\n/**\n * Subtract months from a date\n */\nexport function subMonths(date: Date, months: number): Date {\n return addMonths(date, -months);\n}\n\n// ============================================================================\n// Date Boundaries\n// ============================================================================\n\n/**\n * Get the start of a month\n */\nexport function startOfMonth(date: Date): Date {\n const result = new Date(date);\n result.setDate(1);\n result.setHours(0, 0, 0, 0);\n return result;\n}\n\n/**\n * Get the end of a month\n */\nexport function endOfMonth(date: Date): Date {\n const result = new Date(date);\n result.setMonth(result.getMonth() + 1, 0);\n result.setHours(23, 59, 59, 999);\n return result;\n}\n\n/**\n * Get the start of a year\n */\nexport function startOfYear(date: Date): Date {\n const result = new Date(date);\n result.setMonth(0, 1);\n result.setHours(0, 0, 0, 0);\n return result;\n}\n\n/**\n * Get the end of a year\n */\nexport function endOfYear(date: Date): Date {\n const result = new Date(date);\n result.setMonth(11, 31);\n result.setHours(23, 59, 59, 999);\n return result;\n}\n\n/**\n * Get the start of a day\n */\nexport function startOfDay(date: Date): Date {\n const result = new Date(date);\n result.setHours(0, 0, 0, 0);\n return result;\n}\n\n/**\n * Get the end of a day\n */\nexport function endOfDay(date: Date): Date {\n const result = new Date(date);\n result.setHours(23, 59, 59, 999);\n return result;\n}\n\n// ============================================================================\n// Date Differences\n// ============================================================================\n\n/**\n * Calculate difference in days between two dates\n */\nexport function diffInDays(start: Date, end: Date): number {\n return Math.ceil(\n (new Date(end).getTime() - new Date(start).getTime()) / (1000 * 60 * 60 * 24)\n );\n}\n\n/**\n * Calculate difference in months between two dates\n */\nexport function diffInMonths(start: Date, end: Date): number {\n const startDate = new Date(start);\n const endDate = new Date(end);\n return (\n (endDate.getFullYear() - startDate.getFullYear()) * 12 +\n (endDate.getMonth() - startDate.getMonth())\n );\n}\n\n/**\n * Calculate difference in years between two dates\n */\nexport function diffInYears(start: Date, end: Date): number {\n return Math.floor(diffInMonths(start, end) / 12);\n}\n\n// Aliases for backwards compatibility\nexport const daysBetween = diffInDays;\nexport const monthsBetween = diffInMonths;\n\n// ============================================================================\n// Day Type Checks\n// ============================================================================\n\n/**\n * Check if date is a weekday (Mon-Fri)\n */\nexport function isWeekday(date: Date): boolean {\n const day = new Date(date).getDay();\n return day >= 1 && day <= 5;\n}\n\n/**\n * Check if date is a weekend (Sat-Sun)\n */\nexport function isWeekend(date: Date): boolean {\n const day = new Date(date).getDay();\n return day === 0 || day === 6;\n}\n\n/**\n * Get day of week (0=Sunday, 6=Saturday)\n */\nexport function getDayOfWeek(date: Date): number {\n return new Date(date).getDay();\n}\n\n/**\n * Get day name\n */\nexport function getDayName(date: Date): string {\n const days = [\n 'Sunday',\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n ];\n return days[getDayOfWeek(date)];\n}\n\n// ============================================================================\n// Pay Period Functions\n// ============================================================================\n\n/**\n * Get pay period for a given month and year\n */\nexport function getPayPeriod(month: number, year: number): PayPeriodInfo {\n const startDate = new Date(year, month - 1, 1);\n return {\n month,\n year,\n startDate: startOfMonth(startDate),\n endDate: endOfMonth(startDate),\n };\n}\n\n/**\n * Get current pay period\n */\nexport function getCurrentPeriod(date = new Date()): { year: number; month: number } {\n const d = new Date(date);\n return {\n year: d.getFullYear(),\n month: d.getMonth() + 1,\n };\n}\n\n/**\n * Get working days in a month\n */\nexport function getWorkingDaysInMonth(year: number, month: number): number {\n const start = new Date(year, month - 1, 1);\n const end = endOfMonth(start);\n let count = 0;\n \n const current = new Date(start);\n while (current <= end) {\n if (isWeekday(current)) {\n count++;\n }\n current.setDate(current.getDate() + 1);\n }\n \n return count;\n}\n\n/**\n * Get total days in a month\n */\nexport function getDaysInMonth(year: number, month: number): number {\n return new Date(year, month, 0).getDate();\n}\n\n// ============================================================================\n// Employment Date Functions\n// ============================================================================\n\n/**\n * Calculate probation end date\n */\nexport function calculateProbationEnd(\n hireDate: Date,\n probationMonths: number\n): Date | null {\n if (!probationMonths || probationMonths <= 0) return null;\n return addMonths(hireDate, probationMonths);\n}\n\n/**\n * Check if employee is on probation\n */\nexport function isOnProbation(\n probationEndDate: Date | null | undefined,\n now = new Date()\n): boolean {\n if (!probationEndDate) return false;\n return now < new Date(probationEndDate);\n}\n\n/**\n * Calculate years of service\n */\nexport function calculateYearsOfService(\n hireDate: Date,\n terminationDate?: Date | null\n): number {\n const end = terminationDate || new Date();\n const days = diffInDays(hireDate, end);\n return Math.max(0, Math.floor((days / 365.25) * 10) / 10);\n}\n\n// ============================================================================\n// Range Functions\n// ============================================================================\n\n/**\n * Check if a date is within a range\n */\nexport function isDateInRange(date: Date, start: Date, end: Date): boolean {\n const checkDate = new Date(date);\n return checkDate >= new Date(start) && checkDate <= new Date(end);\n}\n\n/**\n * Get date range for a pay period\n */\nexport function getPayPeriodDateRange(\n month: number,\n year: number\n): { start: Date; end: Date } {\n const period = getPayPeriod(month, year);\n return { start: period.startDate, end: period.endDate };\n}\n\n// ============================================================================\n// Formatting Functions\n// ============================================================================\n\n/**\n * Format date for database storage\n */\nexport function formatDateForDB(date: Date): string {\n if (!date) return '';\n return new Date(date).toISOString();\n}\n\n/**\n * Parse date from database\n */\nexport function parseDBDate(dateString: string): Date | null {\n if (!dateString) return null;\n return new Date(dateString);\n}\n\n/**\n * Format period as string (e.g., \"01/2025\")\n */\nexport function formatPeriod({ month, year }: { month: number; year: number }): string {\n return `${String(month).padStart(2, '0')}/${year}`;\n}\n\n/**\n * Parse period string back to object\n */\nexport function parsePeriod(periodString: string): { month: number; year: number } {\n const [month, year] = periodString.split('/').map(Number);\n return { month, year };\n}\n\n/**\n * Format month name\n */\nexport function getMonthName(month: number): string {\n const months = [\n 'January', 'February', 'March', 'April', 'May', 'June',\n 'July', 'August', 'September', 'October', 'November', 'December',\n ];\n return months[month - 1] || '';\n}\n\n/**\n * Format short month name\n */\nexport function getShortMonthName(month: number): string {\n const months = [\n 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\n 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n ];\n return months[month - 1] || '';\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n addDays,\n addMonths,\n addYears,\n subDays,\n subMonths,\n startOfMonth,\n endOfMonth,\n startOfYear,\n endOfYear,\n startOfDay,\n endOfDay,\n diffInDays,\n diffInMonths,\n diffInYears,\n daysBetween,\n monthsBetween,\n isWeekday,\n isWeekend,\n getDayOfWeek,\n getDayName,\n getPayPeriod,\n getCurrentPeriod,\n getWorkingDaysInMonth,\n getDaysInMonth,\n calculateProbationEnd,\n isOnProbation,\n calculateYearsOfService,\n isDateInRange,\n getPayPeriodDateRange,\n formatDateForDB,\n parseDBDate,\n formatPeriod,\n parsePeriod,\n getMonthName,\n getShortMonthName,\n};\n\n","/**\n * @classytic/payroll - Enums\n *\n * Type-safe enum definitions with const assertions\n * Single source of truth for all enum values\n */\n\nimport type {\n EmploymentType,\n EmployeeStatus,\n Department,\n PaymentFrequency,\n PaymentMethod,\n AllowanceType,\n DeductionType,\n PayrollStatus,\n TerminationReason,\n SalaryBand,\n} from './types.js';\n\n// ============================================================================\n// Employment Type\n// ============================================================================\n\nexport const EMPLOYMENT_TYPE = {\n FULL_TIME: 'full_time',\n PART_TIME: 'part_time',\n CONTRACT: 'contract',\n INTERN: 'intern',\n CONSULTANT: 'consultant',\n} as const satisfies Record<string, EmploymentType>;\n\nexport const EMPLOYMENT_TYPE_VALUES = Object.values(EMPLOYMENT_TYPE);\n\nexport function isValidEmploymentType(value: string): value is EmploymentType {\n return EMPLOYMENT_TYPE_VALUES.includes(value as EmploymentType);\n}\n\n// ============================================================================\n// Employee Status\n// ============================================================================\n\nexport const EMPLOYEE_STATUS = {\n ACTIVE: 'active',\n ON_LEAVE: 'on_leave',\n SUSPENDED: 'suspended',\n TERMINATED: 'terminated',\n} as const satisfies Record<string, EmployeeStatus>;\n\nexport const EMPLOYEE_STATUS_VALUES = Object.values(EMPLOYEE_STATUS);\n\nexport function isValidEmployeeStatus(value: string): value is EmployeeStatus {\n return EMPLOYEE_STATUS_VALUES.includes(value as EmployeeStatus);\n}\n\nexport function isActiveStatus(status: EmployeeStatus): boolean {\n return status === EMPLOYEE_STATUS.ACTIVE;\n}\n\nexport function isEmployedStatus(status: EmployeeStatus): boolean {\n return status !== EMPLOYEE_STATUS.TERMINATED;\n}\n\nexport function canReceiveSalaryStatus(status: EmployeeStatus): boolean {\n return status === EMPLOYEE_STATUS.ACTIVE || status === EMPLOYEE_STATUS.ON_LEAVE;\n}\n\n// ============================================================================\n// Department\n// ============================================================================\n\nexport const DEPARTMENT = {\n MANAGEMENT: 'management',\n TRAINING: 'training',\n SALES: 'sales',\n OPERATIONS: 'operations',\n SUPPORT: 'support',\n HR: 'hr',\n MAINTENANCE: 'maintenance',\n MARKETING: 'marketing',\n FINANCE: 'finance',\n IT: 'it',\n} as const satisfies Record<string, Department>;\n\nexport const DEPARTMENT_VALUES = Object.values(DEPARTMENT);\n\nexport function isValidDepartment(value: string): value is Department {\n return DEPARTMENT_VALUES.includes(value as Department);\n}\n\n// ============================================================================\n// Payment Frequency\n// ============================================================================\n\nexport const PAYMENT_FREQUENCY = {\n MONTHLY: 'monthly',\n BI_WEEKLY: 'bi_weekly',\n WEEKLY: 'weekly',\n HOURLY: 'hourly',\n DAILY: 'daily',\n} as const satisfies Record<string, PaymentFrequency>;\n\nexport const PAYMENT_FREQUENCY_VALUES = Object.values(PAYMENT_FREQUENCY);\n\nexport function isValidPaymentFrequency(value: string): value is PaymentFrequency {\n return PAYMENT_FREQUENCY_VALUES.includes(value as PaymentFrequency);\n}\n\n// ============================================================================\n// Payment Method\n// ============================================================================\n\nexport const PAYMENT_METHOD = {\n BANK: 'bank',\n CASH: 'cash',\n MOBILE: 'mobile',\n BKASH: 'bkash',\n NAGAD: 'nagad',\n ROCKET: 'rocket',\n CHECK: 'check',\n} as const satisfies Record<string, PaymentMethod>;\n\nexport const PAYMENT_METHOD_VALUES = Object.values(PAYMENT_METHOD);\n\nexport function isValidPaymentMethod(value: string): value is PaymentMethod {\n return PAYMENT_METHOD_VALUES.includes(value as PaymentMethod);\n}\n\n// ============================================================================\n// Allowance Type\n// ============================================================================\n\nexport const ALLOWANCE_TYPE = {\n HOUSING: 'housing',\n TRANSPORT: 'transport',\n MEAL: 'meal',\n MOBILE: 'mobile',\n MEDICAL: 'medical',\n EDUCATION: 'education',\n BONUS: 'bonus',\n OTHER: 'other',\n} as const satisfies Record<string, AllowanceType>;\n\nexport const ALLOWANCE_TYPE_VALUES = Object.values(ALLOWANCE_TYPE);\n\nexport function isValidAllowanceType(value: string): value is AllowanceType {\n return ALLOWANCE_TYPE_VALUES.includes(value as AllowanceType);\n}\n\n// ============================================================================\n// Deduction Type\n// ============================================================================\n\nexport const DEDUCTION_TYPE = {\n TAX: 'tax',\n LOAN: 'loan',\n ADVANCE: 'advance',\n PROVIDENT_FUND: 'provident_fund',\n INSURANCE: 'insurance',\n ABSENCE: 'absence',\n OTHER: 'other',\n} as const satisfies Record<string, DeductionType>;\n\nexport const DEDUCTION_TYPE_VALUES = Object.values(DEDUCTION_TYPE);\n\nexport function isValidDeductionType(value: string): value is DeductionType {\n return DEDUCTION_TYPE_VALUES.includes(value as DeductionType);\n}\n\n// ============================================================================\n// Payroll Status\n// ============================================================================\n\nexport const PAYROLL_STATUS = {\n PENDING: 'pending',\n PROCESSING: 'processing',\n PAID: 'paid',\n FAILED: 'failed',\n CANCELLED: 'cancelled',\n} as const satisfies Record<string, PayrollStatus>;\n\nexport const PAYROLL_STATUS_VALUES = Object.values(PAYROLL_STATUS);\n\nexport function isValidPayrollStatus(value: string): value is PayrollStatus {\n return PAYROLL_STATUS_VALUES.includes(value as PayrollStatus);\n}\n\nexport function isCompletedPayrollStatus(status: PayrollStatus): boolean {\n return status === PAYROLL_STATUS.PAID;\n}\n\nexport function isPendingPayrollStatus(status: PayrollStatus): boolean {\n return status === PAYROLL_STATUS.PENDING || status === PAYROLL_STATUS.PROCESSING;\n}\n\n// ============================================================================\n// Termination Reason\n// ============================================================================\n\nexport const TERMINATION_REASON = {\n RESIGNATION: 'resignation',\n RETIREMENT: 'retirement',\n TERMINATION: 'termination',\n CONTRACT_END: 'contract_end',\n MUTUAL_AGREEMENT: 'mutual_agreement',\n OTHER: 'other',\n} as const satisfies Record<string, TerminationReason>;\n\nexport const TERMINATION_REASON_VALUES = Object.values(TERMINATION_REASON);\n\nexport function isValidTerminationReason(value: string): value is TerminationReason {\n return TERMINATION_REASON_VALUES.includes(value as TerminationReason);\n}\n\n// ============================================================================\n// Salary Band\n// ============================================================================\n\nexport const SALARY_BAND = {\n INTERN: 'intern',\n JUNIOR: 'junior',\n MID: 'mid',\n SENIOR: 'senior',\n LEAD: 'lead',\n EXECUTIVE: 'executive',\n CUSTOM: 'custom',\n} as const satisfies Record<string, SalaryBand>;\n\nexport const SALARY_BAND_VALUES = Object.values(SALARY_BAND);\n\nexport function isValidSalaryBand(value: string): value is SalaryBand {\n return SALARY_BAND_VALUES.includes(value as SalaryBand);\n}\n\n// ============================================================================\n// Leave Type\n// ============================================================================\n\nimport type { LeaveType, LeaveRequestStatus } from './types.js';\n\nexport const LEAVE_TYPE = {\n ANNUAL: 'annual',\n SICK: 'sick',\n UNPAID: 'unpaid',\n MATERNITY: 'maternity',\n PATERNITY: 'paternity',\n BEREAVEMENT: 'bereavement',\n COMPENSATORY: 'compensatory',\n OTHER: 'other',\n} as const satisfies Record<string, LeaveType>;\n\nexport const LEAVE_TYPE_VALUES = Object.values(LEAVE_TYPE);\n\nexport function isValidLeaveType(value: string): value is LeaveType {\n return LEAVE_TYPE_VALUES.includes(value as LeaveType);\n}\n\nexport function isPaidLeaveType(type: LeaveType): boolean {\n return type !== LEAVE_TYPE.UNPAID;\n}\n\n// ============================================================================\n// Leave Request Status\n// ============================================================================\n\nexport const LEAVE_REQUEST_STATUS = {\n PENDING: 'pending',\n APPROVED: 'approved',\n REJECTED: 'rejected',\n CANCELLED: 'cancelled',\n} as const satisfies Record<string, LeaveRequestStatus>;\n\nexport const LEAVE_REQUEST_STATUS_VALUES = Object.values(LEAVE_REQUEST_STATUS);\n\nexport function isValidLeaveRequestStatus(value: string): value is LeaveRequestStatus {\n return LEAVE_REQUEST_STATUS_VALUES.includes(value as LeaveRequestStatus);\n}\n\nexport function isPendingLeaveStatus(status: LeaveRequestStatus): boolean {\n return status === LEAVE_REQUEST_STATUS.PENDING;\n}\n\nexport function isApprovedLeaveStatus(status: LeaveRequestStatus): boolean {\n return status === LEAVE_REQUEST_STATUS.APPROVED;\n}\n\n// ============================================================================\n// Tax Type\n// ============================================================================\n\nexport const TAX_TYPE = {\n INCOME_TAX: 'income_tax',\n SOCIAL_SECURITY: 'social_security',\n HEALTH_INSURANCE: 'health_insurance',\n PENSION: 'pension',\n EMPLOYMENT_INSURANCE: 'employment_insurance',\n LOCAL_TAX: 'local_tax',\n OTHER: 'other',\n} as const satisfies Record<string, import('./types.js').TaxType>;\n\nexport const TAX_TYPE_VALUES = Object.values(TAX_TYPE);\n\nexport function isValidTaxType(value: string): value is import('./types.js').TaxType {\n return TAX_TYPE_VALUES.includes(value as import('./types.js').TaxType);\n}\n\n// ============================================================================\n// Tax Status\n// ============================================================================\n\nexport const TAX_STATUS = {\n PENDING: 'pending',\n SUBMITTED: 'submitted',\n PAID: 'paid',\n} as const satisfies Record<string, import('./types.js').TaxStatus>;\n\nexport const TAX_STATUS_VALUES = Object.values(TAX_STATUS);\n\nexport function isValidTaxStatus(value: string): value is import('./types.js').TaxStatus {\n return TAX_STATUS_VALUES.includes(value as import('./types.js').TaxStatus);\n}\n\nexport function isPendingTaxStatus(status: import('./types.js').TaxStatus): boolean {\n return status === TAX_STATUS.PENDING;\n}\n\nexport function isPaidTaxStatus(status: import('./types.js').TaxStatus): boolean {\n return status === TAX_STATUS.PAID;\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n EMPLOYMENT_TYPE,\n EMPLOYMENT_TYPE_VALUES,\n EMPLOYEE_STATUS,\n EMPLOYEE_STATUS_VALUES,\n DEPARTMENT,\n DEPARTMENT_VALUES,\n PAYMENT_FREQUENCY,\n PAYMENT_FREQUENCY_VALUES,\n PAYMENT_METHOD,\n PAYMENT_METHOD_VALUES,\n ALLOWANCE_TYPE,\n ALLOWANCE_TYPE_VALUES,\n DEDUCTION_TYPE,\n DEDUCTION_TYPE_VALUES,\n PAYROLL_STATUS,\n PAYROLL_STATUS_VALUES,\n TERMINATION_REASON,\n TERMINATION_REASON_VALUES,\n SALARY_BAND,\n SALARY_BAND_VALUES,\n LEAVE_TYPE,\n LEAVE_TYPE_VALUES,\n LEAVE_REQUEST_STATUS,\n LEAVE_REQUEST_STATUS_VALUES,\n TAX_TYPE,\n TAX_TYPE_VALUES,\n TAX_STATUS,\n TAX_STATUS_VALUES,\n};\n","/**\n * @classytic/payroll - Validation Utilities\n *\n * Fluent, composable, type-safe validation\n * Clear semantics and helpful error messages\n */\n\nimport type {\n EmployeeStatus,\n EmploymentType,\n Compensation,\n BankDetails,\n EmployeeValidationResult,\n} from '../types.js';\nimport {\n EMPLOYEE_STATUS_VALUES,\n EMPLOYMENT_TYPE_VALUES,\n} from '../enums.js';\nimport { diffInMonths } from './date.js';\n\n// ============================================================================\n// Employee Status Validators\n// ============================================================================\n\n/**\n * Check if employee is active\n */\nexport function isActive(employee: { status?: EmployeeStatus }): boolean {\n return employee?.status === 'active';\n}\n\n/**\n * Check if employee is on leave\n */\nexport function isOnLeave(employee: { status?: EmployeeStatus }): boolean {\n return employee?.status === 'on_leave';\n}\n\n/**\n * Check if employee is suspended\n */\nexport function isSuspended(employee: { status?: EmployeeStatus }): boolean {\n return employee?.status === 'suspended';\n}\n\n/**\n * Check if employee is terminated\n */\nexport function isTerminated(employee: { status?: EmployeeStatus }): boolean {\n return employee?.status === 'terminated';\n}\n\n/**\n * Check if employee is employed (not terminated)\n */\nexport function isEmployed(employee: { status?: EmployeeStatus }): boolean {\n return (\n isActive(employee) || isOnLeave(employee) || isSuspended(employee)\n );\n}\n\n/**\n * Check if employee can receive salary\n */\nexport function canReceiveSalary(employee: {\n status?: EmployeeStatus;\n compensation?: { baseAmount?: number };\n}): boolean {\n return (\n (isActive(employee) || isOnLeave(employee)) &&\n (employee.compensation?.baseAmount ?? 0) > 0\n );\n}\n\n/**\n * Check if employment can be updated\n */\nexport function canUpdateEmployment(employee: { status?: EmployeeStatus }): boolean {\n return !isTerminated(employee);\n}\n\n// ============================================================================\n// Compensation Validators\n// ============================================================================\n\n/**\n * Check if employee has valid compensation\n */\nexport function hasCompensation(employee: {\n compensation?: { baseAmount?: number };\n}): boolean {\n return (employee.compensation?.baseAmount ?? 0) > 0;\n}\n\n/**\n * Check if compensation is valid\n */\nexport function isValidCompensation(compensation?: Compensation): boolean {\n return !!(\n compensation?.baseAmount &&\n compensation.baseAmount > 0 &&\n compensation.frequency &&\n compensation.currency\n );\n}\n\n/**\n * Check if bank details are valid\n */\nexport function isValidBankDetails(bankDetails?: BankDetails): boolean {\n return !!(\n bankDetails?.accountNumber &&\n bankDetails.bankName &&\n bankDetails.accountName\n );\n}\n\n// ============================================================================\n// Probation Validators\n// ============================================================================\n\n/**\n * Check if employee is in probation\n */\nexport function isInProbation(\n employee: { probationEndDate?: Date | null },\n now = new Date()\n): boolean {\n if (!employee?.probationEndDate) return false;\n return new Date(employee.probationEndDate) > now;\n}\n\n/**\n * Check if employee has completed probation\n */\nexport function hasCompletedProbation(\n employee: { probationEndDate?: Date | null },\n now = new Date()\n): boolean {\n if (!employee?.probationEndDate) return true;\n return new Date(employee.probationEndDate) <= now;\n}\n\n// ============================================================================\n// Eligibility Validators\n// ============================================================================\n\n/**\n * Check if employee is eligible for bonus\n */\nexport function isEligibleForBonus(\n employee: { status?: EmployeeStatus; hireDate?: Date },\n requiredMonths = 6\n): boolean {\n if (!isActive(employee) || !employee.hireDate) return false;\n const monthsEmployed = diffInMonths(employee.hireDate, new Date());\n return monthsEmployed >= requiredMonths;\n}\n\n/**\n * Check if employee is eligible for payroll\n */\nexport function isEligibleForPayroll(employee: {\n status?: EmployeeStatus;\n compensation?: { baseAmount?: number };\n bankDetails?: BankDetails;\n}): { eligible: boolean; reasons: string[] } {\n const reasons: string[] = [];\n\n if (!isActive(employee) && !isOnLeave(employee)) {\n reasons.push('Employee is not in active or on-leave status');\n }\n\n if (!hasCompensation(employee)) {\n reasons.push('Employee has no valid compensation');\n }\n\n return {\n eligible: reasons.length === 0,\n reasons,\n };\n}\n\n// ============================================================================\n// Field Validators\n// ============================================================================\n\n/**\n * Check if value is required\n */\nexport function required(fieldName: string): (value: unknown) => string | true {\n return (value: unknown) =>\n value !== undefined && value !== null && value !== ''\n ? true\n : `${fieldName} is required`;\n}\n\n/**\n * Check minimum value\n */\nexport function min(\n minValue: number,\n fieldName: string\n): (value: number) => string | true {\n return (value: number) =>\n value >= minValue ? true : `${fieldName} must be at least ${minValue}`;\n}\n\n/**\n * Check maximum value\n */\nexport function max(\n maxValue: number,\n fieldName: string\n): (value: number) => string | true {\n return (value: number) =>\n value <= maxValue ? true : `${fieldName} must not exceed ${maxValue}`;\n}\n\n/**\n * Check value is in range\n */\nexport function inRange(\n minValue: number,\n maxValue: number,\n fieldName: string\n): (value: number) => string | true {\n return (value: number) =>\n value >= minValue && value <= maxValue\n ? true\n : `${fieldName} must be between ${minValue} and ${maxValue}`;\n}\n\n/**\n * Check value is positive\n */\nexport function isPositive(fieldName: string): (value: number) => string | true {\n return (value: number) =>\n value > 0 ? true : `${fieldName} must be positive`;\n}\n\n/**\n * Check value is one of allowed values\n */\nexport function oneOf<T extends string>(\n allowedValues: readonly T[],\n fieldName: string\n): (value: T) => string | true {\n return (value: T) =>\n allowedValues.includes(value)\n ? true\n : `${fieldName} must be one of: ${allowedValues.join(', ')}`;\n}\n\n// ============================================================================\n// Enum Validators\n// ============================================================================\n\n/**\n * Check if status is valid\n */\nexport function isValidStatus(value: string): value is EmployeeStatus {\n return EMPLOYEE_STATUS_VALUES.includes(value as EmployeeStatus);\n}\n\n/**\n * Check if employment type is valid\n */\nexport function isValidEmploymentType(value: string): value is EmploymentType {\n return EMPLOYMENT_TYPE_VALUES.includes(value as EmploymentType);\n}\n\n// ============================================================================\n// Composite Validators\n// ============================================================================\n\n/**\n * Compose multiple validators\n */\nexport function composeValidators<T>(\n ...validators: Array<(value: T, data?: unknown) => string | true>\n): (value: T, data?: unknown) => string | true {\n return (value: T, data?: unknown) => {\n for (const validator of validators) {\n const result = validator(value, data);\n if (result !== true) return result;\n }\n return true;\n };\n}\n\n/**\n * Create a validator from validation functions\n */\nexport function createValidator<T extends Record<string, unknown>>(\n validationFns: Record<string, (value: unknown, data: T) => string | true>\n): (data: T) => EmployeeValidationResult {\n return (data: T) => {\n const errors: string[] = [];\n\n for (const [field, validator] of Object.entries(validationFns)) {\n const result = validator((data as Record<string, unknown>)[field], data);\n if (result !== true) {\n errors.push(result);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n };\n}\n\n/**\n * Validate required fields exist\n */\nexport function hasRequiredFields(\n obj: Record<string, unknown>,\n fields: string[]\n): { valid: boolean; missing: string[] } {\n const missing = fields.filter(\n (field) => obj[field] === undefined || obj[field] === null\n );\n return {\n valid: missing.length === 0,\n missing,\n };\n}\n\n// ============================================================================\n// Aliases for backwards compatibility\n// ============================================================================\n\nexport const minValue = min;\nexport const maxValue = max;\nexport const isInRange = inRange;\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n // Status validators\n isActive,\n isOnLeave,\n isSuspended,\n isTerminated,\n isEmployed,\n canReceiveSalary,\n canUpdateEmployment,\n // Compensation validators\n hasCompensation,\n isValidCompensation,\n isValidBankDetails,\n // Probation validators\n isInProbation,\n hasCompletedProbation,\n // Eligibility validators\n isEligibleForBonus,\n isEligibleForPayroll,\n // Field validators\n required,\n min,\n max,\n inRange,\n isPositive,\n oneOf,\n // Enum validators\n isValidStatus,\n isValidEmploymentType,\n // Composite validators\n composeValidators,\n createValidator,\n hasRequiredFields,\n};\n\n","/**\n * @classytic/payroll - Calculation Utilities\n *\n * Pure, functional, composable financial calculations\n * No side effects, highly testable\n */\n\nimport type {\n Allowance,\n Deduction,\n Compensation,\n TaxCalculationResult,\n CompensationBreakdownResult,\n ProRatingResult,\n PayPeriodInfo,\n} from '../types.js';\nimport { diffInDays } from './date.js';\n\n// ============================================================================\n// Basic Math Operations\n// ============================================================================\n\n/**\n * Sum array of numbers\n */\nexport function sum(numbers: number[]): number {\n return numbers.reduce((total, n) => total + n, 0);\n}\n\n/**\n * Sum by property\n */\nexport function sumBy<T>(items: T[], getter: (item: T) => number): number {\n return items.reduce((total, item) => total + getter(item), 0);\n}\n\n/**\n * Sum allowances\n */\nexport function sumAllowances(allowances: Array<{ amount: number }>): number {\n return sumBy(allowances, (a) => a.amount);\n}\n\n/**\n * Sum deductions\n */\nexport function sumDeductions(deductions: Array<{ amount: number }>): number {\n return sumBy(deductions, (d) => d.amount);\n}\n\n/**\n * Apply percentage to amount\n */\nexport function applyPercentage(amount: number, percentage: number): number {\n return Math.round(amount * (percentage / 100));\n}\n\n/**\n * Calculate percentage of total\n */\nexport function calculatePercentage(part: number, total: number): number {\n return total > 0 ? Math.round((part / total) * 100) : 0;\n}\n\n/**\n * Round to decimal places\n */\nexport function roundTo(value: number, decimals = 2): number {\n const factor = Math.pow(10, decimals);\n return Math.round(value * factor) / factor;\n}\n\n// ============================================================================\n// Salary Calculations\n// ============================================================================\n\n/**\n * Calculate gross salary from base and allowances\n */\nexport function calculateGross(\n baseAmount: number,\n allowances: Array<{ amount: number }>\n): number {\n return baseAmount + sumAllowances(allowances);\n}\n\n/**\n * Calculate net salary from gross and deductions\n */\nexport function calculateNet(\n gross: number,\n deductions: Array<{ amount: number }>\n): number {\n return Math.max(0, gross - sumDeductions(deductions));\n}\n\n/**\n * Calculate total compensation\n */\nexport function calculateTotalCompensation(\n baseAmount: number,\n allowances: Array<{ amount: number }>,\n deductions: Array<{ amount: number }>\n): { gross: number; net: number; deductions: number } {\n const gross = calculateGross(baseAmount, allowances);\n const totalDeductions = sumDeductions(deductions);\n const net = calculateNet(gross, deductions);\n return { gross, net, deductions: totalDeductions };\n}\n\n// ============================================================================\n// Allowance & Deduction Calculation\n// ============================================================================\n\n/**\n * Calculate allowance amount (handles percentage-based)\n */\nexport function calculateAllowanceAmount(\n allowance: Pick<Allowance, 'amount' | 'isPercentage' | 'value'>,\n baseAmount: number\n): number {\n if (allowance.isPercentage && allowance.value !== undefined) {\n return applyPercentage(baseAmount, allowance.value);\n }\n return allowance.amount;\n}\n\n/**\n * Calculate deduction amount (handles percentage-based)\n */\nexport function calculateDeductionAmount(\n deduction: Pick<Deduction, 'amount' | 'isPercentage' | 'value'>,\n baseAmount: number\n): number {\n if (deduction.isPercentage && deduction.value !== undefined) {\n return applyPercentage(baseAmount, deduction.value);\n }\n return deduction.amount;\n}\n\n/**\n * Calculate all allowances with their actual amounts\n */\nexport function calculateAllowances(\n allowances: Allowance[],\n baseAmount: number\n): Array<Allowance & { calculatedAmount: number }> {\n return allowances.map((allowance) => ({\n ...allowance,\n calculatedAmount: calculateAllowanceAmount(allowance, baseAmount),\n }));\n}\n\n/**\n * Calculate all deductions with their actual amounts\n */\nexport function calculateDeductions(\n deductions: Deduction[],\n baseAmount: number\n): Array<Deduction & { calculatedAmount: number }> {\n return deductions.map((deduction) => ({\n ...deduction,\n calculatedAmount: calculateDeductionAmount(deduction, baseAmount),\n }));\n}\n\n// ============================================================================\n// Compensation Breakdown\n// ============================================================================\n\n/**\n * Calculate full compensation breakdown\n */\nexport function calculateCompensationBreakdown(\n compensation: Pick<Compensation, 'baseAmount' | 'allowances' | 'deductions'>\n): CompensationBreakdownResult {\n const { baseAmount, allowances = [], deductions = [] } = compensation;\n\n const calculatedAllowances = calculateAllowances(allowances, baseAmount);\n const calculatedDeductions = calculateDeductions(deductions, baseAmount);\n\n const grossAmount =\n baseAmount + sumBy(calculatedAllowances, (a) => a.calculatedAmount);\n const netAmount =\n grossAmount - sumBy(calculatedDeductions, (d) => d.calculatedAmount);\n\n return {\n baseAmount,\n allowances: calculatedAllowances,\n deductions: calculatedDeductions,\n grossAmount,\n netAmount: Math.max(0, netAmount),\n };\n}\n\n// ============================================================================\n// Pro-Rating Calculations\n// ============================================================================\n\n/**\n * Calculate pro-rating for mid-month hires\n */\nexport function calculateProRating(\n hireDate: Date,\n periodStart: Date,\n periodEnd: Date\n): ProRatingResult {\n const totalDays = diffInDays(periodStart, periodEnd) + 1;\n\n // Hired before period start - no pro-rating\n if (hireDate <= periodStart) {\n return {\n isProRated: false,\n totalDays,\n actualDays: totalDays,\n ratio: 1,\n };\n }\n\n // Hired during the period - pro-rate\n if (hireDate > periodStart && hireDate <= periodEnd) {\n const actualDays = diffInDays(hireDate, periodEnd) + 1;\n const ratio = actualDays / totalDays;\n\n return {\n isProRated: true,\n totalDays,\n actualDays,\n ratio,\n };\n }\n\n // Hired after period - no work days\n return {\n isProRated: false,\n totalDays,\n actualDays: 0,\n ratio: 0,\n };\n}\n\n/**\n * Apply pro-rating to an amount\n */\nexport function applyProRating(\n amount: number,\n proRating: ProRatingResult\n): number {\n return Math.round(amount * proRating.ratio);\n}\n\n/**\n * Calculate pro-rated salary\n */\nexport function calculateProRatedSalary(\n baseAmount: number,\n hireDate: Date,\n period: PayPeriodInfo\n): { amount: number; proRating: ProRatingResult } {\n const proRating = calculateProRating(hireDate, period.startDate, period.endDate);\n const amount = applyProRating(baseAmount, proRating);\n return { amount, proRating };\n}\n\n// ============================================================================\n// Tax Calculations\n// ============================================================================\n\n/**\n * Apply tax brackets to calculate tax\n */\nexport function applyTaxBrackets(\n amount: number,\n brackets: Array<{ min: number; max: number; rate: number }>\n): number {\n let tax = 0;\n\n for (const bracket of brackets) {\n if (amount > bracket.min) {\n const taxableAmount = Math.min(amount, bracket.max) - bracket.min;\n tax += taxableAmount * bracket.rate;\n }\n }\n\n return Math.round(tax);\n}\n\n/**\n * Calculate tax with result\n */\nexport function calculateTax(\n amount: number,\n brackets: Array<{ min: number; max: number; rate: number }>\n): TaxCalculationResult {\n const tax = applyTaxBrackets(amount, brackets);\n return {\n gross: amount,\n tax,\n net: amount - tax,\n };\n}\n\n// ============================================================================\n// Functional Composition\n// ============================================================================\n\n/**\n * Pipe functions left-to-right\n * pipe(f, g, h)(x) === h(g(f(x)))\n */\nexport function pipe<T>(...fns: Array<(value: T) => T>): (value: T) => T {\n return (value: T) => fns.reduce((acc, fn) => fn(acc), value);\n}\n\n/**\n * Compose functions right-to-left\n * compose(f, g, h)(x) === f(g(h(x)))\n */\nexport function compose<T>(...fns: Array<(value: T) => T>): (value: T) => T {\n return (value: T) => fns.reduceRight((acc, fn) => fn(acc), value);\n}\n\n/**\n * Create an allowance calculator factory\n */\nexport function createAllowanceCalculator(\n allowances: Allowance[]\n): (baseSalary: number) => Array<Allowance & { calculatedAmount: number }> {\n return (baseSalary: number) => calculateAllowances(allowances, baseSalary);\n}\n\n/**\n * Create a deduction calculator factory\n */\nexport function createDeductionCalculator(\n deductions: Deduction[]\n): (baseSalary: number) => Array<Deduction & { calculatedAmount: number }> {\n return (baseSalary: number) => calculateDeductions(deductions, baseSalary);\n}\n\n// ============================================================================\n// Overtime Calculations\n// ============================================================================\n\n/**\n * Calculate overtime pay\n */\nexport function calculateOvertime(\n hourlyRate: number,\n overtimeHours: number,\n multiplier = 1.5\n): number {\n return Math.round(hourlyRate * overtimeHours * multiplier);\n}\n\n/**\n * Calculate hourly rate from monthly salary\n */\nexport function calculateHourlyRate(\n monthlySalary: number,\n hoursPerMonth = 176 // 44 hours/week * 4 weeks\n): number {\n return Math.round(monthlySalary / hoursPerMonth);\n}\n\n/**\n * Calculate daily rate from monthly salary\n */\nexport function calculateDailyRate(\n monthlySalary: number,\n daysPerMonth = 22\n): number {\n return Math.round(monthlySalary / daysPerMonth);\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n sum,\n sumBy,\n sumAllowances,\n sumDeductions,\n applyPercentage,\n calculatePercentage,\n roundTo,\n calculateGross,\n calculateNet,\n calculateTotalCompensation,\n calculateAllowanceAmount,\n calculateDeductionAmount,\n calculateAllowances,\n calculateDeductions,\n calculateCompensationBreakdown,\n calculateProRating,\n applyProRating,\n calculateProRatedSalary,\n applyTaxBrackets,\n calculateTax,\n pipe,\n compose,\n createAllowanceCalculator,\n createDeductionCalculator,\n calculateOvertime,\n calculateHourlyRate,\n calculateDailyRate,\n};\n\n","/**\n * @classytic/payroll - Leave Utilities\n *\n * Pure, composable leave calculation functions\n */\n\nimport type {\n LeaveBalance,\n LeaveType,\n LeaveInitConfig,\n LeaveSummaryResult,\n WorkingDaysOptions,\n} from '../types.js';\n\n// ============================================================================\n// Default Configurations\n// ============================================================================\n\n/** Default leave allocations by type (days per year) */\nexport const DEFAULT_LEAVE_ALLOCATIONS: Record<LeaveType, number> = {\n annual: 20,\n sick: 10,\n unpaid: 0, // Unlimited\n maternity: 90,\n paternity: 10,\n bereavement: 5,\n compensatory: 0,\n other: 0,\n};\n\n/** Default carry-over limits by type (days) */\nexport const DEFAULT_CARRY_OVER: Record<LeaveType, number> = {\n annual: 5,\n sick: 0,\n unpaid: 0,\n maternity: 0,\n paternity: 0,\n bereavement: 0,\n compensatory: 5,\n other: 0,\n};\n\n// ============================================================================\n// Working Days Calculation\n// ============================================================================\n\n/**\n * Calculate working days between two dates\n * Excludes weekends and optionally holidays\n *\n * @example\n * // March 2024: Get working days for a week\n * const days = calculateLeaveDays(\n * new Date('2024-03-01'),\n * new Date('2024-03-08'),\n * { holidays: [new Date('2024-03-05')] }\n * );\n */\nexport function calculateLeaveDays(\n startDate: Date,\n endDate: Date,\n options: WorkingDaysOptions = {}\n): number {\n const {\n workingDays = [1, 2, 3, 4, 5], // Mon-Fri by default\n holidays = [],\n includeEndDate = true,\n } = options;\n\n const holidaySet = new Set(holidays.map((d) => new Date(d).toDateString()));\n\n let count = 0;\n const current = new Date(startDate);\n current.setHours(0, 0, 0, 0);\n\n const end = new Date(endDate);\n end.setHours(0, 0, 0, 0);\n\n if (!includeEndDate) {\n end.setDate(end.getDate() - 1);\n }\n\n while (current <= end) {\n const isWorkDay = workingDays.includes(current.getDay());\n const isHoliday = holidaySet.has(current.toDateString());\n\n if (isWorkDay && !isHoliday) {\n count++;\n }\n\n current.setDate(current.getDate() + 1);\n }\n\n return count;\n}\n\n// ============================================================================\n// Balance Checks\n// ============================================================================\n\n/**\n * Check if employee has sufficient leave balance\n *\n * @example\n * if (hasLeaveBalance(employee, 'annual', 5)) {\n * // Can request 5 days annual leave\n * }\n */\nexport function hasLeaveBalance(\n employee: { leaveBalances?: LeaveBalance[] },\n type: LeaveType,\n days: number,\n year = new Date().getFullYear()\n): boolean {\n // Unpaid leave is always allowed\n if (type === 'unpaid') return true;\n\n const balance = getLeaveBalance(employee, type, year);\n if (!balance) return false;\n\n const available =\n balance.allocated + balance.carriedOver - balance.used - balance.pending;\n return available >= days;\n}\n\n/**\n * Get leave balance for a specific type\n */\nexport function getLeaveBalance(\n employee: { leaveBalances?: LeaveBalance[] },\n type: LeaveType,\n year = new Date().getFullYear()\n): LeaveBalance | undefined {\n return employee.leaveBalances?.find((b) => b.type === type && b.year === year);\n}\n\n/**\n * Get all leave balances for a year\n */\nexport function getLeaveBalances(\n employee: { leaveBalances?: LeaveBalance[] },\n year = new Date().getFullYear()\n): LeaveBalance[] {\n return (employee.leaveBalances || []).filter((b) => b.year === year);\n}\n\n/**\n * Calculate available days for a leave type\n */\nexport function getAvailableDays(\n employee: { leaveBalances?: LeaveBalance[] },\n type: LeaveType,\n year = new Date().getFullYear()\n): number {\n // Unpaid leave has no limit\n if (type === 'unpaid') return Infinity;\n\n const balance = getLeaveBalance(employee, type, year);\n if (!balance) return 0;\n\n return Math.max(\n 0,\n balance.allocated + balance.carriedOver - balance.used - balance.pending\n );\n}\n\n// ============================================================================\n// Leave Summary\n// ============================================================================\n\n/**\n * Get comprehensive leave summary for an employee\n *\n * @example\n * const summary = getLeaveSummary(employee, 2024);\n * console.log(`Available: ${summary.totalAvailable} days`);\n * console.log(`Annual: ${summary.byType.annual?.available || 0} days`);\n */\nexport function getLeaveSummary(\n employee: { leaveBalances?: LeaveBalance[] },\n year = new Date().getFullYear()\n): LeaveSummaryResult {\n const balances = getLeaveBalances(employee, year);\n\n const byType = {} as LeaveSummaryResult['byType'];\n let totalAllocated = 0;\n let totalUsed = 0;\n let totalPending = 0;\n\n for (const balance of balances) {\n const available = Math.max(\n 0,\n balance.allocated + balance.carriedOver - balance.used - balance.pending\n );\n byType[balance.type] = {\n allocated: balance.allocated + balance.carriedOver,\n used: balance.used,\n pending: balance.pending,\n available,\n };\n totalAllocated += balance.allocated + balance.carriedOver;\n totalUsed += balance.used;\n totalPending += balance.pending;\n }\n\n return {\n year,\n balances,\n totalAllocated,\n totalUsed,\n totalPending,\n totalAvailable: Math.max(0, totalAllocated - totalUsed - totalPending),\n byType,\n };\n}\n\n// ============================================================================\n// Balance Initialization\n// ============================================================================\n\n/**\n * Initialize leave balances for a new employee\n *\n * @example\n * // Full allocation for employee hired Jan 1st\n * const balances = initializeLeaveBalances(new Date('2024-01-01'));\n *\n * // Pro-rated for mid-year hire\n * const balances = initializeLeaveBalances(new Date('2024-07-01'), {\n * proRateNewHires: true,\n * });\n */\nexport function initializeLeaveBalances(\n hireDate: Date,\n config: LeaveInitConfig = {},\n year = new Date().getFullYear()\n): LeaveBalance[] {\n const {\n defaultAllocations = DEFAULT_LEAVE_ALLOCATIONS,\n proRateNewHires = true,\n fiscalYearStartMonth = 1,\n } = config;\n\n const fiscalYearStart = new Date(year, fiscalYearStartMonth - 1, 1);\n const fiscalYearEnd = new Date(year + 1, fiscalYearStartMonth - 1, 0);\n\n // Calculate proration if hired mid-year\n let prorationRatio = 1;\n if (proRateNewHires && hireDate > fiscalYearStart) {\n const totalDays = diffInDays(fiscalYearStart, fiscalYearEnd);\n const remainingDays = diffInDays(hireDate, fiscalYearEnd);\n prorationRatio = Math.max(0, Math.min(1, remainingDays / totalDays));\n }\n\n const balances: LeaveBalance[] = [];\n\n for (const [type, allocation] of Object.entries(defaultAllocations)) {\n if (allocation > 0) {\n balances.push({\n type: type as LeaveType,\n allocated: Math.round(allocation * prorationRatio),\n used: 0,\n pending: 0,\n carriedOver: 0,\n year,\n });\n }\n }\n\n return balances;\n}\n\n/**\n * Calculate prorated allocation for mid-year hire\n */\nexport function proRateAllocation(\n fullAllocation: number,\n hireDate: Date,\n fiscalYearStartMonth = 1,\n year = new Date().getFullYear()\n): number {\n const fiscalYearStart = new Date(year, fiscalYearStartMonth - 1, 1);\n\n if (hireDate <= fiscalYearStart) {\n return fullAllocation;\n }\n\n const fiscalYearEnd = new Date(year + 1, fiscalYearStartMonth - 1, 0);\n const totalDays = diffInDays(fiscalYearStart, fiscalYearEnd);\n const remainingDays = Math.max(0, diffInDays(hireDate, fiscalYearEnd));\n\n return Math.round((fullAllocation * remainingDays) / totalDays);\n}\n\n// ============================================================================\n// Payroll Integration\n// ============================================================================\n\n/**\n * Calculate unpaid leave deduction for payroll\n *\n * @example\n * const deduction = calculateUnpaidLeaveDeduction(100000, 5, 22);\n * // Daily rate: 100000 / 22 = 4545\n * // Deduction: 4545 * 5 = 22727\n */\nexport function calculateUnpaidLeaveDeduction(\n baseSalary: number,\n unpaidDays: number,\n workingDaysInMonth: number\n): number {\n if (unpaidDays <= 0 || workingDaysInMonth <= 0) return 0;\n\n const dailyRate = baseSalary / workingDaysInMonth;\n return Math.round(dailyRate * unpaidDays);\n}\n\n/**\n * Get total unpaid leave days from a list of leave requests\n */\nexport function getUnpaidLeaveDays(\n leaveRequests: Array<{ type: LeaveType; days: number; status: string }>,\n status = 'approved'\n): number {\n return leaveRequests\n .filter((r) => r.type === 'unpaid' && r.status === status)\n .reduce((sum, r) => sum + r.days, 0);\n}\n\n// ============================================================================\n// Year-End Processing\n// ============================================================================\n\n/**\n * Calculate carry-over balances for year-end\n *\n * Creates new year balances for ALL leave types from the current year.\n * Types with carry-over limits get their unused balance carried forward.\n * Types without carry-over (or 0 limit) start fresh with 0 carriedOver.\n *\n * @example\n * // With default allocations - creates balances for all types\n * const newBalances = calculateCarryOver(employee.leaveBalances, {\n * annual: 5,\n * compensatory: 3,\n * });\n * // Merge with existing (don't replace entirely)\n * employee.leaveBalances.push(...newBalances);\n *\n * // With custom allocations (org-specific entitlements)\n * const newBalances = calculateCarryOver(employee.leaveBalances, {\n * annual: 5,\n * compensatory: 3,\n * }, {\n * annual: 25, // Custom org policy\n * sick: 15,\n * });\n */\nexport function calculateCarryOver(\n balances: LeaveBalance[],\n maxCarryOver: Partial<Record<LeaveType, number>> = DEFAULT_CARRY_OVER,\n newYearAllocations: Partial<Record<LeaveType, number>> = DEFAULT_LEAVE_ALLOCATIONS\n): LeaveBalance[] {\n if (!balances.length) return [];\n\n const currentYear = balances[0].year;\n const newYear = currentYear + 1;\n\n // Process ALL leave types from current year, not just those with carry-over\n return balances.map((balance) => {\n const available =\n balance.allocated + balance.carriedOver - balance.used - balance.pending;\n const maxForType = maxCarryOver[balance.type] ?? 0;\n // Only carry over if max > 0, otherwise start fresh\n const carryOver = maxForType > 0\n ? Math.min(Math.max(0, available), maxForType)\n : 0;\n\n return {\n type: balance.type,\n allocated: newYearAllocations[balance.type] ?? DEFAULT_LEAVE_ALLOCATIONS[balance.type] ?? 0,\n used: 0,\n pending: 0,\n carriedOver: carryOver,\n year: newYear,\n };\n });\n}\n\n/**\n * Add accrued leave to balances\n */\nexport function accrueLeaveToBalance(\n balances: LeaveBalance[],\n type: LeaveType,\n amount: number,\n year = new Date().getFullYear()\n): LeaveBalance[] {\n const existingIdx = balances.findIndex((b) => b.type === type && b.year === year);\n\n if (existingIdx >= 0) {\n balances[existingIdx].allocated += amount;\n } else {\n balances.push({\n type,\n allocated: amount,\n used: 0,\n pending: 0,\n carriedOver: 0,\n year,\n });\n }\n\n return balances;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Calculate difference in days between two dates\n */\nfunction diffInDays(start: Date, end: Date): number {\n const startDate = new Date(start);\n const endDate = new Date(end);\n startDate.setHours(0, 0, 0, 0);\n endDate.setHours(0, 0, 0, 0);\n return Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24));\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n DEFAULT_LEAVE_ALLOCATIONS,\n DEFAULT_CARRY_OVER,\n calculateLeaveDays,\n hasLeaveBalance,\n getLeaveBalance,\n getLeaveBalances,\n getAvailableDays,\n getLeaveSummary,\n initializeLeaveBalances,\n proRateAllocation,\n calculateUnpaidLeaveDeduction,\n getUnpaidLeaveDays,\n calculateCarryOver,\n accrueLeaveToBalance,\n};\n","/**\n * @classytic/payroll - Employee Identity Helper\n *\n * Dual identity system for employee lookups:\n * - MongoDB ObjectId (_id field)\n * - Business string identifier (employeeId field like \"EMP-001\")\n *\n * Auto-detects identifier type and builds appropriate queries\n */\n\nimport type { ObjectIdLike } from '../types.js';\nimport { Types } from 'mongoose';\nimport { isValidObjectId, toObjectId } from './query-builders.js';\n\n/**\n * Employee identifier type\n */\nexport type EmployeeIdType = 'objectId' | 'string';\n\n/**\n * Employee query filter\n */\nexport interface EmployeeQueryFilter {\n _id?: Types.ObjectId;\n employeeId?: string;\n organizationId: Types.ObjectId;\n}\n\n/**\n * Detect if employeeId is ObjectId or string\n *\n * @param employeeId - Employee identifier (ObjectId or string)\n * @returns 'objectId' if valid ObjectId, 'string' otherwise\n *\n * @example\n * detectEmployeeIdType(employee._id)\n * // Returns: 'objectId'\n *\n * @example\n * detectEmployeeIdType(\"EMP-001\")\n * // Returns: 'string'\n */\nexport function detectEmployeeIdType(\n employeeId: ObjectIdLike | string\n): EmployeeIdType {\n // Check if it's a valid ObjectId\n if (isValidObjectId(employeeId)) {\n return 'objectId';\n }\n\n // Otherwise treat as string business identifier\n return 'string';\n}\n\n/**\n * Build employee query based on identifier type\n *\n * Automatically detects if employeeId is ObjectId or string\n * and builds the appropriate MongoDB query filter.\n *\n * @param employeeId - Employee identifier (ObjectId or string)\n * @param organizationId - Organization ID for multi-tenant isolation\n * @returns Query filter for MongoDB\n *\n * @example\n * // By ObjectId _id\n * const query = buildEmployeeQuery(employee._id, org._id);\n * // Returns: { _id: ObjectId(...), organizationId: ObjectId(...) }\n *\n * @example\n * // By string employeeId\n * const query = buildEmployeeQuery(\"EMP-001\", org._id);\n * // Returns: { employeeId: \"EMP-001\", organizationId: ObjectId(...) }\n */\nexport function buildEmployeeQuery(\n employeeId: ObjectIdLike | string,\n organizationId: Types.ObjectId\n): EmployeeQueryFilter {\n const idType = detectEmployeeIdType(employeeId);\n\n if (idType === 'objectId') {\n return {\n _id: toObjectId(employeeId as ObjectIdLike),\n organizationId,\n };\n }\n\n // String business identifier\n return {\n employeeId: employeeId as string,\n organizationId,\n };\n}\n\n/**\n * Normalize employee identifier to consistent format\n *\n * Converts ObjectIdLike to ObjectId, keeps strings as-is\n *\n * @param employeeId - Employee identifier\n * @returns Normalized ObjectId or string\n */\nexport function normalizeEmployeeId(\n employeeId: ObjectIdLike | string\n): Types.ObjectId | string {\n const idType = detectEmployeeIdType(employeeId);\n\n if (idType === 'objectId') {\n return toObjectId(employeeId as ObjectIdLike);\n }\n\n return employeeId as string;\n}\n\n/**\n * Check if value is a string employee ID (not ObjectId)\n *\n * @param value - Value to check\n * @returns true if string employeeId, false if ObjectId\n */\nexport function isStringEmployeeId(value: unknown): value is string {\n return typeof value === 'string' && !isValidObjectId(value);\n}\n\n/**\n * Check if value is an ObjectId employee identifier\n *\n * @param value - Value to check\n * @returns true if ObjectId, false otherwise\n */\nexport function isObjectIdEmployeeId(value: unknown): value is ObjectIdLike {\n return isValidObjectId(value);\n}\n\n/**\n * Format employee identifier for display\n *\n * @param employeeId - Employee identifier\n * @returns Human-readable string\n *\n * @example\n * formatEmployeeId(employee._id)\n * // Returns: \"_id=507f1f77bcf86cd799439011\"\n *\n * @example\n * formatEmployeeId(\"EMP-001\")\n * // Returns: \"employeeId=EMP-001\"\n */\nexport function formatEmployeeId(employeeId: ObjectIdLike | string): string {\n const idType = detectEmployeeIdType(employeeId);\n\n if (idType === 'objectId') {\n return `_id=${toObjectId(employeeId as ObjectIdLike).toString()}`;\n }\n\n return `employeeId=${employeeId}`;\n}\n","/**\n * @classytic/payroll - Utilities\n *\n * Pure, testable utility functions\n */\n\n// ============================================================================\n// Logger\n// ============================================================================\n\nexport {\n logger,\n getLogger,\n setLogger,\n resetLogger,\n createChildLogger,\n createSilentLogger,\n enableLogging,\n disableLogging,\n isLoggingEnabled,\n} from './logger.js';\n\n// ============================================================================\n// Date Utilities\n// ============================================================================\n\nexport {\n addDays,\n addMonths,\n addYears,\n subDays,\n subMonths,\n startOfMonth,\n endOfMonth,\n startOfYear,\n endOfYear,\n startOfDay,\n endOfDay,\n diffInDays,\n diffInMonths,\n diffInYears,\n daysBetween,\n monthsBetween,\n isWeekday,\n isWeekend,\n getDayOfWeek,\n getDayName,\n getPayPeriod,\n getCurrentPeriod,\n getWorkingDaysInMonth,\n getDaysInMonth,\n calculateProbationEnd,\n isOnProbation,\n calculateYearsOfService,\n isDateInRange,\n getPayPeriodDateRange,\n formatDateForDB,\n parseDBDate,\n formatPeriod,\n parsePeriod,\n getMonthName,\n getShortMonthName,\n default as dateUtils,\n} from './date.js';\n\n// ============================================================================\n// Calculation Utilities\n// ============================================================================\n\nexport {\n sum,\n sumBy,\n sumAllowances,\n sumDeductions,\n applyPercentage,\n calculatePercentage,\n roundTo,\n calculateGross,\n calculateNet,\n calculateTotalCompensation,\n calculateAllowanceAmount,\n calculateDeductionAmount,\n calculateAllowances,\n calculateDeductions,\n calculateCompensationBreakdown,\n calculateProRating,\n applyProRating,\n calculateProRatedSalary,\n applyTaxBrackets,\n calculateTax,\n pipe,\n compose,\n createAllowanceCalculator,\n createDeductionCalculator,\n calculateOvertime,\n calculateHourlyRate,\n calculateDailyRate,\n default as calculationUtils,\n} from './calculation.js';\n\n// ============================================================================\n// Validation Utilities\n// ============================================================================\n\nexport {\n isActive,\n isOnLeave,\n isSuspended,\n isTerminated,\n isEmployed,\n canReceiveSalary,\n canUpdateEmployment,\n hasCompensation,\n isValidCompensation,\n isValidBankDetails,\n isInProbation,\n hasCompletedProbation,\n isEligibleForBonus,\n isEligibleForPayroll,\n required,\n min,\n max,\n inRange,\n isPositive,\n oneOf,\n isValidStatus,\n isValidEmploymentType,\n composeValidators,\n createValidator,\n hasRequiredFields,\n minValue,\n maxValue,\n isInRange,\n default as validationUtils,\n} from './validation.js';\n\n// ============================================================================\n// Query Builders\n// ============================================================================\n\nexport {\n toObjectId,\n safeToObjectId,\n isValidObjectId,\n QueryBuilder,\n EmployeeQueryBuilder,\n PayrollQueryBuilder,\n employee,\n payroll,\n createQueryBuilder,\n buildEmployeeQuery,\n buildPayrollQuery,\n buildAggregationPipeline,\n matchStage,\n groupStage,\n sortStage,\n limitStage,\n skipStage,\n projectStage,\n lookupStage,\n unwindStage,\n default as queryBuilders,\n} from './query-builders.js';\n\n// ============================================================================\n// Leave Utilities\n// ============================================================================\n\nexport {\n DEFAULT_LEAVE_ALLOCATIONS,\n DEFAULT_CARRY_OVER,\n calculateLeaveDays,\n hasLeaveBalance,\n getLeaveBalance,\n getLeaveBalances,\n getAvailableDays,\n getLeaveSummary,\n initializeLeaveBalances,\n proRateAllocation,\n calculateUnpaidLeaveDeduction,\n getUnpaidLeaveDays,\n calculateCarryOver,\n accrueLeaveToBalance,\n default as leaveUtils,\n} from './leave.js';\n\n// ============================================================================\n// Secure Employee Lookup (Multi-Tenant Safety)\n// ============================================================================\n\nexport {\n findEmployeeSecure,\n employeeExistsSecure,\n findEmployeesSecure,\n requireOrganizationId,\n type SecureEmployeeLookupOptions,\n type EmployeeIdMode,\n} from './employee-lookup.js';\n\n// ============================================================================\n// Organization Resolution (Smart Auto-Detection)\n// ============================================================================\n\nexport {\n resolveOrganizationId,\n validateOrganizationId,\n tryResolveOrganizationId,\n type ResolveOrganizationIdParams,\n type ContainerLike,\n} from './org-resolution.js';\n\n// ============================================================================\n// Employee Identity (Dual ID System)\n// ============================================================================\n\nexport {\n detectEmployeeIdType,\n normalizeEmployeeId,\n isStringEmployeeId,\n isObjectIdEmployeeId,\n formatEmployeeId,\n type EmployeeIdType,\n type EmployeeQueryFilter,\n} from './employee-identity.js';\n\n// Note: buildEmployeeQuery from employee-identity.js is intentionally not exported\n// to avoid naming conflict with query-builders.js. It's used internally by findEmployeeSecure.\n","/**\n * @classytic/payroll - Tax Withholding Service\n *\n * Business logic for tax withholding tracking and management\n */\n\nimport type { Model, ClientSession } from 'mongoose';\nimport type {\n TaxWithholdingDocument,\n TaxType,\n TaxStatus,\n ObjectIdLike,\n ObjectId,\n PayrollBreakdown,\n PayrollPeriod,\n AnyModel,\n OperationContext,\n GetPendingTaxParams,\n TaxSummaryParams,\n TaxSummaryResult,\n MarkTaxPaidParams,\n} from '../types.js';\nimport type { EventBus } from '../core/events.js';\nimport { toObjectId } from '../utils/index.js';\nimport { logger } from '../utils/logger.js';\nimport { TAX_TYPE, TAX_STATUS } from '../enums.js';\n\n// ============================================================================\n// Service Configuration\n// ============================================================================\n\nexport interface TaxWithholdingServiceConfig {\n TaxWithholdingModel: Model<TaxWithholdingDocument>;\n TransactionModel?: AnyModel;\n events?: EventBus;\n}\n\nexport interface CreateFromBreakdownParams {\n organizationId: ObjectId;\n employeeId: ObjectId;\n userId?: ObjectId;\n payrollRecordId: ObjectId;\n transactionId: ObjectId;\n period: PayrollPeriod;\n breakdown: PayrollBreakdown;\n currency?: string;\n session?: ClientSession;\n context?: OperationContext;\n}\n\n// ============================================================================\n// Tax Withholding Service\n// ============================================================================\n\n/**\n * Service for managing tax withholdings\n *\n * Provides methods for creating, querying, and updating tax withholding records\n */\nexport class TaxWithholdingService {\n constructor(\n private readonly TaxWithholdingModel: Model<TaxWithholdingDocument>,\n private readonly TransactionModel?: AnyModel,\n private readonly events?: EventBus\n ) {}\n\n /**\n * Create tax withholding records from payroll breakdown\n *\n * Extracts tax deductions from the breakdown and creates separate\n * TaxWithholding records for each tax type\n */\n async createFromBreakdown(params: CreateFromBreakdownParams): Promise<TaxWithholdingDocument[]> {\n const {\n organizationId,\n employeeId,\n userId,\n payrollRecordId,\n transactionId,\n period,\n breakdown,\n currency = 'BDT',\n session,\n context,\n } = params;\n\n // Extract tax deductions from breakdown\n const taxDeductions = breakdown.deductions?.filter((d) =>\n d.type === 'tax' || this.isTaxDeduction(d.type)\n ) || [];\n\n if (taxDeductions.length === 0) {\n return [];\n }\n\n const withholdings: TaxWithholdingDocument[] = [];\n\n // Create one TaxWithholding record per tax type\n for (const deduction of taxDeductions) {\n const taxType = this.mapDeductionTypeToTaxType(deduction.type);\n const taxRate = breakdown.taxableAmount && breakdown.taxableAmount > 0\n ? deduction.amount / breakdown.taxableAmount\n : 0;\n\n const withholdingData = {\n organizationId,\n employeeId,\n userId,\n payrollRecordId,\n transactionId,\n period,\n amount: deduction.amount,\n currency,\n taxType,\n taxRate,\n taxableAmount: breakdown.taxableAmount || breakdown.grossSalary,\n status: TAX_STATUS.PENDING as TaxStatus,\n };\n\n const [withholding] = await this.TaxWithholdingModel.create([withholdingData], {\n session,\n });\n\n withholdings.push(withholding);\n\n // Emit tax:withheld event\n if (this.events) {\n this.events.emitSync('tax:withheld', {\n withholding: {\n id: withholding._id,\n taxType: withholding.taxType,\n amount: withholding.amount,\n },\n employee: {\n id: employeeId,\n employeeId: '', // Will be filled by caller if needed\n },\n payrollRecord: {\n id: payrollRecordId,\n },\n period: {\n month: period.month,\n year: period.year,\n },\n organizationId,\n context,\n });\n }\n\n logger.info('Tax withholding created', {\n withholdingId: withholding._id.toString(),\n employeeId: employeeId.toString(),\n taxType,\n amount: deduction.amount,\n period: `${period.month}/${period.year}`,\n });\n }\n\n return withholdings;\n }\n\n /**\n * Get pending tax withholdings with optional filters\n */\n async getPending(params: GetPendingTaxParams): Promise<TaxWithholdingDocument[]> {\n const { organizationId, fromPeriod, toPeriod, taxType, employeeId } = params;\n\n const options: {\n fromMonth?: number;\n fromYear?: number;\n toMonth?: number;\n toYear?: number;\n taxType?: TaxType;\n } = {};\n\n if (fromPeriod) {\n options.fromMonth = fromPeriod.month;\n options.fromYear = fromPeriod.year;\n }\n if (toPeriod) {\n options.toMonth = toPeriod.month;\n options.toYear = toPeriod.year;\n }\n if (taxType) {\n options.taxType = taxType;\n }\n\n let query = (this.TaxWithholdingModel as any).findPending(\n toObjectId(organizationId),\n options\n );\n\n // Additional filter by employee if provided\n if (employeeId) {\n query = query.where({ employeeId: toObjectId(employeeId) });\n }\n\n return query.exec();\n }\n\n /**\n * Get tax summary aggregated by type, period, or employee\n */\n async getSummary(params: TaxSummaryParams): Promise<TaxSummaryResult> {\n const { organizationId, fromPeriod, toPeriod, groupBy = 'type' } = params;\n\n if (groupBy === 'type') {\n const byType = await (this.TaxWithholdingModel as any).getSummaryByType(\n toObjectId(organizationId),\n fromPeriod,\n toPeriod\n );\n\n const totalAmount = byType.reduce((sum: number, item: { totalAmount: number }) => sum + item.totalAmount, 0);\n const count = byType.reduce((sum: number, item: { count: number }) => sum + item.count, 0);\n\n return {\n totalAmount,\n count,\n byType,\n period: {\n fromMonth: fromPeriod.month,\n fromYear: fromPeriod.year,\n toMonth: toPeriod.month,\n toYear: toPeriod.year,\n },\n };\n }\n\n // For now, only support groupBy: 'type'\n // Can extend for 'period' and 'employee' later\n throw new Error(`groupBy '${groupBy}' not yet implemented`);\n }\n\n /**\n * Mark tax withholdings as paid\n *\n * Updates status, optionally creates government payment transaction,\n * and emits tax:paid event\n */\n async markPaid(params: MarkTaxPaidParams): Promise<{\n withholdings: TaxWithholdingDocument[];\n transaction?: any;\n }> {\n const {\n organizationId,\n withholdingIds,\n createTransaction = false,\n referenceNumber,\n paidAt = new Date(),\n notes,\n context,\n } = params;\n\n const session = context?.session;\n\n // Fetch withholdings\n const withholdings = await this.TaxWithholdingModel.find({\n _id: { $in: withholdingIds.map(toObjectId) },\n organizationId: toObjectId(organizationId),\n }).session(session || null);\n\n if (withholdings.length === 0) {\n throw new Error('No tax withholdings found with provided IDs');\n }\n\n // Calculate total amount\n const totalAmount = withholdings.reduce((sum, w) => sum + w.amount, 0);\n\n let governmentTransaction: any = null;\n\n // Optionally create government payment transaction\n if (createTransaction && this.TransactionModel) {\n const transactionData = {\n organizationId: toObjectId(organizationId),\n type: 'tax_payment',\n flow: 'outflow',\n tags: ['tax', 'government', 'withholding'],\n amount: totalAmount,\n grossAmount: totalAmount,\n currency: withholdings[0].currency || 'BDT',\n status: 'completed',\n date: paidAt,\n description: `Tax payment to government - ${referenceNumber || 'Multiple withholdings'}`,\n notes,\n metadata: {\n withholdingIds: withholdingIds.map((id) => id.toString()),\n referenceNumber,\n },\n };\n\n [governmentTransaction] = await this.TransactionModel.create([transactionData], {\n session,\n });\n }\n\n // Update all withholdings\n for (const withholding of withholdings) {\n withholding.markAsPaid(\n governmentTransaction?._id,\n referenceNumber,\n paidAt\n );\n await withholding.save({ session });\n }\n\n // Emit tax:paid event\n if (this.events) {\n this.events.emitSync('tax:paid', {\n withholdings: withholdings.map((w) => ({\n id: w._id,\n taxType: w.taxType,\n amount: w.amount,\n })),\n transaction: governmentTransaction\n ? {\n id: governmentTransaction._id,\n amount: governmentTransaction.amount,\n }\n : undefined,\n totalAmount,\n referenceNumber,\n paidAt,\n organizationId: toObjectId(organizationId),\n context,\n });\n }\n\n logger.info('Tax withholdings marked as paid', {\n count: withholdings.length,\n totalAmount,\n referenceNumber,\n transactionId: governmentTransaction?._id.toString(),\n });\n\n return {\n withholdings,\n transaction: governmentTransaction,\n };\n }\n\n /**\n * Get tax withholdings for a specific payroll record\n */\n async getByPayrollRecord(payrollRecordId: ObjectIdLike): Promise<TaxWithholdingDocument[]> {\n return (this.TaxWithholdingModel as any)\n .getByPayrollRecord(toObjectId(payrollRecordId))\n .exec();\n }\n\n /**\n * Get tax withholdings for a specific employee\n */\n async getByEmployee(\n employeeId: ObjectIdLike,\n options?: { year?: number; taxType?: TaxType; status?: TaxStatus }\n ): Promise<TaxWithholdingDocument[]> {\n return (this.TaxWithholdingModel as any)\n .findByEmployee(toObjectId(employeeId), options)\n .exec();\n }\n\n // ============================================================================\n // Private Helpers\n // ============================================================================\n\n /**\n * Check if deduction type is a tax deduction\n */\n private isTaxDeduction(deductionType: string): boolean {\n const taxTypes = ['tax', 'income_tax', 'social_security', 'health_insurance', 'pension', 'employment_insurance', 'local_tax'];\n return taxTypes.includes(deductionType.toLowerCase());\n }\n\n /**\n * Map deduction type to TaxType enum\n */\n private mapDeductionTypeToTaxType(deductionType: string): TaxType {\n const typeMap: Record<string, TaxType> = {\n 'tax': TAX_TYPE.INCOME_TAX,\n 'income_tax': TAX_TYPE.INCOME_TAX,\n 'social_security': TAX_TYPE.SOCIAL_SECURITY,\n 'health_insurance': TAX_TYPE.HEALTH_INSURANCE,\n 'pension': TAX_TYPE.PENSION,\n 'employment_insurance': TAX_TYPE.EMPLOYMENT_INSURANCE,\n 'local_tax': TAX_TYPE.LOCAL_TAX,\n };\n\n return typeMap[deductionType.toLowerCase()] || TAX_TYPE.OTHER;\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a new TaxWithholdingService instance\n *\n * @example\n * const service = createTaxWithholdingService({\n * TaxWithholdingModel,\n * TransactionModel,\n * events: eventBus\n * });\n */\nexport function createTaxWithholdingService(\n config: TaxWithholdingServiceConfig\n): TaxWithholdingService {\n return new TaxWithholdingService(\n config.TaxWithholdingModel,\n config.TransactionModel,\n config.events\n );\n}\n","/**\n * @classytic/payroll - Dependency Container\n *\n * Per-instance dependency injection container for service management.\n * Enables clean dependency injection and testing without global state.\n *\n * IMPORTANT: This container is instance-based (not a singleton) to support:\n * - Serverless/Lambda environments\n * - Multi-app runtimes\n * - Parallel testing\n * - Multiple Payroll instances in the same process\n */\n\nimport type { Model, ClientSession } from 'mongoose';\nimport type {\n Logger,\n HRMConfig,\n SingleTenantConfig,\n EmployeeDocument,\n PayrollRecordDocument,\n AnyDocument,\n LeaveRequestDocument,\n TaxWithholdingDocument,\n} from '../types.js';\nimport { getLogger } from '../utils/logger.js';\nimport { HRM_CONFIG, mergeConfig } from '../config.js';\n\n// ============================================================================\n// Container Types with Strong Generics\n// ============================================================================\n\n/**\n * Strongly-typed models container\n * Uses specific document types instead of Model<any> for better DX\n */\nexport interface ModelsContainer<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument,\n TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument,\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument,\n> {\n EmployeeModel: Model<TEmployee>;\n PayrollRecordModel: Model<TPayrollRecord>;\n TransactionModel: Model<TTransaction>;\n AttendanceModel?: Model<TAttendance> | null;\n LeaveRequestModel?: Model<TLeaveRequest> | null;\n TaxWithholdingModel?: Model<TTaxWithholding> | null;\n}\n\n/**\n * Container configuration with generic model types\n */\nexport interface ContainerConfig<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument,\n TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument,\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument,\n> {\n models: ModelsContainer<TEmployee, TPayrollRecord, TTransaction, TAttendance, TLeaveRequest, TTaxWithholding>;\n config?: Partial<HRMConfig>;\n singleTenant?: SingleTenantConfig | null;\n logger?: Logger;\n}\n\n// ============================================================================\n// Container Class (Per-Instance, Not Singleton)\n// ============================================================================\n\n/**\n * Per-instance DI Container for Payroll\n *\n * Each Payroll instance creates its own Container, avoiding global state issues\n * in serverless and multi-app environments.\n *\n * @example\n * ```typescript\n * // Each Payroll instance has its own container\n * const payroll1 = createPayrollInstance()\n * .withModels({ EmployeeModel, PayrollRecordModel, TransactionModel })\n * .build();\n *\n * const payroll2 = createPayrollInstance()\n * .withModels({ OtherEmployeeModel, OtherPayrollModel, OtherTransactionModel })\n * .build();\n *\n * // They don't share state - perfect for multi-tenant or testing\n * ```\n */\nexport class Container<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument,\n TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument,\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument,\n> {\n private _models: ModelsContainer<TEmployee, TPayrollRecord, TTransaction, TAttendance, TLeaveRequest, TTaxWithholding> | null = null;\n private _config: HRMConfig = HRM_CONFIG;\n private _singleTenant: SingleTenantConfig | null = null;\n private _logger: Logger;\n private _initialized = false;\n\n constructor() {\n this._logger = getLogger();\n }\n\n /**\n * Initialize container with configuration\n */\n initialize(\n config: ContainerConfig<TEmployee, TPayrollRecord, TTransaction, TAttendance, TLeaveRequest, TTaxWithholding>\n ): void {\n if (this._initialized) {\n this._logger.warn('Container already initialized, re-initializing');\n }\n\n this._models = config.models;\n this._config = mergeConfig(config.config);\n this._singleTenant = config.singleTenant ?? null;\n\n if (config.logger) {\n this._logger = config.logger;\n }\n\n this._initialized = true;\n\n this._logger.info('Container initialized', {\n hasEmployeeModel: !!this._models.EmployeeModel,\n hasPayrollRecordModel: !!this._models.PayrollRecordModel,\n hasTransactionModel: !!this._models.TransactionModel,\n hasAttendanceModel: !!this._models.AttendanceModel,\n hasLeaveRequestModel: !!this._models.LeaveRequestModel,\n hasTaxWithholdingModel: !!this._models.TaxWithholdingModel,\n isSingleTenant: !!this._singleTenant,\n });\n }\n\n /**\n * Check if container is initialized\n */\n isInitialized(): boolean {\n return this._initialized;\n }\n\n /**\n * Reset container (useful for testing)\n */\n reset(): void {\n this._models = null;\n this._config = HRM_CONFIG;\n this._singleTenant = null;\n this._initialized = false;\n this._logger.info('Container reset');\n }\n\n /**\n * Ensure container is initialized\n */\n private ensureInitialized(): void {\n if (!this._initialized || !this._models) {\n throw new Error(\n 'Payroll not initialized. Call Payroll.initialize() first.'\n );\n }\n }\n\n /**\n * Get models container (strongly typed)\n */\n getModels(): ModelsContainer<TEmployee, TPayrollRecord, TTransaction, TAttendance, TLeaveRequest, TTaxWithholding> {\n this.ensureInitialized();\n return this._models!;\n }\n\n /**\n * Get Employee model (strongly typed)\n */\n getEmployeeModel(): Model<TEmployee> {\n this.ensureInitialized();\n return this._models!.EmployeeModel;\n }\n\n /**\n * Get PayrollRecord model (strongly typed)\n */\n getPayrollRecordModel(): Model<TPayrollRecord> {\n this.ensureInitialized();\n return this._models!.PayrollRecordModel;\n }\n\n /**\n * Get Transaction model (strongly typed)\n */\n getTransactionModel(): Model<TTransaction> {\n this.ensureInitialized();\n return this._models!.TransactionModel;\n }\n\n /**\n * Get Attendance model (optional, strongly typed)\n */\n getAttendanceModel(): Model<TAttendance> | null {\n this.ensureInitialized();\n return this._models!.AttendanceModel ?? null;\n }\n\n /**\n * Get LeaveRequest model (optional, strongly typed)\n */\n getLeaveRequestModel(): Model<TLeaveRequest> | null {\n this.ensureInitialized();\n return this._models!.LeaveRequestModel ?? null;\n }\n\n /**\n * Get TaxWithholding model (optional, strongly typed)\n */\n getTaxWithholdingModel(): Model<TTaxWithholding> | null {\n this.ensureInitialized();\n return this._models!.TaxWithholdingModel ?? null;\n }\n\n /**\n * Get configuration\n */\n getConfig(): HRMConfig {\n return this._config;\n }\n\n /**\n * Get specific config section\n */\n getConfigSection<K extends keyof HRMConfig>(section: K): HRMConfig[K] {\n return this._config[section];\n }\n\n /**\n * Check if single-tenant mode\n */\n isSingleTenant(): boolean {\n return !!this._singleTenant;\n }\n\n /**\n * Get single-tenant config\n */\n getSingleTenantConfig(): SingleTenantConfig | null {\n return this._singleTenant;\n }\n\n /**\n * Get organization ID (for single-tenant mode)\n */\n getOrganizationId(): string | null {\n if (!this._singleTenant || !this._singleTenant.organizationId) return null;\n return typeof this._singleTenant.organizationId === 'string'\n ? this._singleTenant.organizationId\n : this._singleTenant.organizationId.toString();\n }\n\n /**\n * Get logger\n */\n getLogger(): Logger {\n return this._logger;\n }\n\n /**\n * Set logger\n */\n setLogger(logger: Logger): void {\n this._logger = logger;\n }\n\n /**\n * Has attendance integration\n */\n hasAttendanceIntegration(): boolean {\n return (\n !!this._models?.AttendanceModel &&\n this._config.payroll.attendanceIntegration\n );\n }\n\n /**\n * Create operation context with defaults\n */\n createOperationContext(\n overrides?: Partial<{\n userId: string;\n userName: string;\n userRole: string;\n organizationId: string;\n session: ClientSession;\n }>\n ): {\n userId?: string;\n userName?: string;\n userRole?: string;\n organizationId?: string;\n session?: ClientSession;\n } {\n const context: Record<string, unknown> = {};\n\n // Auto-inject organizationId in single-tenant mode\n if (this._singleTenant?.autoInject && !overrides?.organizationId) {\n context.organizationId = this.getOrganizationId();\n }\n\n return { ...context, ...overrides };\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a new Container instance\n */\nexport function createContainer<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument,\n TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument,\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument,\n>(): Container<TEmployee, TPayrollRecord, TTransaction, TAttendance, TLeaveRequest, TTaxWithholding> {\n return new Container<TEmployee, TPayrollRecord, TTransaction, TAttendance, TLeaveRequest, TTaxWithholding>();\n}\n\n// ============================================================================\n// Default Instance (for backwards compatibility)\n// ============================================================================\n\n/**\n * @deprecated Use createPayrollInstance() instead for new code.\n * This default instance is kept for backwards compatibility but should be avoided\n * in serverless/multi-app environments.\n *\n * WARNING: Global singletons can cause issues in:\n * - AWS Lambda (cold starts may share state)\n * - Vercel Functions\n * - Multiple app instances in same process\n * - Parallel tests\n */\nlet defaultContainer: Container | null = null;\n\n/**\n * @deprecated Use createPayrollInstance() instead.\n * Get or create the default container instance.\n */\nexport function getContainer(): Container {\n if (!defaultContainer) {\n defaultContainer = new Container();\n }\n return defaultContainer;\n}\n\n/**\n * @deprecated Use createPayrollInstance() instead.\n * Initialize the default container.\n */\nexport function initializeContainer(config: ContainerConfig): void {\n getContainer().initialize(config);\n}\n\n/**\n * @deprecated Use container.isInitialized() instead.\n * Check if the default container is initialized.\n */\nexport function isContainerInitialized(): boolean {\n return defaultContainer?.isInitialized() ?? false;\n}\n\n/**\n * @deprecated Use container.getModels() instead.\n * Get models from the default container.\n */\nexport function getModels(): ModelsContainer {\n return getContainer().getModels();\n}\n\n/**\n * @deprecated Use container.getConfig() instead.\n * Get config from the default container.\n */\nexport function getConfig(): HRMConfig {\n return getContainer().getConfig();\n}\n\n/**\n * @deprecated Use container.isSingleTenant() instead.\n * Check if single-tenant mode.\n */\nexport function isSingleTenant(): boolean {\n return getContainer().isSingleTenant();\n}\n\n/**\n * Reset the default container (for testing).\n * @deprecated Prefer instance-based containers for testing.\n */\nexport function resetDefaultContainer(): void {\n if (defaultContainer) {\n defaultContainer.reset();\n }\n defaultContainer = null;\n}\n\n// Legacy alias for backwards compatibility\nexport { resetDefaultContainer as resetContainer };\n","/**\n * @classytic/payroll - Configuration\n *\n * Centralized configuration with type safety\n * Configurable defaults for different use cases\n */\n\nimport type {\n HRMConfig,\n TaxBracket,\n SalaryBandRange,\n RoleMappingConfig,\n OrgRole,\n SalaryBand,\n Department,\n EmploymentType,\n PaymentFrequency,\n DeepPartial,\n EmployeeIdentityMode,\n} from './types.js';\n\n// ============================================================================\n// Default Configuration\n// ============================================================================\n\nexport const HRM_CONFIG: HRMConfig = {\n dataRetention: {\n payrollRecordsTTL: 63072000, // 2 years in seconds\n exportWarningDays: 30,\n archiveBeforeDeletion: true,\n },\n\n payroll: {\n defaultCurrency: 'BDT',\n allowProRating: true,\n attendanceIntegration: true,\n autoDeductions: true,\n overtimeEnabled: false,\n overtimeMultiplier: 1.5,\n },\n\n salary: {\n minimumWage: 0,\n maximumAllowances: 10,\n maximumDeductions: 10,\n defaultFrequency: 'monthly',\n },\n\n employment: {\n defaultProbationMonths: 3,\n maxProbationMonths: 6,\n allowReHiring: true,\n trackEmploymentHistory: true,\n },\n\n validation: {\n requireBankDetails: false,\n requireUserId: false, // Modern: Allow guest employees by default\n identityMode: 'employeeId', // Modern: Use human-readable IDs as primary\n identityFallbacks: ['email', 'userId'], // Smart fallback chain\n },\n};\n\n// ============================================================================\n// Salary Bands Configuration\n// ============================================================================\n\nexport const SALARY_BANDS: Record<Exclude<SalaryBand, 'custom'>, SalaryBandRange> = {\n intern: { min: 10000, max: 20000 },\n junior: { min: 20000, max: 40000 },\n mid: { min: 40000, max: 70000 },\n senior: { min: 70000, max: 120000 },\n lead: { min: 100000, max: 200000 },\n executive: { min: 150000, max: 500000 },\n};\n\n// ============================================================================\n// Tax Brackets Configuration\n// ============================================================================\n\nexport const TAX_BRACKETS: Record<string, TaxBracket[]> = {\n BDT: [\n { min: 0, max: 300000, rate: 0 },\n { min: 300000, max: 400000, rate: 0.05 },\n { min: 400000, max: 500000, rate: 0.10 },\n { min: 500000, max: 600000, rate: 0.15 },\n { min: 600000, max: 3000000, rate: 0.20 },\n { min: 3000000, max: Infinity, rate: 0.25 },\n ],\n USD: [\n { min: 0, max: 10000, rate: 0.10 },\n { min: 10000, max: 40000, rate: 0.12 },\n { min: 40000, max: 85000, rate: 0.22 },\n { min: 85000, max: 165000, rate: 0.24 },\n { min: 165000, max: 215000, rate: 0.32 },\n { min: 215000, max: 540000, rate: 0.35 },\n { min: 540000, max: Infinity, rate: 0.37 },\n ],\n};\n\n// ============================================================================\n// Organization Roles Configuration\n// ============================================================================\n\nexport interface OrgRoleDefinition {\n key: OrgRole;\n label: string;\n description: string;\n}\n\nexport const ORG_ROLES: Record<Uppercase<OrgRole>, OrgRoleDefinition> = {\n OWNER: {\n key: 'owner',\n label: 'Owner',\n description: 'Full organization access (set by Organization model)',\n },\n MANAGER: {\n key: 'manager',\n label: 'Manager',\n description: 'Management and administrative features',\n },\n TRAINER: {\n key: 'trainer',\n label: 'Trainer',\n description: 'Training and coaching features',\n },\n STAFF: {\n key: 'staff',\n label: 'Staff',\n description: 'General staff access to basic features',\n },\n INTERN: {\n key: 'intern',\n label: 'Intern',\n description: 'Limited access for interns',\n },\n CONSULTANT: {\n key: 'consultant',\n label: 'Consultant',\n description: 'Project-based consultant access',\n },\n};\n\nexport const ORG_ROLE_KEYS = Object.values(ORG_ROLES).map((role) => role.key);\n\n// ============================================================================\n// Role Mapping Configuration\n// ============================================================================\n\nexport const ROLE_MAPPING: RoleMappingConfig = {\n byDepartment: {\n management: 'manager',\n training: 'trainer',\n sales: 'staff',\n operations: 'staff',\n finance: 'staff',\n hr: 'staff',\n marketing: 'staff',\n it: 'staff',\n support: 'staff',\n maintenance: 'staff',\n },\n\n byEmploymentType: {\n full_time: 'staff',\n part_time: 'staff',\n contract: 'consultant',\n intern: 'intern',\n consultant: 'consultant',\n },\n\n default: 'staff',\n};\n\n// ============================================================================\n// Configuration Functions\n// ============================================================================\n\n/**\n * Calculate tax based on annual income\n */\nexport function calculateTax(annualIncome: number, currency = 'BDT'): number {\n const brackets = TAX_BRACKETS[currency];\n if (!brackets) return 0;\n\n let tax = 0;\n for (const bracket of brackets) {\n if (annualIncome > bracket.min) {\n const taxableAmount = Math.min(annualIncome, bracket.max) - bracket.min;\n tax += taxableAmount * bracket.rate;\n }\n }\n return Math.round(tax);\n}\n\n/**\n * Get salary band for a given amount\n */\nexport function getSalaryBand(amount: number): SalaryBand {\n for (const [band, range] of Object.entries(SALARY_BANDS)) {\n if (amount >= range.min && amount <= range.max) {\n return band as SalaryBand;\n }\n }\n return 'custom';\n}\n\n/**\n * Determine the appropriate organization role for an employee\n */\nexport function determineOrgRole(employmentData: {\n department?: Department | string;\n type?: EmploymentType | string;\n position?: string;\n}): OrgRole {\n const { department, type: employmentType } = employmentData;\n\n // Priority 1: Department-based mapping\n if (department && department in ROLE_MAPPING.byDepartment) {\n return ROLE_MAPPING.byDepartment[department as keyof typeof ROLE_MAPPING.byDepartment];\n }\n\n // Priority 2: Employment type mapping\n if (employmentType && employmentType in ROLE_MAPPING.byEmploymentType) {\n return ROLE_MAPPING.byEmploymentType[employmentType as keyof typeof ROLE_MAPPING.byEmploymentType];\n }\n\n // Priority 3: Default role\n return ROLE_MAPPING.default;\n}\n\n/**\n * Get pay periods per year based on frequency\n */\nexport function getPayPeriodsPerYear(frequency: PaymentFrequency): number {\n const periodsMap: Record<PaymentFrequency, number> = {\n monthly: 12,\n bi_weekly: 26,\n weekly: 52,\n daily: 365,\n hourly: 2080, // Assuming 40 hours/week * 52 weeks\n };\n return periodsMap[frequency];\n}\n\n/**\n * Calculate monthly equivalent from any frequency\n */\nexport function toMonthlyAmount(amount: number, frequency: PaymentFrequency): number {\n const periodsPerYear = getPayPeriodsPerYear(frequency);\n return Math.round((amount * periodsPerYear) / 12);\n}\n\n/**\n * Calculate annual equivalent from any frequency\n */\nexport function toAnnualAmount(amount: number, frequency: PaymentFrequency): number {\n const periodsPerYear = getPayPeriodsPerYear(frequency);\n return Math.round(amount * periodsPerYear);\n}\n\n/**\n * Merge configuration with defaults\n */\nexport function mergeConfig(\n customConfig: Partial<HRMConfig> | DeepPartial<HRMConfig> | undefined\n): HRMConfig {\n if (!customConfig) return HRM_CONFIG;\n\n return {\n dataRetention: { ...HRM_CONFIG.dataRetention, ...customConfig.dataRetention },\n payroll: { ...HRM_CONFIG.payroll, ...customConfig.payroll },\n salary: { ...HRM_CONFIG.salary, ...customConfig.salary },\n employment: { ...HRM_CONFIG.employment, ...customConfig.employment },\n validation: {\n ...HRM_CONFIG.validation,\n ...customConfig.validation,\n // Ensure fallbacks is always EmployeeIdentityMode[]\n identityFallbacks: (customConfig.validation?.identityFallbacks ?? HRM_CONFIG.validation.identityFallbacks) as EmployeeIdentityMode[]\n },\n };\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n HRM_CONFIG,\n SALARY_BANDS,\n TAX_BRACKETS,\n ORG_ROLES,\n ORG_ROLE_KEYS,\n ROLE_MAPPING,\n calculateTax,\n getSalaryBand,\n determineOrgRole,\n getPayPeriodsPerYear,\n toMonthlyAmount,\n toAnnualAmount,\n mergeConfig,\n};\n\n","/**\n * @classytic/payroll - Event System\n *\n * Type-safe event emitter for payroll lifecycle events\n * Enables loose coupling and extensibility\n */\n\nimport type {\n PayrollEvent,\n EmployeeDocument,\n PayrollRecordDocument,\n ObjectId,\n OperationContext,\n} from '../types.js';\n\n// ============================================================================\n// Event Payload Types\n// ============================================================================\n\nexport interface EmployeeHiredEventPayload {\n employee: {\n id: ObjectId;\n employeeId: string;\n position: string;\n department?: string;\n };\n organizationId: ObjectId;\n context?: OperationContext;\n}\n\nexport interface EmployeeTerminatedEventPayload {\n employee: {\n id: ObjectId;\n employeeId: string;\n name?: string;\n };\n terminationDate: Date;\n reason?: string;\n organizationId: ObjectId;\n context?: OperationContext;\n}\n\nexport interface EmployeeRehiredEventPayload {\n employee: {\n id: ObjectId;\n employeeId: string;\n position: string;\n };\n previousTerminationDate?: Date;\n organizationId: ObjectId;\n context?: OperationContext;\n}\n\nexport interface SalaryUpdatedEventPayload {\n employee: {\n id: ObjectId;\n employeeId: string;\n };\n previousSalary: number;\n newSalary: number;\n effectiveFrom: Date;\n organizationId: ObjectId;\n context?: OperationContext;\n}\n\nexport interface SalaryProcessedEventPayload {\n employee: {\n id: ObjectId;\n employeeId: string;\n name?: string;\n };\n payroll: {\n id: ObjectId;\n period: { month: number; year: number };\n grossAmount: number;\n netAmount: number;\n };\n transactionId: ObjectId;\n organizationId: ObjectId;\n context?: OperationContext;\n}\n\nexport interface SalaryFailedEventPayload {\n employee: {\n id: ObjectId;\n employeeId: string;\n };\n period: { month: number; year: number };\n error: string;\n organizationId: ObjectId;\n context?: OperationContext;\n}\n\nexport interface PayrollCompletedEventPayload {\n organizationId: ObjectId;\n period: { month: number; year: number };\n summary: {\n total: number;\n successful: number;\n failed: number;\n totalAmount: number;\n };\n context?: OperationContext;\n}\n\nexport interface PayrollExportedEventPayload {\n organizationId: ObjectId;\n dateRange: { start: Date; end: Date };\n recordCount: number;\n format: string;\n context?: OperationContext;\n}\n\nexport interface CompensationChangedEventPayload {\n employee: {\n id: ObjectId;\n employeeId: string;\n };\n changeType: 'allowance_added' | 'allowance_removed' | 'deduction_added' | 'deduction_removed';\n details: {\n type: string;\n amount: number;\n };\n organizationId: ObjectId;\n context?: OperationContext;\n}\n\nexport interface MilestoneAchievedEventPayload {\n employee: {\n id: ObjectId;\n employeeId: string;\n name?: string;\n };\n milestone: {\n type: 'tenure' | 'salary' | 'payments';\n value: number;\n message: string;\n };\n organizationId: ObjectId;\n}\n\nexport interface TaxWithheldEventPayload {\n withholding: {\n id: ObjectId;\n taxType: string;\n amount: number;\n };\n employee: {\n id: ObjectId;\n employeeId: string;\n };\n payrollRecord: {\n id: ObjectId;\n };\n period: {\n month: number;\n year: number;\n };\n organizationId: ObjectId;\n context?: OperationContext;\n}\n\nexport interface TaxPaidEventPayload {\n withholdings: Array<{\n id: ObjectId;\n taxType: string;\n amount: number;\n }>;\n transaction?: {\n id: ObjectId;\n amount: number;\n };\n totalAmount: number;\n referenceNumber?: string;\n paidAt: Date;\n organizationId: ObjectId;\n context?: OperationContext;\n}\n\n// ============================================================================\n// Event Map\n// ============================================================================\n\nexport interface PayrollEventMap {\n 'employee:hired': EmployeeHiredEventPayload;\n 'employee:terminated': EmployeeTerminatedEventPayload;\n 'employee:rehired': EmployeeRehiredEventPayload;\n 'salary:updated': SalaryUpdatedEventPayload;\n 'salary:processed': SalaryProcessedEventPayload;\n 'salary:failed': SalaryFailedEventPayload;\n 'payroll:completed': PayrollCompletedEventPayload;\n 'payroll:exported': PayrollExportedEventPayload;\n 'compensation:changed': CompensationChangedEventPayload;\n 'milestone:achieved': MilestoneAchievedEventPayload;\n 'tax:withheld': TaxWithheldEventPayload;\n 'tax:paid': TaxPaidEventPayload;\n}\n\nexport type PayrollEventType = keyof PayrollEventMap;\n\n// ============================================================================\n// Event Handler Types\n// ============================================================================\n\nexport type EventHandler<T> = (payload: T) => void | Promise<void>;\n\nexport type PayrollEventHandler<K extends PayrollEventType> = EventHandler<\n PayrollEventMap[K]\n>;\n\n// ============================================================================\n// EventBus Class\n// ============================================================================\n\nexport class EventBus {\n private handlers = new Map<\n PayrollEventType,\n Set<EventHandler<unknown>>\n >();\n\n /**\n * Register an event handler\n */\n on<K extends PayrollEventType>(\n event: K,\n handler: PayrollEventHandler<K>\n ): () => void {\n if (!this.handlers.has(event)) {\n this.handlers.set(event, new Set());\n }\n this.handlers.get(event)!.add(handler as EventHandler<unknown>);\n\n // Return unsubscribe function\n return () => this.off(event, handler);\n }\n\n /**\n * Register a one-time event handler\n */\n once<K extends PayrollEventType>(\n event: K,\n handler: PayrollEventHandler<K>\n ): () => void {\n const wrappedHandler: PayrollEventHandler<K> = async (payload) => {\n this.off(event, wrappedHandler);\n await handler(payload);\n };\n return this.on(event, wrappedHandler);\n }\n\n /**\n * Remove an event handler\n */\n off<K extends PayrollEventType>(\n event: K,\n handler: PayrollEventHandler<K>\n ): void {\n const eventHandlers = this.handlers.get(event);\n if (eventHandlers) {\n eventHandlers.delete(handler as EventHandler<unknown>);\n }\n }\n\n /**\n * Emit an event\n */\n async emit<K extends PayrollEventType>(\n event: K,\n payload: PayrollEventMap[K]\n ): Promise<void> {\n const eventHandlers = this.handlers.get(event);\n if (!eventHandlers || eventHandlers.size === 0) {\n return;\n }\n\n const handlers = Array.from(eventHandlers);\n await Promise.all(\n handlers.map(async (handler) => {\n try {\n await handler(payload);\n } catch (error) {\n console.error(`Event handler error for ${event}:`, error);\n }\n })\n );\n }\n\n /**\n * Emit event synchronously (fire-and-forget)\n */\n emitSync<K extends PayrollEventType>(\n event: K,\n payload: PayrollEventMap[K]\n ): void {\n void this.emit(event, payload);\n }\n\n /**\n * Remove all handlers for an event\n */\n removeAllListeners(event?: PayrollEventType): void {\n if (event) {\n this.handlers.delete(event);\n } else {\n this.handlers.clear();\n }\n }\n\n /**\n * Get listener count for an event\n */\n listenerCount(event: PayrollEventType): number {\n return this.handlers.get(event)?.size ?? 0;\n }\n\n /**\n * Get all registered events\n */\n eventNames(): PayrollEventType[] {\n return Array.from(this.handlers.keys());\n }\n}\n\n// ============================================================================\n// Default EventBus Instance\n// ============================================================================\n\nlet defaultEventBus: EventBus | null = null;\n\n/**\n * Get or create the default event bus\n */\nexport function getEventBus(): EventBus {\n if (!defaultEventBus) {\n defaultEventBus = new EventBus();\n }\n return defaultEventBus;\n}\n\n/**\n * Create a new event bus instance\n */\nexport function createEventBus(): EventBus {\n return new EventBus();\n}\n\n/**\n * Reset the default event bus (for testing)\n */\nexport function resetEventBus(): void {\n if (defaultEventBus) {\n defaultEventBus.removeAllListeners();\n }\n defaultEventBus = null;\n}\n\n// ============================================================================\n// Convenience Functions\n// ============================================================================\n\n/**\n * Subscribe to employee hired events\n */\nexport function onEmployeeHired(\n handler: PayrollEventHandler<'employee:hired'>\n): () => void {\n return getEventBus().on('employee:hired', handler);\n}\n\n/**\n * Subscribe to salary processed events\n */\nexport function onSalaryProcessed(\n handler: PayrollEventHandler<'salary:processed'>\n): () => void {\n return getEventBus().on('salary:processed', handler);\n}\n\n/**\n * Subscribe to payroll completed events\n */\nexport function onPayrollCompleted(\n handler: PayrollEventHandler<'payroll:completed'>\n): () => void {\n return getEventBus().on('payroll:completed', handler);\n}\n\n/**\n * Subscribe to milestone achieved events\n */\nexport function onMilestoneAchieved(\n handler: PayrollEventHandler<'milestone:achieved'>\n): () => void {\n return getEventBus().on('milestone:achieved', handler);\n}\n\n","/**\n * @classytic/payroll - Plugin System\n *\n * Extensible plugin architecture for customization\n * Follows patterns from popular libraries like Mongoose, Fastify\n */\n\nimport type { PayrollInstance } from '../types.js';\nimport type { EventBus, PayrollEventType, PayrollEventMap } from './events.js';\n\n// ============================================================================\n// Plugin Context\n// ============================================================================\n\nexport interface PluginContext {\n /** Payroll instance */\n payroll: PayrollInstance;\n /** Event bus for subscribing to events */\n events: EventBus;\n /** Logger instance */\n logger: PluginLogger;\n /** Configuration getter */\n getConfig: <T>(key: string) => T | undefined;\n /** Register a hook */\n addHook: <K extends PayrollEventType>(\n event: K,\n handler: (payload: PayrollEventMap[K]) => void | Promise<void>\n ) => () => void;\n}\n\nexport interface PluginLogger {\n info(message: string, meta?: Record<string, unknown>): void;\n error(message: string, meta?: Record<string, unknown>): void;\n warn(message: string, meta?: Record<string, unknown>): void;\n debug(message: string, meta?: Record<string, unknown>): void;\n}\n\n// ============================================================================\n// Plugin Hooks\n// ============================================================================\n\nexport interface PluginHooks {\n /** Called before employee is hired */\n beforeHire?: (params: unknown) => void | Promise<void>;\n /** Called after employee is hired */\n afterHire?: (employee: unknown) => void | Promise<void>;\n /** Called before salary is processed */\n beforeProcessSalary?: (params: unknown) => void | Promise<void>;\n /** Called after salary is processed */\n afterProcessSalary?: (result: unknown) => void | Promise<void>;\n /** Called before termination */\n beforeTerminate?: (params: unknown) => void | Promise<void>;\n /** Called after termination */\n afterTerminate?: (employee: unknown) => void | Promise<void>;\n /** Called on any error */\n onError?: (error: Error, context: string) => void | Promise<void>;\n}\n\n// ============================================================================\n// Payroll Plugin Interface\n// ============================================================================\n\nexport interface PayrollPluginDefinition {\n name: string;\n version?: string;\n hooks?: PluginHooks;\n init?: (context: PluginContext) => void | Promise<void>;\n destroy?: () => void | Promise<void>;\n}\n\n// ============================================================================\n// Plugin Manager\n// ============================================================================\n\nexport class PluginManager {\n private plugins = new Map<string, PayrollPluginDefinition>();\n private hooks = new Map<keyof PluginHooks, Array<NonNullable<PluginHooks[keyof PluginHooks]>>>();\n\n constructor(private context: PluginContext) {}\n\n /**\n * Register a plugin\n */\n async register(plugin: PayrollPluginDefinition): Promise<void> {\n if (this.plugins.has(plugin.name)) {\n throw new Error(`Plugin \"${plugin.name}\" is already registered`);\n }\n\n // Register hooks\n if (plugin.hooks) {\n for (const [hookName, handler] of Object.entries(plugin.hooks)) {\n if (handler) {\n this.addHook(hookName as keyof PluginHooks, handler);\n }\n }\n }\n\n // Initialize plugin\n if (plugin.init) {\n await plugin.init(this.context);\n }\n\n this.plugins.set(plugin.name, plugin);\n this.context.logger.debug(`Plugin \"${plugin.name}\" registered`);\n }\n\n /**\n * Unregister a plugin\n */\n async unregister(name: string): Promise<void> {\n const plugin = this.plugins.get(name);\n if (!plugin) {\n return;\n }\n\n if (plugin.destroy) {\n await plugin.destroy();\n }\n\n this.plugins.delete(name);\n this.context.logger.debug(`Plugin \"${name}\" unregistered`);\n }\n\n /**\n * Add a hook handler\n */\n private addHook<K extends keyof PluginHooks>(\n hookName: K,\n handler: NonNullable<PluginHooks[K]>\n ): void {\n if (!this.hooks.has(hookName)) {\n this.hooks.set(hookName, []);\n }\n this.hooks.get(hookName)!.push(handler);\n }\n\n /**\n * Execute hooks for a given event\n */\n async executeHooks<K extends keyof PluginHooks>(\n hookName: K,\n ...args: Parameters<NonNullable<PluginHooks[K]>>\n ): Promise<void> {\n const handlers = this.hooks.get(hookName);\n if (!handlers || handlers.length === 0) {\n return;\n }\n\n for (const handler of handlers) {\n try {\n await (handler as (...args: unknown[]) => void | Promise<void>)(...args);\n } catch (error) {\n this.context.logger.error(`Hook \"${hookName}\" error:`, { error });\n // Execute onError hooks\n const errorHandlers = this.hooks.get('onError');\n if (errorHandlers) {\n for (const errorHandler of errorHandlers) {\n try {\n await (errorHandler as PluginHooks['onError'])!(error as Error, hookName);\n } catch {\n // Ignore errors in error handlers\n }\n }\n }\n }\n }\n }\n\n /**\n * Get registered plugin names\n */\n getPluginNames(): string[] {\n return Array.from(this.plugins.keys());\n }\n\n /**\n * Check if plugin is registered\n */\n hasPlugin(name: string): boolean {\n return this.plugins.has(name);\n }\n}\n\n// ============================================================================\n// Plugin Definition Helper\n// ============================================================================\n\n/**\n * Define a plugin with type safety\n */\nexport function definePlugin(\n definition: PayrollPluginDefinition\n): PayrollPluginDefinition {\n return definition;\n}\n\n// ============================================================================\n// Built-in Plugins\n// ============================================================================\n\n/**\n * Logging plugin - logs all payroll events\n */\nexport const loggingPlugin = definePlugin({\n name: 'logging',\n version: '1.0.0',\n init: (context) => {\n // Subscribe to all events\n context.addHook('employee:hired', (payload) => {\n context.logger.info('Employee hired', {\n employeeId: payload.employee.employeeId,\n position: payload.employee.position,\n });\n });\n\n context.addHook('salary:processed', (payload) => {\n context.logger.info('Salary processed', {\n employeeId: payload.employee.employeeId,\n amount: payload.payroll.netAmount,\n period: payload.payroll.period,\n });\n });\n\n context.addHook('employee:terminated', (payload) => {\n context.logger.info('Employee terminated', {\n employeeId: payload.employee.employeeId,\n reason: payload.reason,\n });\n });\n },\n hooks: {\n onError: (error, context) => {\n console.error(`[Payroll Error] ${context}:`, error.message);\n },\n },\n});\n\n/**\n * Metrics plugin - collects payroll metrics\n */\nexport const metricsPlugin = definePlugin({\n name: 'metrics',\n version: '1.0.0',\n init: (context) => {\n const metrics = {\n employeesHired: 0,\n employeesTerminated: 0,\n salariesProcessed: 0,\n totalPaid: 0,\n errors: 0,\n };\n\n context.addHook('employee:hired', () => {\n metrics.employeesHired++;\n });\n\n context.addHook('employee:terminated', () => {\n metrics.employeesTerminated++;\n });\n\n context.addHook('salary:processed', (payload) => {\n metrics.salariesProcessed++;\n metrics.totalPaid += payload.payroll.netAmount;\n });\n\n // Expose metrics on payroll instance\n (context.payroll as unknown as { metrics: typeof metrics }).metrics = metrics;\n },\n hooks: {\n onError: (error, context) => {\n // Increment error counter\n },\n },\n});\n\n/**\n * Notification plugin - sends notifications for events\n */\nexport interface NotificationPluginOptions {\n onHired?: (employee: { id: unknown; name?: string }) => void | Promise<void>;\n onTerminated?: (employee: { id: unknown; name?: string }) => void | Promise<void>;\n onSalaryProcessed?: (details: { \n employee: { id: unknown; name?: string };\n amount: number;\n }) => void | Promise<void>;\n onMilestone?: (details: {\n employee: { id: unknown; name?: string };\n milestone: string;\n }) => void | Promise<void>;\n}\n\nexport function createNotificationPlugin(\n options: NotificationPluginOptions\n): PayrollPluginDefinition {\n return definePlugin({\n name: 'notification',\n version: '1.0.0',\n init: (context) => {\n if (options.onHired) {\n context.addHook('employee:hired', async (payload) => {\n await options.onHired!({\n id: payload.employee.id,\n name: payload.employee.position,\n });\n });\n }\n\n if (options.onTerminated) {\n context.addHook('employee:terminated', async (payload) => {\n await options.onTerminated!({\n id: payload.employee.id,\n name: payload.employee.name,\n });\n });\n }\n\n if (options.onSalaryProcessed) {\n context.addHook('salary:processed', async (payload) => {\n await options.onSalaryProcessed!({\n employee: {\n id: payload.employee.id,\n name: payload.employee.name,\n },\n amount: payload.payroll.netAmount,\n });\n });\n }\n\n if (options.onMilestone) {\n context.addHook('milestone:achieved', async (payload) => {\n await options.onMilestone!({\n employee: {\n id: payload.employee.id,\n name: payload.employee.name,\n },\n milestone: payload.milestone.message,\n });\n });\n }\n },\n });\n}\n\n// Alias for backwards compatibility\nexport const notificationPlugin = createNotificationPlugin({});\n\n","/**\n * Idempotency Manager\n * Ensures operations are not duplicated when called with the same key\n */\n\nimport { LRUCache } from 'lru-cache';\nimport type { ObjectIdLike } from '../types.js';\n\nexport interface IdempotentResult<T = any> {\n value: T;\n cached: boolean;\n createdAt: Date;\n}\n\nexport class IdempotencyManager {\n private cache: LRUCache<string, { value: any; createdAt: Date }>;\n\n constructor(options: { max?: number; ttl?: number } = {}) {\n this.cache = new LRUCache({\n max: options.max || 10000, // Store 10k keys\n ttl: options.ttl || 1000 * 60 * 60 * 24, // 24 hours default\n });\n }\n\n /**\n * Check if key exists and return cached result\n */\n get<T>(key: string): IdempotentResult<T> | null {\n const cached = this.cache.get(key);\n if (!cached) return null;\n\n return {\n value: cached.value,\n cached: true,\n createdAt: cached.createdAt,\n };\n }\n\n /**\n * Store result for idempotency key\n */\n set<T>(key: string, value: T): void {\n this.cache.set(key, {\n value,\n createdAt: new Date(),\n });\n }\n\n /**\n * Execute function with idempotency protection\n */\n async execute<T>(\n key: string,\n fn: () => Promise<T>\n ): Promise<IdempotentResult<T>> {\n // Check cache first\n const cached = this.get<T>(key);\n if (cached) {\n return cached;\n }\n\n // Execute function\n const value = await fn();\n\n // Cache result\n this.set(key, value);\n\n return {\n value,\n cached: false,\n createdAt: new Date(),\n };\n }\n\n /**\n * Clear a specific key\n */\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n /**\n * Clear all keys\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get cache stats\n */\n stats(): { size: number; max: number } {\n return {\n size: this.cache.size,\n max: this.cache.max,\n };\n }\n}\n\n/**\n * Generate idempotency key for payroll operations\n */\nexport function generatePayrollIdempotencyKey(\n organizationId: ObjectIdLike,\n employeeId: ObjectIdLike,\n month: number,\n year: number\n): string {\n return `payroll:${organizationId}:${employeeId}:${year}-${month}`;\n}\n","/**\n * Webhook System\n * Sends HTTP notifications when payroll events occur\n */\n\nimport type { PayrollEventType, PayrollEventMap } from './events.js';\n\nexport interface WebhookConfig {\n url: string;\n events: PayrollEventType[];\n secret?: string;\n headers?: Record<string, string>;\n retries?: number;\n timeout?: number;\n}\n\nexport interface WebhookDelivery {\n id: string;\n event: PayrollEventType;\n url: string;\n payload: unknown;\n attempt: number;\n status: 'pending' | 'sent' | 'failed';\n response?: {\n status: number;\n body: string;\n };\n error?: string;\n sentAt?: Date;\n}\n\nexport class WebhookManager {\n private webhooks: WebhookConfig[] = [];\n private deliveryLog: WebhookDelivery[] = [];\n\n /**\n * Register a webhook\n */\n register(config: WebhookConfig): void {\n this.webhooks.push({\n retries: 3,\n timeout: 30000,\n ...config,\n });\n }\n\n /**\n * Remove a webhook\n */\n unregister(url: string): void {\n this.webhooks = this.webhooks.filter((w) => w.url !== url);\n }\n\n /**\n * Send webhook for event\n */\n async send<K extends PayrollEventType>(\n event: K,\n payload: PayrollEventMap[K]\n ): Promise<void> {\n const matchingWebhooks = this.webhooks.filter((w) => w.events.includes(event));\n\n const deliveries = matchingWebhooks.map((webhook) =>\n this.deliver(webhook, event, payload)\n );\n\n await Promise.allSettled(deliveries);\n }\n\n /**\n * Deliver webhook with retries\n */\n private async deliver<K extends PayrollEventType>(\n webhook: WebhookConfig,\n event: K,\n payload: PayrollEventMap[K]\n ): Promise<WebhookDelivery> {\n const deliveryId = `${Date.now()}-${Math.random().toString(36)}`;\n\n const delivery: WebhookDelivery = {\n id: deliveryId,\n event,\n url: webhook.url,\n payload,\n attempt: 0,\n status: 'pending',\n };\n\n this.deliveryLog.push(delivery);\n\n const maxRetries = webhook.retries || 3;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n delivery.attempt = attempt;\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), webhook.timeout || 30000);\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Payroll-Event': event,\n 'X-Payroll-Delivery': deliveryId,\n ...webhook.headers,\n };\n\n if (webhook.secret) {\n headers['X-Payroll-Signature'] = this.generateSignature(payload, webhook.secret);\n }\n\n const response = await fetch(webhook.url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n event,\n payload,\n deliveredAt: new Date().toISOString(),\n }),\n signal: controller.signal,\n });\n\n clearTimeout(timeout);\n\n delivery.response = {\n status: response.status,\n body: await response.text(),\n };\n delivery.sentAt = new Date();\n\n if (response.ok) {\n delivery.status = 'sent';\n return delivery;\n }\n\n // Retry on 5xx errors\n if (response.status >= 500 && attempt < maxRetries) {\n await this.sleep(Math.pow(2, attempt) * 1000); // Exponential backoff\n continue;\n }\n\n delivery.status = 'failed';\n delivery.error = `HTTP ${response.status}`;\n return delivery;\n } catch (error) {\n delivery.error = (error as Error).message;\n\n if (attempt < maxRetries) {\n await this.sleep(Math.pow(2, attempt) * 1000);\n continue;\n }\n\n delivery.status = 'failed';\n return delivery;\n }\n }\n\n return delivery;\n }\n\n /**\n * Generate HMAC signature for webhook\n */\n private generateSignature(payload: unknown, secret: string): string {\n // Simple hash - in production, use crypto.createHmac\n const data = JSON.stringify(payload);\n return Buffer.from(`${secret}:${data}`).toString('base64');\n }\n\n /**\n * Sleep for ms\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Get delivery log\n */\n getDeliveries(options?: { event?: PayrollEventType; status?: WebhookDelivery['status']; limit?: number }): WebhookDelivery[] {\n let results = this.deliveryLog;\n\n if (options?.event) {\n results = results.filter((d) => d.event === options.event);\n }\n\n if (options?.status) {\n results = results.filter((d) => d.status === options.status);\n }\n\n if (options?.limit) {\n results = results.slice(-options.limit);\n }\n\n return results;\n }\n\n /**\n * Clear delivery log\n */\n clearLog(): void {\n this.deliveryLog = [];\n }\n\n /**\n * Get all registered webhooks\n */\n getWebhooks(): WebhookConfig[] {\n return [...this.webhooks];\n }\n}\n","/**\n * @classytic/payroll - Main Payroll Class\n *\n * Clean, Stripe-like API for payroll management\n * Builder pattern for configuration\n */\n\nimport mongoose, { Model, ClientSession } from 'mongoose';\nimport type {\n PayrollInitConfig,\n HRMConfig,\n SingleTenantConfig,\n Logger,\n ObjectIdLike,\n PayrollInstance,\n EmployeeDocument,\n PayrollRecordDocument,\n LeaveRequestDocument,\n TaxWithholdingDocument,\n AnyDocument,\n HireEmployeeParams,\n UpdateEmploymentParams,\n TerminateEmployeeParams,\n ReHireEmployeeParams,\n ListEmployeesParams,\n UpdateSalaryParams,\n AddAllowanceParams,\n RemoveAllowanceParams,\n AddDeductionParams,\n RemoveDeductionParams,\n UpdateBankDetailsParams,\n ProcessSalaryParams,\n ProcessBulkPayrollParams,\n PayrollHistoryParams,\n PayrollSummaryParams,\n ExportPayrollParams,\n ProcessSalaryResult,\n BulkPayrollResult,\n BulkPayrollProgress,\n PayrollSummaryResult,\n PaymentMethod,\n DeepPartial,\n Allowance,\n Deduction,\n GetPendingTaxParams,\n TaxSummaryParams,\n TaxSummaryResult,\n MarkTaxPaidParams,\n OperationContext,\n} from './types.js';\nimport { Container, type ModelsContainer, resetDefaultContainer } from './core/container.js';\nimport { EventBus, createEventBus, type PayrollEventMap, type PayrollEventType } from './core/events.js';\nimport { PluginManager, type PayrollPluginDefinition, type PluginContext } from './core/plugin.js';\nimport { IdempotencyManager, generatePayrollIdempotencyKey, type IdempotentResult } from './core/idempotency.js';\nimport { WebhookManager, type WebhookConfig } from './core/webhooks.js';\nimport { EmployeeFactory } from './factories/employee.factory.js';\nimport { createPayrollTransaction } from './factories/transaction.factory.js';\nimport { TAX_BRACKETS } from './config.js';\nimport { employee as employeeQuery, payroll as payrollQuery, toObjectId, isValidObjectId } from './utils/query-builders.js';\nimport { findEmployeeSecure, type SecureEmployeeLookupOptions } from './utils/employee-lookup.js';\nimport { resolveOrganizationId } from './utils/org-resolution.js';\nimport { getPayPeriod, addMonths } from './utils/date.js';\nimport { calculateGross, calculateNet, sumAllowances, sumDeductions, applyTaxBrackets } from './utils/calculation.js';\nimport { getLogger, setLogger } from './utils/logger.js';\nimport { NotInitializedError, EmployeeNotFoundError, DuplicatePayrollError, NotEligibleError, EmployeeTerminatedError, ValidationError } from './errors/index.js';\nimport { countWorkingDays, type AttendanceInput, type PayrollProcessingOptions } from './core/config.js';\nimport { EmployeeService, createEmployeeService } from './services/employee.service.js';\nimport { PayrollService, createPayrollService } from './services/payroll.service.js';\nimport { CompensationService, createCompensationService } from './services/compensation.service.js';\nimport { calculateSalaryBreakdown as calculateSalaryBreakdownPure } from './calculators/salary.calculator.js';\n\n// ============================================================================\n// Helper: Check plugin methods exist\n// ============================================================================\n\nfunction hasPluginMethod(obj: unknown, method: string): boolean {\n return typeof obj === 'object' && obj !== null && typeof (obj as Record<string, unknown>)[method] === 'function';\n}\n\nfunction assertPluginMethod(obj: unknown, method: string, context: string): void {\n if (!hasPluginMethod(obj, method)) {\n throw new Error(\n `Method '${method}' not found on employee. Did you forget to apply employeePlugin to your Employee schema? ` +\n `Context: ${context}`\n );\n }\n}\n\n// ============================================================================\n// Helper: Check if date is within range\n// ============================================================================\n\nfunction isEffectiveForPeriod(\n item: { effectiveFrom?: Date | null; effectiveTo?: Date | null },\n periodStart: Date,\n periodEnd: Date\n): boolean {\n const effectiveFrom = item.effectiveFrom ? new Date(item.effectiveFrom) : new Date(0);\n const effectiveTo = item.effectiveTo ? new Date(item.effectiveTo) : new Date('2099-12-31');\n \n // Item is effective if its range overlaps with the period\n return effectiveFrom <= periodEnd && effectiveTo >= periodStart;\n}\n\n// ============================================================================\n// Payroll Class\n// ============================================================================\n\n/**\n * Fully generic Payroll class for best-in-class TypeScript DX.\n *\n * Type parameters flow through to all methods, providing complete type inference.\n *\n * @typeParam TEmployee - Your Employee document type (extends EmployeeDocument)\n * @typeParam TPayrollRecord - Your PayrollRecord document type (extends PayrollRecordDocument)\n * @typeParam TTransaction - Your Transaction document type\n * @typeParam TAttendance - Your Attendance document type (optional)\n *\n * @example\n * ```typescript\n * // Full type inference\n * const payroll = createPayrollInstance()\n * .withModels({\n * EmployeeModel, // Model<MyEmployeeDoc>\n * PayrollRecordModel, // Model<MyPayrollDoc>\n * TransactionModel, // Model<MyTransactionDoc>\n * })\n * .build();\n *\n * // employee is typed as MyEmployeeDoc\n * const employee = await payroll.hire({ ... });\n * ```\n */\nexport class Payroll<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument,\n> implements PayrollInstance<TEmployee, TPayrollRecord, TTransaction, TAttendance> {\n [key: string]: unknown;\n private _container: Container<TEmployee, TPayrollRecord, TTransaction, TAttendance>;\n private _events: EventBus;\n private _plugins: PluginManager | null = null;\n private _initialized = false;\n\n // Service layer delegation (lazy initialization)\n private _employeeService?: EmployeeService;\n private _payrollService?: PayrollService;\n private _compensationService?: CompensationService;\n\n // Idempotency & Webhooks (Stripe-level features)\n private _idempotency: IdempotencyManager;\n private _webhooks: WebhookManager;\n\n /**\n * Create a new Payroll instance with its own container.\n * Each instance is isolated - no shared global state.\n */\n constructor() {\n // Each Payroll instance gets its own Container (no global singleton)\n this._container = new Container<TEmployee, TPayrollRecord, TTransaction, TAttendance>();\n this._events = createEventBus();\n this._idempotency = new IdempotencyManager();\n this._webhooks = new WebhookManager();\n\n // Connect webhooks to events\n this.setupWebhookBridge();\n }\n\n // ========================================\n // Initialization\n // ========================================\n\n /**\n * Initialize Payroll with models and configuration\n */\n initialize(config: PayrollInitConfig<TEmployee, TPayrollRecord, TTransaction, TAttendance>): this {\n const { EmployeeModel, PayrollRecordModel, TransactionModel, AttendanceModel, singleTenant, logger: customLogger, config: customConfig } = config;\n\n if (!EmployeeModel || !PayrollRecordModel || !TransactionModel) {\n throw new Error('EmployeeModel, PayrollRecordModel, and TransactionModel are required');\n }\n\n if (customLogger) {\n setLogger(customLogger);\n }\n\n // Initialize THIS instance's container (not the deprecated global one)\n this._container.initialize({\n models: {\n EmployeeModel,\n PayrollRecordModel,\n TransactionModel,\n AttendanceModel: AttendanceModel ?? null,\n },\n config: customConfig as Partial<HRMConfig>,\n singleTenant: singleTenant ?? null,\n logger: customLogger,\n });\n\n // Setup plugin manager\n const pluginContext: PluginContext = {\n payroll: this,\n events: this._events,\n logger: getLogger(),\n getConfig: <T = unknown>(key: string): T | undefined => {\n const config = this._container.getConfig();\n return (config as unknown as Record<string, T>)[key];\n },\n addHook: (event, handler) => this._events.on(event, handler),\n };\n this._plugins = new PluginManager(pluginContext);\n\n this._initialized = true;\n\n getLogger().info('Payroll initialized', {\n hasAttendanceIntegration: !!AttendanceModel,\n isSingleTenant: !!singleTenant,\n });\n\n return this;\n }\n\n /**\n * Check if initialized\n */\n isInitialized(): boolean {\n return this._initialized;\n }\n\n /**\n * Ensure initialized\n */\n private ensureInitialized(): void {\n if (!this._initialized) {\n throw new NotInitializedError();\n }\n }\n\n // ========================================\n // Helper Methods\n // ========================================\n\n /**\n * Resolve employeeId to ObjectId _id (respects explicit mode)\n * \n * Mode priority:\n * - 'objectId': Always treat as MongoDB ObjectId (direct _id lookup)\n * - 'businessId': Always treat as business ID (lookup by employeeId field)\n * - 'auto': Smart detection (ObjectId-like → _id, otherwise → businessId)\n */\n private async resolveEmployeeId(\n employeeId: ObjectIdLike | string,\n employeeIdMode: 'auto' | 'objectId' | 'businessId' | undefined,\n organizationId: ObjectIdLike,\n session?: ClientSession\n ): Promise<mongoose.Types.ObjectId> {\n const mode = employeeIdMode || 'auto';\n\n // Explicit mode: 'objectId' - Force treat as MongoDB _id\n if (mode === 'objectId') {\n return toObjectId(employeeId as ObjectIdLike);\n }\n\n // Explicit mode: 'businessId' - Force treat as business ID (even if looks like ObjectId)\n if (mode === 'businessId') {\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId,\n employeeIdMode: 'businessId',\n organizationId,\n session\n });\n return employee._id;\n }\n\n // Auto mode: Smart detection\n if (isValidObjectId(employeeId)) {\n return toObjectId(employeeId as ObjectIdLike);\n }\n\n // String that's not ObjectId-like - treat as business ID\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId,\n employeeIdMode: 'businessId',\n organizationId,\n session\n });\n\n return employee._id;\n }\n\n // ========================================\n // Lazy Service Initialization\n // ========================================\n\n /**\n * Get EmployeeService (lazy initialization)\n */\n private get employeeService(): EmployeeService {\n if (!this._employeeService) {\n this._employeeService = createEmployeeService(\n this.models.EmployeeModel as any,\n this.config\n );\n }\n return this._employeeService;\n }\n\n /**\n * Get PayrollService (lazy initialization)\n */\n private get payrollService(): PayrollService {\n if (!this._payrollService) {\n this._payrollService = createPayrollService(\n this.models.PayrollRecordModel as any,\n this.employeeService // Uses lazy getter\n );\n }\n return this._payrollService;\n }\n\n /**\n * Get CompensationService (lazy initialization)\n */\n private get compensationService(): CompensationService {\n if (!this._compensationService) {\n this._compensationService = createCompensationService(\n this.models.EmployeeModel as any\n );\n }\n return this._compensationService;\n }\n\n /**\n * Get models (strongly typed)\n */\n private get models(): ModelsContainer<TEmployee, TPayrollRecord, TTransaction, TAttendance> {\n this.ensureInitialized();\n return this._container.getModels();\n }\n\n /**\n * Get config\n */\n private get config(): HRMConfig {\n return this._container.getConfig();\n }\n\n /**\n * Get container (for org resolution and single-tenant detection)\n */\n private get container(): Container<TEmployee, TPayrollRecord, TTransaction, TAttendance> {\n return this._container;\n }\n\n // ========================================\n // Plugin System\n // ========================================\n\n /**\n * Register a plugin\n */\n async use(plugin: PayrollPluginDefinition): Promise<this> {\n this.ensureInitialized();\n await this._plugins!.register(plugin);\n return this;\n }\n\n /**\n * Subscribe to events\n */\n on<K extends keyof PayrollEventMap>(\n event: K,\n handler: (payload: PayrollEventMap[K]) => void | Promise<void>\n ): () => void {\n return this._events.on(event, handler);\n }\n\n /**\n * Register webhook URL for events (Stripe-style)\n */\n registerWebhook(config: WebhookConfig): void {\n this._webhooks.register(config);\n }\n\n /**\n * Unregister webhook URL\n */\n unregisterWebhook(url: string): void {\n this._webhooks.unregister(url);\n }\n\n /**\n * Get webhook delivery log\n */\n getWebhookDeliveries(options?: { event?: PayrollEventType; status?: 'pending' | 'sent' | 'failed'; limit?: number }) {\n return this._webhooks.getDeliveries(options);\n }\n\n /**\n * Setup webhook bridge (connects event bus to webhook manager)\n */\n private setupWebhookBridge(): void {\n // Forward all events to webhooks\n const events: PayrollEventType[] = [\n 'employee:hired',\n 'employee:terminated',\n 'employee:rehired',\n 'salary:updated',\n 'salary:processed',\n 'salary:failed',\n 'payroll:completed',\n 'payroll:exported',\n 'compensation:changed',\n 'milestone:achieved',\n 'tax:withheld',\n 'tax:paid',\n ];\n\n events.forEach((event) => {\n this._events.on(event, async (payload) => {\n await this._webhooks.send(event, payload);\n });\n });\n }\n\n // ========================================\n // Employment Lifecycle\n // ========================================\n\n /**\n * Hire a new employee\n */\n async hire(params: HireEmployeeParams): Promise<TEmployee> {\n this.ensureInitialized();\n const { userId, employment, compensation, bankDetails, context } = params;\n \n // Auto-inject organizationId in single-tenant mode\n const organizationId = params.organizationId ?? this._container.getOrganizationId();\n if (!organizationId) {\n throw new Error('organizationId is required (or configure single-tenant mode)');\n }\n\n // Validate identity based on config (keep in Payroll for public API validation)\n if (this.config.validation.requireUserId && !userId) {\n throw new ValidationError(\n 'userId is required (set validation.requireUserId: false to allow guest employees)',\n { field: 'userId' }\n );\n }\n\n // Ensure at least one identity field is provided\n if (!userId && !employment.email && !employment.employeeId) {\n throw new ValidationError(\n 'At least one identity field required: userId, email, or employeeId'\n );\n }\n\n const employee = await this.employeeService.create({\n userId,\n organizationId,\n employment,\n compensation: {\n ...compensation,\n currency: compensation.currency || this.config.payroll.defaultCurrency,\n },\n bankDetails,\n }, {\n session: context?.session,\n });\n\n // Emit high-level business event\n this._events.emitSync('employee:hired', {\n employee: {\n id: employee._id,\n employeeId: employee.employeeId,\n position: employee.position,\n department: employee.department,\n },\n organizationId: employee.organizationId,\n context,\n });\n\n // Note: Detailed logging already done by EmployeeService\n\n return employee as TEmployee;\n }\n\n /**\n * Update employment details\n * NOTE: Status changes to 'terminated' must use terminate() method\n */\n async updateEmployment(params: UpdateEmploymentParams): Promise<TEmployee> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, updates, context } = params;\n\n // CRITICAL: Resolve organizationId with smart detection\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'updateEmployment'\n });\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId,\n session\n });\n\n if (employee.status === 'terminated') {\n throw new EmployeeTerminatedError(employee.employeeId);\n }\n\n // IMPORTANT: Block direct status change to 'terminated' - must use terminate()\n if (updates.status === 'terminated') {\n throw new ValidationError(\n 'Cannot set status to terminated directly. Use the terminate() method instead to ensure proper history tracking.',\n { field: 'status' }\n );\n }\n\n const allowedUpdates = ['department', 'position', 'employmentType', 'status', 'workSchedule'];\n for (const [key, value] of Object.entries(updates)) {\n if (allowedUpdates.includes(key)) {\n (employee as unknown as Record<string, unknown>)[key] = value;\n }\n }\n\n await employee.save({ session });\n\n getLogger().info('Employee updated', {\n employeeId: employee.employeeId,\n updates: Object.keys(updates),\n });\n\n return employee as TEmployee;\n }\n\n /**\n * Terminate employee\n */\n async terminate(params: TerminateEmployeeParams): Promise<TEmployee> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, terminationDate = new Date(), reason = 'resignation', notes, context } = params;\n\n // CRITICAL: Resolve organizationId with smart detection\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'terminate'\n });\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId,\n session\n });\n\n // Check plugin method exists\n assertPluginMethod(employee, 'terminate', 'terminate()');\n\n (employee as unknown as { terminate: (reason: string, date: Date) => void }).terminate(reason, terminationDate);\n\n if (notes) {\n employee.notes = (employee.notes || '') + `\\nTermination: ${notes}`;\n }\n\n await employee.save({ session });\n\n // Emit event\n this._events.emitSync('employee:terminated', {\n employee: {\n id: employee._id,\n employeeId: employee.employeeId,\n },\n terminationDate,\n reason,\n organizationId: employee.organizationId,\n context,\n });\n\n getLogger().info('Employee terminated', {\n employeeId: employee.employeeId,\n reason,\n });\n\n return employee as TEmployee;\n }\n\n /**\n * Re-hire terminated employee\n */\n async reHire(params: ReHireEmployeeParams): Promise<TEmployee> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, hireDate = new Date(), position, department, compensation, context } = params;\n\n if (!this.config.employment.allowReHiring) {\n throw new Error('Re-hiring is not enabled');\n }\n\n // CRITICAL: Resolve organizationId with smart detection\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'reHire'\n });\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId,\n session\n });\n\n // Check plugin method exists\n assertPluginMethod(employee, 'reHire', 'reHire()');\n\n (employee as unknown as { reHire: (date: Date, position?: string, department?: string) => void }).reHire(hireDate, position, department);\n\n if (compensation) {\n employee.compensation = { ...employee.compensation, ...compensation } as typeof employee.compensation;\n }\n\n await employee.save({ session });\n\n // Emit event\n this._events.emitSync('employee:rehired', {\n employee: {\n id: employee._id,\n employeeId: employee.employeeId,\n position: employee.position,\n },\n organizationId: employee.organizationId,\n context,\n });\n\n getLogger().info('Employee re-hired', {\n employeeId: employee.employeeId,\n });\n\n return employee as TEmployee;\n }\n\n /**\n * Get employee by ID\n */\n async getEmployee(params: {\n employeeId: ObjectIdLike | string;\n employeeIdMode?: 'auto' | 'objectId' | 'businessId';\n organizationId?: ObjectIdLike;\n populateUser?: boolean;\n session?: ClientSession;\n context?: OperationContext;\n }): Promise<TEmployee> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, populateUser = true, session, context } = params;\n\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'getEmployee'\n });\n\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId,\n employeeIdMode, // Explicit disambiguation if needed\n organizationId,\n session,\n populate: populateUser ? 'userId' : undefined\n });\n\n return employee as TEmployee;\n }\n\n /**\n * Get employee by flexible identity (userId, employeeId, or email)\n *\n * Supports multiple identity modes with automatic fallback:\n * - 'userId': Lookup by user account ID (traditional)\n * - 'employeeId': Lookup by human-readable employee ID (e.g., \"EMP-001\")\n * - 'email': Lookup by email address (for guest employees)\n * - 'any': Try all modes until found\n *\n * @example\n * // By user ID (traditional)\n * const emp = await payroll.getEmployeeByIdentity({\n * identity: userId,\n * organizationId,\n * mode: 'userId'\n * });\n *\n * // By employee ID (human-readable)\n * const emp = await payroll.getEmployeeByIdentity({\n * identity: 'EMP-001',\n * organizationId,\n * mode: 'employeeId'\n * });\n *\n * // By email (guest employees)\n * const emp = await payroll.getEmployeeByIdentity({\n * identity: 'driver@example.com',\n * organizationId,\n * mode: 'email'\n * });\n *\n * // Auto-detect (uses config.identityMode + fallbacks)\n * const emp = await payroll.getEmployeeByIdentity({\n * identity: 'EMP-001',\n * organizationId\n * });\n */\n async getEmployeeByIdentity(params: {\n identity: ObjectIdLike | string;\n organizationId?: ObjectIdLike;\n mode?: import('./types.js').EmployeeIdentityMode;\n populateUser?: boolean;\n session?: ClientSession;\n }): Promise<TEmployee> {\n this.ensureInitialized();\n\n const {\n identity,\n mode = this.config.validation.identityMode,\n populateUser = true,\n session\n } = params;\n\n // Auto-inject organizationId in single-tenant mode\n const organizationId = params.organizationId ?? this._container.getOrganizationId();\n if (!organizationId) {\n throw new Error('organizationId is required (or configure single-tenant mode)');\n }\n\n const orgId = toObjectId(organizationId);\n const modes: Array<import('./types.js').EmployeeIdentityMode> = [\n mode,\n ...this.config.validation.identityFallbacks\n ];\n\n for (const currentMode of modes) {\n let employee: TEmployee | null = null;\n\n switch (currentMode) {\n case 'userId': {\n // Lookup by userId (traditional pattern)\n try {\n const userId = toObjectId(identity);\n let query = this.models.EmployeeModel.findOne({\n userId,\n organizationId: orgId\n });\n if (session) query = query.session(session);\n if (populateUser) query = query.populate('userId', 'name email phone');\n employee = await query as TEmployee | null;\n } catch {\n // Invalid ObjectId, skip this mode\n }\n break;\n }\n\n case 'employeeId': {\n // Lookup by employeeId (human-readable)\n let query = this.models.EmployeeModel.findOne({\n employeeId: identity.toString(),\n organizationId: orgId\n });\n if (session) query = query.session(session);\n if (populateUser) query = query.populate('userId', 'name email phone');\n employee = await query as TEmployee | null;\n break;\n }\n\n case 'email': {\n // Lookup by email (guest employees)\n const email = identity.toString().toLowerCase().trim();\n let query = this.models.EmployeeModel.findOne({\n email,\n organizationId: orgId\n });\n if (session) query = query.session(session);\n if (populateUser) query = query.populate('userId', 'name email phone');\n employee = await query as TEmployee | null;\n break;\n }\n\n case 'any': {\n // Try all modes: userId → employeeId → email\n const anyModes: Array<import('./types.js').EmployeeIdentityMode> = ['userId', 'employeeId', 'email'];\n for (const tryMode of anyModes) {\n try {\n return await this.getEmployeeByIdentity({\n identity,\n organizationId,\n mode: tryMode,\n populateUser,\n session\n });\n } catch {\n // Continue to next mode\n }\n }\n break;\n }\n }\n\n if (employee) {\n return employee;\n }\n }\n\n throw new EmployeeNotFoundError(\n `Employee not found with identity: ${identity} (tried modes: ${modes.join(', ')})`\n );\n }\n\n /**\n * List employees\n */\n async listEmployees(params: ListEmployeesParams): Promise<{\n docs: TEmployee[];\n totalDocs: number;\n page: number;\n limit: number;\n }> {\n this.ensureInitialized();\n const { organizationId, filters = {}, pagination = {} } = params;\n\n let queryBuilder = employeeQuery().forOrganization(organizationId);\n\n if (filters.status) queryBuilder = queryBuilder.withStatus(filters.status);\n if (filters.department) queryBuilder = queryBuilder.inDepartment(filters.department);\n if (filters.employmentType) queryBuilder = queryBuilder.withEmploymentType(filters.employmentType);\n if (filters.minSalary) queryBuilder = queryBuilder.withMinSalary(filters.minSalary);\n if (filters.maxSalary) queryBuilder = queryBuilder.withMaxSalary(filters.maxSalary);\n\n const query = queryBuilder.build();\n const page = pagination.page || 1;\n const limit = pagination.limit || 20;\n const sort = pagination.sort || { createdAt: -1 };\n\n const [docs, totalDocs] = await Promise.all([\n this.models.EmployeeModel.find(query)\n .populate('userId', 'name email phone')\n .sort(sort)\n .skip((page - 1) * limit)\n .limit(limit),\n this.models.EmployeeModel.countDocuments(query),\n ]);\n\n return { docs: docs as unknown as TEmployee[], totalDocs, page, limit };\n }\n\n // ========================================\n // Compensation Management\n // ========================================\n\n /**\n * Update employee salary\n */\n async updateSalary(params: UpdateSalaryParams): Promise<TEmployee> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, compensation, effectiveFrom = new Date(), context } = params;\n\n // CRITICAL: Resolve organizationId with smart detection\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'updateSalary'\n });\n\n // Resolve employeeId to ObjectId if it's a string business ID\n const resolvedEmployeeId = await this.resolveEmployeeId(employeeId, employeeIdMode, organizationId, context?.session);\n\n // Get old salary for event (before update)\n const oldEmployee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId: resolvedEmployeeId,\n employeeIdMode: 'objectId', // We resolved it to ObjectId\n organizationId,\n session: context?.session\n });\n\n if (oldEmployee.status === 'terminated') {\n throw new EmployeeTerminatedError(oldEmployee.employeeId);\n }\n\n const oldSalary = oldEmployee.compensation.netSalary;\n\n const employee = await this.employeeService.updateCompensation(\n resolvedEmployeeId,\n organizationId,\n {\n ...compensation,\n effectiveFrom,\n },\n { session: context?.session }\n );\n\n // Emit high-level business event\n this._events.emitSync('salary:updated', {\n employee: { id: employee._id, employeeId: employee.employeeId },\n previousSalary: oldSalary || 0,\n newSalary: employee.compensation.netSalary || 0,\n effectiveFrom,\n organizationId: employee.organizationId,\n context,\n });\n\n // Note: Detailed logging already done by EmployeeService\n\n return employee as TEmployee;\n }\n\n /**\n * Add allowance to employee\n */\n async addAllowance(params: AddAllowanceParams): Promise<TEmployee> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, type, amount, isPercentage, value, taxable = true, recurring = true, effectiveFrom = new Date(), effectiveTo, context } = params;\n\n // CRITICAL: Resolve organizationId with smart detection\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'addAllowance'\n });\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId,\n session\n });\n\n if (employee.status === 'terminated') {\n throw new EmployeeTerminatedError(employee.employeeId);\n }\n\n if (!employee.compensation.allowances) {\n employee.compensation.allowances = [];\n }\n\n employee.compensation.allowances.push({\n type,\n name: type,\n amount,\n isPercentage,\n value,\n taxable,\n recurring,\n effectiveFrom,\n effectiveTo,\n });\n\n if (hasPluginMethod(employee, 'updateSalaryCalculations')) {\n (employee as unknown as { updateSalaryCalculations: () => void }).updateSalaryCalculations();\n }\n await employee.save({ session });\n\n getLogger().info('Allowance added', {\n employeeId: employee.employeeId,\n type,\n amount,\n });\n\n return employee as TEmployee;\n }\n\n /**\n * Remove allowance from employee\n */\n async removeAllowance(params: RemoveAllowanceParams): Promise<TEmployee> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, type, context } = params;\n\n // CRITICAL: Resolve organizationId with smart detection\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'removeAllowance'\n });\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId,\n session\n });\n\n const before = employee.compensation.allowances?.length || 0;\n \n if (hasPluginMethod(employee, 'removeAllowance')) {\n (employee as unknown as { removeAllowance: (type: string) => void }).removeAllowance(type);\n } else {\n // Fallback if plugin not applied\n if (employee.compensation.allowances) {\n employee.compensation.allowances = employee.compensation.allowances.filter(\n (a: Allowance) => a.type !== type\n );\n }\n }\n \n const after = employee.compensation.allowances?.length || 0;\n\n if (before === after) {\n throw new Error(`Allowance type '${type}' not found`);\n }\n\n await employee.save({ session });\n\n getLogger().info('Allowance removed', {\n employeeId: employee.employeeId,\n type,\n });\n\n return employee as TEmployee;\n }\n\n /**\n * Add deduction to employee\n */\n async addDeduction(params: AddDeductionParams): Promise<TEmployee> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, type, amount, isPercentage, value, auto = false, recurring = true, description, effectiveFrom = new Date(), effectiveTo, context } = params;\n\n // CRITICAL: Resolve organizationId with smart detection\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'addDeduction'\n });\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId,\n session\n });\n\n if (employee.status === 'terminated') {\n throw new EmployeeTerminatedError(employee.employeeId);\n }\n\n if (!employee.compensation.deductions) {\n employee.compensation.deductions = [];\n }\n\n employee.compensation.deductions.push({\n type,\n name: type,\n amount,\n isPercentage,\n value,\n auto,\n recurring,\n description,\n effectiveFrom,\n effectiveTo,\n });\n\n if (hasPluginMethod(employee, 'updateSalaryCalculations')) {\n (employee as unknown as { updateSalaryCalculations: () => void }).updateSalaryCalculations();\n }\n await employee.save({ session });\n\n getLogger().info('Deduction added', {\n employeeId: employee.employeeId,\n type,\n amount,\n auto,\n });\n\n return employee as TEmployee;\n }\n\n /**\n * Remove deduction from employee\n */\n async removeDeduction(params: RemoveDeductionParams): Promise<TEmployee> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, type, context } = params;\n\n // CRITICAL: Resolve organizationId with smart detection\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'removeDeduction'\n });\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId,\n session\n });\n\n const before = employee.compensation.deductions?.length || 0;\n \n if (hasPluginMethod(employee, 'removeDeduction')) {\n (employee as unknown as { removeDeduction: (type: string) => void }).removeDeduction(type);\n } else {\n // Fallback if plugin not applied\n if (employee.compensation.deductions) {\n employee.compensation.deductions = employee.compensation.deductions.filter(\n (d: Deduction) => d.type !== type\n );\n }\n }\n \n const after = employee.compensation.deductions?.length || 0;\n\n if (before === after) {\n throw new Error(`Deduction type '${type}' not found`);\n }\n\n await employee.save({ session });\n\n getLogger().info('Deduction removed', {\n employeeId: employee.employeeId,\n type,\n });\n\n return employee as TEmployee;\n }\n\n /**\n * Update bank details\n */\n async updateBankDetails(params: UpdateBankDetailsParams): Promise<TEmployee> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, bankDetails, context } = params;\n\n // CRITICAL: Resolve organizationId with smart detection\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'updateBankDetails'\n });\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId,\n session\n });\n\n employee.bankDetails = { ...employee.bankDetails, ...bankDetails };\n await employee.save({ session });\n\n getLogger().info('Bank details updated', {\n employeeId: employee.employeeId,\n });\n\n return employee as TEmployee;\n }\n\n // ========================================\n // Payroll Processing\n // ========================================\n\n /**\n * Process salary for single employee\n * \n * ATOMICITY: This method creates its own transaction if none provided.\n * All database operations (PayrollRecord, Transaction, Employee stats) \n * are atomic - either all succeed or all fail.\n */\n async processSalary(\n params: ProcessSalaryParams\n ): Promise<ProcessSalaryResult<TEmployee, TPayrollRecord, TTransaction>> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, month, year, paymentDate = new Date(), paymentMethod = 'bank', attendance, options, context, idempotencyKey } = params;\n\n // CRITICAL: Resolve organizationId with smart detection\n const organizationId = resolveOrganizationId({\n explicit: explicitOrgId,\n context,\n container: this.container,\n operation: 'processSalary'\n });\n\n // Idempotency: Generate or use provided key\n const resolvedEmployeeId = await this.resolveEmployeeId(employeeId, employeeIdMode, organizationId, context?.session);\n const idempotentKey = idempotencyKey || generatePayrollIdempotencyKey(organizationId, resolvedEmployeeId, month, year);\n\n // Check idempotency cache (Stripe-style)\n const cached = this._idempotency.get<ProcessSalaryResult<TEmployee, TPayrollRecord, TTransaction>>(idempotentKey);\n if (cached) {\n getLogger().info('Returning cached payroll result (idempotent)', {\n idempotencyKey: idempotentKey,\n cachedAt: cached.createdAt,\n });\n return cached.value;\n }\n\n // CRITICAL: Use provided session OR create a new transaction\n const providedSession = context?.session;\n const session = providedSession || await mongoose.startSession();\n const shouldManageTransaction = !providedSession && session != null;\n\n try {\n if (shouldManageTransaction) {\n await session.startTransaction();\n }\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId,\n session,\n populate: 'userId'\n });\n\n // Check eligibility - with plugin method verification\n const canReceive = hasPluginMethod(employee, 'canReceiveSalary')\n ? (employee as unknown as { canReceiveSalary: () => boolean }).canReceiveSalary()\n : (employee.status === 'active' && (employee.compensation?.baseAmount || 0) > 0);\n\n if (!canReceive) {\n throw new NotEligibleError('Employee is not eligible to receive salary');\n }\n\n // Check for existing payroll\n // ✅ Use employee._id (not employeeId param) since we've resolved the employee\n const existingQuery = payrollQuery()\n .forEmployee(employee._id)\n .forPeriod(month, year)\n .whereIn('status', ['paid', 'processing'])\n .build();\n\n let existingRecordQuery = this.models.PayrollRecordModel.findOne(existingQuery);\n if (session) existingRecordQuery = existingRecordQuery.session(session);\n const existingRecord = await existingRecordQuery;\n \n if (existingRecord) {\n throw new DuplicatePayrollError(employee.employeeId, month, year);\n }\n\n const period = { ...getPayPeriod(month, year), payDate: paymentDate };\n const breakdown = await this.calculateSalaryBreakdown(employee, period, { attendance, options }, session);\n\n // Handle userId - could be ObjectId, populated doc, or null\n // Extract userId if present (optional for guest employees)\n const userIdValue = employee.userId\n ? (typeof employee.userId === 'object' && '_id' in employee.userId\n ? (employee.userId as { _id: mongoose.Types.ObjectId })._id\n : (employee.userId as mongoose.Types.ObjectId))\n : undefined;\n\n // Use type assertions for generic model create operations\n const [payrollRecord] = await (this.models.PayrollRecordModel as Model<PayrollRecordDocument>).create([{\n organizationId: employee.organizationId,\n employeeId: employee._id,\n userId: userIdValue,\n period,\n breakdown,\n status: 'processing',\n paymentMethod,\n processedAt: new Date(),\n processedBy: context?.userId ? toObjectId(context.userId) : undefined,\n }], session ? { session } : {}) as unknown as [TPayrollRecord & PayrollRecordDocument];\n\n // Aligned with @classytic/shared-types ITransactionCreateInput\n const [transaction] = await (this.models.TransactionModel as Model<AnyDocument>).create([{\n organizationId: employee.organizationId,\n\n // Classification (shared-types)\n type: 'salary',\n flow: 'outflow',\n tags: ['recurring', 'payroll', 'monthly'],\n status: 'completed',\n\n // Amounts (shared-types convention: amount = gross, net = after deductions)\n amount: breakdown.grossSalary, // Gross amount\n net: breakdown.netSalary, // Net after deductions\n currency: employee.compensation.currency || 'USD', // From employee, not hardcoded\n fee: 0,\n tax: breakdown.taxAmount || 0,\n\n // Tax details (shared-types structure)\n taxDetails: breakdown.taxAmount && breakdown.taxAmount > 0 ? {\n type: 'income_tax',\n rate: breakdown.grossSalary > 0 ? breakdown.taxAmount / breakdown.grossSalary : 0,\n jurisdiction: undefined, // App-controlled (can be added via metadata)\n } : undefined,\n\n // Payment (flexible method - users can pass any string)\n method: paymentMethod, // 'bank_transfer', 'cash', 'check', 'mobile_wallet', etc.\n date: paymentDate,\n\n // Parties (shared-types)\n employeeId: employee._id,\n customerId: employee.userId as mongoose.Types.ObjectId,\n processedBy: context?.userId ? toObjectId(context.userId) : undefined,\n\n // ✅ UNIFIED: Breakdown structure\n breakdown: {\n base: breakdown.baseAmount,\n additions: breakdown.allowances.map(a => ({\n type: a.type,\n amount: a.amount,\n description: a.type,\n isTaxable: a.taxable\n })),\n deductions: breakdown.deductions.map(d => ({\n type: d.type,\n amount: d.amount,\n description: d.description\n })),\n period: {\n month,\n year,\n start: new Date(year, month - 1, 1),\n end: new Date(year, month, 0)\n },\n workingDays: breakdown.workingDays ? {\n expected: breakdown.workingDays,\n actual: breakdown.actualDays || breakdown.workingDays\n } : undefined\n },\n\n // References (shared-types)\n sourceId: payrollRecord._id,\n sourceModel: 'PayrollRecord',\n\n // Idempotency (Stripe-style, shared-types)\n idempotencyKey: idempotentKey,\n\n // Timestamps (shared-types)\n processedAt: paymentDate,\n completedAt: paymentDate,\n\n // Description & metadata\n description: `Salary payment - ${(employee.userId as { name?: string })?.name || employee.employeeId} (${month}/${year})`,\n notes: breakdown.proRatedAmount ? `Pro-rated: ${breakdown.actualDays}/${breakdown.workingDays} days` : undefined,\n metadata: {\n employeeId: employee.employeeId,\n email: (employee as any).email, // For guest employees\n payrollRecordId: payrollRecord._id.toString(),\n },\n }], session ? { session } : {}) as unknown as [TTransaction & { _id: mongoose.Types.ObjectId }];\n\n // Update payroll record with transaction reference\n (payrollRecord as PayrollRecordDocument).transactionId = transaction._id;\n (payrollRecord as PayrollRecordDocument).status = 'paid';\n (payrollRecord as PayrollRecordDocument).paidAt = paymentDate;\n await (payrollRecord as PayrollRecordDocument).save(session ? { session } : {});\n\n // Create Tax Withholding Records (if tax > 0 and model provided)\n if (breakdown.taxAmount && breakdown.taxAmount > 0 && this.models.TaxWithholdingModel) {\n const { TaxWithholdingService } = await import('./services/tax-withholding.service.js');\n const taxService = new TaxWithholdingService(\n this.models.TaxWithholdingModel,\n this.models.TransactionModel as any,\n this._events\n );\n\n await taxService.createFromBreakdown({\n organizationId: employee.organizationId,\n employeeId: employee._id,\n userId: employee.userId as mongoose.Types.ObjectId | undefined,\n payrollRecordId: payrollRecord._id,\n transactionId: transaction._id,\n period: {\n month,\n year,\n startDate: period.startDate,\n endDate: period.endDate,\n payDate: paymentDate,\n },\n breakdown,\n currency: 'BDT',\n session,\n context,\n });\n }\n\n // Update employee payroll stats\n await this.updatePayrollStats(employee, breakdown.netSalary, paymentDate, session);\n\n // Commit transaction if we created it\n if (shouldManageTransaction) {\n await session.commitTransaction();\n }\n\n // Emit event (after commit to ensure data is persisted)\n this._events.emitSync('salary:processed', {\n employee: {\n id: employee._id,\n employeeId: employee.employeeId,\n name: (employee.userId as { name?: string })?.name,\n },\n payroll: {\n id: payrollRecord._id,\n period: { month, year },\n grossAmount: breakdown.grossSalary,\n netAmount: breakdown.netSalary,\n },\n transactionId: transaction._id,\n organizationId: employee.organizationId,\n context,\n });\n\n getLogger().info('Salary processed', {\n employeeId: employee.employeeId,\n month,\n year,\n amount: breakdown.netSalary,\n idempotencyKey: idempotentKey,\n });\n\n const result = {\n payrollRecord: payrollRecord as unknown as TPayrollRecord,\n transaction: transaction as unknown as TTransaction,\n employee: employee as unknown as TEmployee,\n };\n\n // Cache result for idempotency (Stripe-style)\n this._idempotency.set(idempotentKey, result);\n\n return result;\n\n } catch (error) {\n // Rollback transaction if we created it\n if (shouldManageTransaction && session?.inTransaction()) {\n await session.abortTransaction();\n }\n throw error;\n } finally {\n // End session if we created it\n if (shouldManageTransaction && session) {\n await session.endSession();\n }\n }\n }\n\n /**\n * Process bulk payroll for multiple employees\n *\n * ATOMICITY STRATEGY: Each employee is processed in its own transaction.\n * This allows partial success - some employees can succeed while others fail.\n * Failed employees don't affect successful ones.\n *\n * NEW FEATURES (all optional, backward compatible):\n * - Progress tracking via onProgress callback\n * - Cancellation support via AbortSignal\n * - Batch processing to prevent resource exhaustion\n * - Concurrency control for parallel processing\n *\n * @example Basic usage (unchanged)\n * ```typescript\n * const result = await payroll.processBulkPayroll({\n * organizationId, month, year\n * });\n * ```\n *\n * @example With progress tracking\n * ```typescript\n * await payroll.processBulkPayroll({\n * organizationId, month, year,\n * onProgress: (p) => console.log(`${p.percentage}% done`)\n * });\n * ```\n *\n * @example With job queue integration\n * ```typescript\n * await payroll.processBulkPayroll({\n * organizationId, month, year,\n * batchSize: 10,\n * onProgress: async (p) => {\n * await Job.findByIdAndUpdate(jobId, { progress: p });\n * }\n * });\n * ```\n *\n * @example With cancellation\n * ```typescript\n * const controller = new AbortController();\n * payroll.processBulkPayroll({ signal: controller.signal });\n * // Later: controller.abort();\n * ```\n */\n async processBulkPayroll(params: ProcessBulkPayrollParams): Promise<BulkPayrollResult> {\n this.ensureInitialized();\n const {\n organizationId,\n month,\n year,\n employeeIds = [],\n paymentDate = new Date(),\n paymentMethod = 'bank',\n options,\n context,\n // Progress and control params\n onProgress,\n signal,\n batchSize = 10,\n batchDelay = 0,\n concurrency = 1,\n useStreaming,\n } = params;\n\n const query: Record<string, unknown> = { organizationId: toObjectId(organizationId), status: 'active' };\n if (employeeIds.length > 0) {\n query._id = { $in: employeeIds.map(toObjectId) };\n }\n\n // Auto-detect streaming: use for >10k employees\n const employeeCount = await this.models.EmployeeModel.countDocuments(query);\n const shouldStream = useStreaming ?? (employeeCount > 10000);\n\n // Use streaming for large datasets\n if (shouldStream) {\n return this.processBulkPayrollStreaming({\n query,\n organizationId,\n month,\n year,\n paymentDate,\n paymentMethod,\n options,\n context,\n signal,\n batchSize,\n batchDelay,\n concurrency,\n onProgress,\n total: employeeCount,\n });\n }\n\n // Original implementation for smaller datasets\n const employees = await this.models.EmployeeModel.find(query);\n const total = employees.length;\n\n const results: BulkPayrollResult = {\n successful: [],\n failed: [],\n total,\n };\n\n // Helper to report progress\n const reportProgress = async (currentEmployee?: string) => {\n if (onProgress) {\n const processed = results.successful.length + results.failed.length;\n await onProgress({\n processed,\n total,\n successful: results.successful.length,\n failed: results.failed.length,\n currentEmployee,\n percentage: total > 0 ? Math.round((processed / total) * 100) : 0,\n });\n }\n };\n\n // Process in batches\n for (let i = 0; i < employees.length; i += batchSize) {\n // Check for cancellation before each batch\n if (signal?.aborted) {\n getLogger().warn('Bulk payroll cancelled', {\n organizationId: organizationId.toString(),\n processed: results.successful.length + results.failed.length,\n total,\n });\n throw new Error('Payroll processing cancelled by user');\n }\n\n const batch = employees.slice(i, i + batchSize);\n\n if (concurrency === 1) {\n // SEQUENTIAL (default, safest)\n for (const employee of batch) {\n if (signal?.aborted) throw new Error('Payroll processing cancelled by user');\n\n try {\n const result = await this.processSalary({\n employeeId: employee._id,\n organizationId,\n month,\n year,\n paymentDate,\n paymentMethod,\n options,\n context: { ...context, session: undefined },\n });\n\n results.successful.push({\n employeeId: employee.employeeId,\n amount: result.payrollRecord.breakdown.netSalary,\n transactionId: result.transaction._id,\n });\n } catch (error) {\n results.failed.push({\n employeeId: employee.employeeId,\n error: (error as Error).message,\n });\n\n getLogger().error('Failed to process salary', {\n employeeId: employee.employeeId,\n error: (error as Error).message,\n });\n }\n\n await reportProgress(employee.employeeId);\n }\n } else {\n // CONCURRENT (faster, more resources)\n const batchResults = await Promise.allSettled(\n batch.map((employee) =>\n this.processSalary({\n employeeId: employee._id,\n organizationId,\n month,\n year,\n paymentDate,\n paymentMethod,\n options,\n context: { ...context, session: undefined },\n }).then((result) => ({ employee, result }))\n )\n );\n\n // Aggregate batch results\n for (let j = 0; j < batchResults.length; j++) {\n const batchResult = batchResults[j];\n const employee = batch[j];\n\n if (batchResult.status === 'fulfilled') {\n results.successful.push({\n employeeId: batchResult.value.employee.employeeId,\n amount: batchResult.value.result.payrollRecord.breakdown.netSalary,\n transactionId: batchResult.value.result.transaction._id,\n });\n } else {\n results.failed.push({\n employeeId: employee.employeeId,\n error: (batchResult.reason as Error).message || 'Unknown error',\n });\n\n getLogger().error('Failed to process salary (concurrent)', {\n employeeId: employee.employeeId,\n error: (batchResult.reason as Error).message,\n });\n }\n }\n\n await reportProgress();\n }\n\n // Pause between batches\n if (batchDelay > 0 && i + batchSize < employees.length) {\n await new Promise((resolve) => setTimeout(resolve, batchDelay));\n }\n }\n\n // Emit completed event\n this._events.emitSync('payroll:completed', {\n organizationId: toObjectId(organizationId),\n period: { month, year },\n summary: {\n total: results.total,\n successful: results.successful.length,\n failed: results.failed.length,\n totalAmount: results.successful.reduce((sum, r) => sum + r.amount, 0),\n },\n context,\n });\n\n getLogger().info('Bulk payroll processed', {\n organizationId: organizationId.toString(),\n month,\n year,\n total: results.total,\n successful: results.successful.length,\n failed: results.failed.length,\n concurrency,\n batchSize,\n });\n\n return results;\n }\n\n /**\n * Stream-based bulk payroll processing for millions of employees.\n * Uses MongoDB cursors to avoid loading everything into memory.\n *\n * @private\n */\n private async processBulkPayrollStreaming(params: {\n query: Record<string, unknown>;\n organizationId: ObjectIdLike;\n month: number;\n year: number;\n paymentDate: Date;\n paymentMethod?: string;\n options?: any;\n context?: any;\n signal?: AbortSignal;\n batchSize: number;\n batchDelay: number;\n concurrency: number;\n onProgress?: (progress: BulkPayrollProgress) => void | Promise<void>;\n total: number;\n }): Promise<BulkPayrollResult> {\n const {\n query,\n organizationId,\n month,\n year,\n paymentDate,\n paymentMethod,\n options,\n context,\n signal,\n batchSize,\n batchDelay,\n concurrency,\n onProgress,\n total,\n } = params;\n\n const startTime = Date.now();\n const results: BulkPayrollResult = {\n successful: [],\n failed: [],\n total,\n };\n\n // Create cursor (streams employees one at a time)\n const cursor = this.models.EmployeeModel.find(query).cursor();\n\n let processed = 0;\n let batchCount = 0;\n const batchPromises: Array<Promise<void>> = [];\n\n // Import p-limit for concurrency control\n const { default: pLimit } = await import('p-limit');\n const limit = pLimit(concurrency);\n\n // Progress reporting helper\n const reportProgress = async (currentEmployee?: string) => {\n if (onProgress) {\n await onProgress({\n processed,\n total,\n successful: results.successful.length,\n failed: results.failed.length,\n currentEmployee,\n percentage: total > 0 ? Math.round((processed / total) * 100) : 0,\n });\n }\n };\n\n // Stream employees\n for await (const employee of cursor) {\n // Check cancellation\n if (signal?.aborted) {\n cursor.close();\n getLogger().warn('Streaming bulk payroll cancelled', {\n processed,\n total,\n });\n throw new Error('Payroll processing cancelled by user');\n }\n\n // Add to worker pool\n const promise = limit(async () => {\n try {\n const result = await this.processSalary({\n employeeId: employee._id,\n organizationId,\n month,\n year,\n paymentDate,\n paymentMethod: paymentMethod as PaymentMethod | undefined,\n options,\n context: { ...context, session: undefined },\n });\n\n results.successful.push({\n employeeId: employee.employeeId,\n amount: result.payrollRecord.breakdown.netSalary,\n transactionId: result.transaction._id,\n });\n } catch (error) {\n results.failed.push({\n employeeId: employee.employeeId,\n error: (error as Error).message,\n });\n\n getLogger().error('Failed to process salary (streaming)', {\n employeeId: employee.employeeId,\n error: (error as Error).message,\n });\n }\n });\n\n batchPromises.push(promise);\n processed++;\n\n // Batch completion\n if (processed % batchSize === 0) {\n await Promise.all(batchPromises);\n batchPromises.length = 0;\n batchCount++;\n\n await reportProgress();\n\n // Batch delay\n if (batchDelay > 0 && processed < total) {\n await new Promise((resolve) => setTimeout(resolve, batchDelay));\n }\n }\n }\n\n // Wait for final batch\n if (batchPromises.length > 0) {\n await Promise.all(batchPromises);\n await reportProgress();\n }\n\n // Emit completion event\n this._events.emitSync('payroll:completed', {\n organizationId: toObjectId(query.organizationId as ObjectIdLike),\n period: { month, year },\n summary: {\n total: results.total,\n successful: results.successful.length,\n failed: results.failed.length,\n totalAmount: results.successful.reduce((sum, r) => sum + r.amount, 0),\n },\n context,\n });\n\n const duration = Date.now() - startTime;\n\n getLogger().info('Streaming bulk payroll completed', {\n total: results.total,\n successful: results.successful.length,\n failed: results.failed.length,\n duration,\n concurrency,\n batchSize,\n });\n\n return results;\n }\n\n /**\n * Get payroll history\n */\n async payrollHistory(params: PayrollHistoryParams): Promise<TPayrollRecord[]> {\n this.ensureInitialized();\n const { employeeId, employeeIdMode, organizationId, month, year, status, pagination = {} } = params;\n\n // Resolve employeeId to ObjectId _id if it's a string business ID\n // Respect explicit employeeIdMode hint before auto-detection\n let resolvedEmployeeId: mongoose.Types.ObjectId | undefined;\n if (employeeId) {\n const mode = employeeIdMode || 'auto';\n const shouldTreatAsObjectId =\n mode === 'objectId' ||\n (mode === 'auto' && isValidObjectId(employeeId));\n\n const shouldTreatAsBusinessId =\n mode === 'businessId' ||\n (mode === 'auto' && !isValidObjectId(employeeId));\n\n if (shouldTreatAsObjectId) {\n resolvedEmployeeId = toObjectId(employeeId as ObjectIdLike);\n } else if (shouldTreatAsBusinessId) {\n // String business ID - need to resolve to ObjectId _id\n if (!organizationId) {\n throw new Error('payrollHistory requires organizationId when using string employeeId');\n }\n const employee = await findEmployeeSecure(this.models.EmployeeModel, {\n employeeId,\n employeeIdMode,\n organizationId\n });\n resolvedEmployeeId = employee._id;\n }\n }\n\n let queryBuilder = payrollQuery();\n if (resolvedEmployeeId) queryBuilder = queryBuilder.forEmployee(resolvedEmployeeId);\n if (organizationId) queryBuilder = queryBuilder.forOrganization(organizationId);\n if (month || year) queryBuilder = queryBuilder.forPeriod(month, year);\n if (status) queryBuilder = queryBuilder.withStatus(status);\n\n const query = queryBuilder.build();\n const page = pagination.page || 1;\n const limit = pagination.limit || 20;\n const sort = pagination.sort || { 'period.year': -1, 'period.month': -1 };\n\n return this.models.PayrollRecordModel.find(query)\n .populate('employeeId', 'employeeId position department')\n .populate('userId', 'name email')\n .populate('transactionId', 'amount method status date')\n .sort(sort)\n .skip((page - 1) * limit)\n .limit(limit);\n }\n\n /**\n * Get payroll summary\n */\n async payrollSummary(params: PayrollSummaryParams): Promise<PayrollSummaryResult> {\n this.ensureInitialized();\n const { organizationId, month, year } = params;\n\n const query: Record<string, unknown> = { organizationId: toObjectId(organizationId) };\n if (month) query['period.month'] = month;\n if (year) query['period.year'] = year;\n\n const [summary] = await this.models.PayrollRecordModel.aggregate([\n { $match: query },\n {\n $group: {\n _id: null,\n totalGross: { $sum: '$breakdown.grossSalary' },\n totalNet: { $sum: '$breakdown.netSalary' },\n totalDeductions: { $sum: { $sum: '$breakdown.deductions.amount' } },\n totalTax: { $sum: { $ifNull: ['$breakdown.taxAmount', 0] } },\n employeeCount: { $sum: 1 },\n paidCount: { $sum: { $cond: [{ $eq: ['$status', 'paid'] }, 1, 0] } },\n pendingCount: { $sum: { $cond: [{ $eq: ['$status', 'pending'] }, 1, 0] } },\n },\n },\n ]);\n\n return summary || {\n totalGross: 0,\n totalNet: 0,\n totalDeductions: 0,\n totalTax: 0,\n employeeCount: 0,\n paidCount: 0,\n pendingCount: 0,\n };\n }\n\n /**\n * Export payroll data\n */\n async exportPayroll(params: ExportPayrollParams): Promise<TPayrollRecord[]> {\n this.ensureInitialized();\n const { organizationId, startDate, endDate } = params;\n\n const query = {\n organizationId: toObjectId(organizationId),\n 'period.payDate': { $gte: startDate, $lte: endDate },\n };\n\n const records = await this.models.PayrollRecordModel.find(query)\n .populate('employeeId', 'employeeId position department')\n .populate('userId', 'name email')\n .populate('transactionId', 'amount method status date')\n .sort({ 'period.year': -1, 'period.month': -1 });\n\n // Mark as exported\n await this.models.PayrollRecordModel.updateMany(query, {\n exported: true,\n exportedAt: new Date(),\n });\n\n // Emit event\n this._events.emitSync('payroll:exported', {\n organizationId: toObjectId(organizationId),\n dateRange: { start: startDate, end: endDate },\n recordCount: records.length,\n format: 'json',\n });\n\n getLogger().info('Payroll data exported', {\n organizationId: organizationId.toString(),\n count: records.length,\n });\n\n return records as unknown as TPayrollRecord[];\n }\n\n // ========================================\n // Tax Withholding Methods\n // ========================================\n\n /**\n * Get pending tax withholdings with optional filters\n */\n async getPendingTaxWithholdings(params: GetPendingTaxParams): Promise<TaxWithholdingDocument[]> {\n this.ensureInitialized();\n\n if (!this.models.TaxWithholdingModel) {\n throw new Error('TaxWithholding model not provided. Please add TaxWithholdingModel to your models configuration.');\n }\n\n const { TaxWithholdingService } = await import('./services/tax-withholding.service.js');\n const service = new TaxWithholdingService(this.models.TaxWithholdingModel);\n\n return service.getPending(params);\n }\n\n /**\n * Get tax summary aggregated by type, period, or employee\n */\n async getTaxSummary(params: TaxSummaryParams): Promise<TaxSummaryResult> {\n this.ensureInitialized();\n\n if (!this.models.TaxWithholdingModel) {\n throw new Error('TaxWithholding model not provided. Please add TaxWithholdingModel to your models configuration.');\n }\n\n const { TaxWithholdingService } = await import('./services/tax-withholding.service.js');\n const service = new TaxWithholdingService(this.models.TaxWithholdingModel);\n\n return service.getSummary(params);\n }\n\n /**\n * Mark tax withholdings as paid\n *\n * Updates status, optionally creates government payment transaction,\n * and emits tax:paid event\n */\n async markTaxWithholdingsPaid(params: MarkTaxPaidParams): Promise<{\n withholdings: TaxWithholdingDocument[];\n transaction?: any;\n }> {\n this.ensureInitialized();\n\n if (!this.models.TaxWithholdingModel) {\n throw new Error('TaxWithholding model not provided. Please add TaxWithholdingModel to your models configuration.');\n }\n\n const { TaxWithholdingService } = await import('./services/tax-withholding.service.js');\n const service = new TaxWithholdingService(\n this.models.TaxWithholdingModel,\n this.models.TransactionModel as any,\n this._events\n );\n\n return service.markPaid(params);\n }\n\n // ========================================\n // Helper Methods\n // ========================================\n\n /**\n * Calculate salary breakdown\n *\n * Delegates to pure calculator for testability and reusability\n */\n private async calculateSalaryBreakdown(\n employee: EmployeeDocument,\n period: { month: number; year: number; startDate: Date; endDate: Date; payDate: Date },\n input: { attendance?: AttendanceInput | null; options?: PayrollProcessingOptions } = {},\n session?: ClientSession\n ): Promise<import('./types.js').PayrollBreakdown> {\n const options = input.options || {};\n let attendanceData = input.attendance;\n\n // Handle DB-based attendance lookup (if not provided and AttendanceModel exists)\n if (!options.skipAttendance && this.config.payroll.attendanceIntegration && !attendanceData && this.models.AttendanceModel) {\n // This is the ONLY non-pure part - fetch attendance from DB\n const dbAttendance = await this.calculateAttendanceDeduction(\n employee._id,\n employee.organizationId,\n period,\n 0, // We'll recalculate daily rate in the pure calculator\n 0, // We'll calculate expected days in the pure calculator\n session\n );\n\n // Convert DB result to attendance data format\n if (dbAttendance > 0) {\n // We need to get actual working days from the attendance model\n // For now, we'll keep the old behavior and let the pure calculator handle it\n try {\n let query = this.models.AttendanceModel.findOne({\n tenantId: employee.organizationId,\n targetId: employee._id,\n targetModel: 'Employee',\n year: period.year,\n month: period.month,\n });\n if (session) query = query.session(session);\n\n const attendance = await query;\n if (attendance) {\n const workedDays = (attendance as { totalWorkDays?: number }).totalWorkDays || 0;\n attendanceData = {\n expectedDays: 0, // Will be calculated by the pure calculator\n actualDays: workedDays,\n };\n }\n } catch (error) {\n getLogger().warn('Failed to fetch attendance data', {\n employeeId: employee._id.toString(),\n error: (error as Error).message,\n });\n }\n }\n }\n\n const currency = employee.compensation.currency || this.config.payroll.defaultCurrency;\n const taxBrackets = TAX_BRACKETS[currency] || [];\n\n return calculateSalaryBreakdownPure({\n employee: {\n hireDate: employee.hireDate,\n terminationDate: employee.terminationDate,\n compensation: employee.compensation,\n workSchedule: employee.workSchedule,\n },\n period,\n attendance: attendanceData,\n options,\n config: {\n allowProRating: this.config.payroll.allowProRating,\n autoDeductions: this.config.payroll.autoDeductions,\n defaultCurrency: this.config.payroll.defaultCurrency,\n attendanceIntegration: this.config.payroll.attendanceIntegration,\n },\n taxBrackets,\n });\n }\n\n /**\n * Calculate attendance deduction using working days (not calendar days)\n */\n private async calculateAttendanceDeduction(\n employeeId: mongoose.Types.ObjectId,\n organizationId: mongoose.Types.ObjectId,\n period: { month: number; year: number; startDate: Date; endDate: Date },\n dailyRate: number,\n expectedWorkingDays: number,\n session?: ClientSession\n ): Promise<number> {\n try {\n if (!this.models.AttendanceModel) return 0;\n\n let query = this.models.AttendanceModel.findOne({\n tenantId: organizationId,\n targetId: employeeId,\n targetModel: 'Employee',\n year: period.year,\n month: period.month,\n });\n if (session) query = query.session(session);\n\n const attendance = await query;\n if (!attendance) return 0;\n\n const workedDays = (attendance as { totalWorkDays?: number }).totalWorkDays || 0;\n \n // Calculate absent days based on expected working days (not calendar days)\n const absentDays = Math.max(0, expectedWorkingDays - workedDays);\n\n return Math.round(absentDays * dailyRate);\n } catch (error) {\n getLogger().warn('Failed to calculate attendance deduction', {\n employeeId: employeeId.toString(),\n error: (error as Error).message,\n });\n return 0;\n }\n }\n\n private async updatePayrollStats(\n employee: EmployeeDocument,\n amount: number,\n paymentDate: Date,\n session?: ClientSession\n ): Promise<void> {\n if (!employee.payrollStats) {\n employee.payrollStats = {\n totalPaid: 0,\n paymentsThisYear: 0,\n averageMonthly: 0,\n };\n }\n\n employee.payrollStats.totalPaid = (employee.payrollStats.totalPaid || 0) + amount;\n employee.payrollStats.lastPaymentDate = paymentDate;\n employee.payrollStats.paymentsThisYear = (employee.payrollStats.paymentsThisYear || 0) + 1;\n employee.payrollStats.averageMonthly = Math.round(\n employee.payrollStats.totalPaid / employee.payrollStats.paymentsThisYear\n );\n employee.payrollStats.nextPaymentDate = addMonths(paymentDate, 1);\n\n await employee.save(session ? { session } : {});\n }\n\n // ========================================\n // Static Factory\n // ========================================\n\n /**\n * Create a new Payroll instance with default types\n */\n static create<\n E extends EmployeeDocument = EmployeeDocument,\n P extends PayrollRecordDocument = PayrollRecordDocument,\n T extends AnyDocument = AnyDocument,\n A extends AnyDocument = AnyDocument,\n >(): Payroll<E, P, T, A> {\n return new Payroll<E, P, T, A>();\n }\n}\n\n// ============================================================================\n// Payroll Builder\n// ============================================================================\n\n/**\n * Generic models configuration - infers types from your models\n */\nexport interface ModelsConfig<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument,\n TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument,\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument,\n> {\n EmployeeModel: Model<TEmployee>;\n PayrollRecordModel: Model<TPayrollRecord>;\n TransactionModel: Model<TTransaction>;\n AttendanceModel?: Model<TAttendance> | null;\n LeaveRequestModel?: Model<TLeaveRequest> | null;\n TaxWithholdingModel?: Model<TTaxWithholding> | null;\n}\n\n/**\n * Generic Payroll Builder with full type inference.\n *\n * Types flow from withModels() through to build(), giving you a fully typed Payroll instance.\n *\n * @typeParam TEmployee - Inferred from EmployeeModel\n * @typeParam TPayrollRecord - Inferred from PayrollRecordModel\n * @typeParam TTransaction - Inferred from TransactionModel\n * @typeParam TAttendance - Inferred from AttendanceModel\n *\n * @example\n * ```typescript\n * // Types are automatically inferred!\n * const payroll = createPayrollInstance()\n * .withModels({\n * EmployeeModel, // Model<MyEmployee>\n * PayrollRecordModel, // Model<MyPayroll>\n * TransactionModel, // Model<MyTransaction>\n * })\n * .build(); // Returns PayrollInstance<MyEmployee, MyPayroll, MyTransaction, AnyDocument>\n * ```\n */\nexport class PayrollBuilder<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument,\n TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument,\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument,\n> {\n private _models: ModelsConfig<TEmployee, TPayrollRecord, TTransaction, TAttendance, TLeaveRequest, TTaxWithholding> | null = null;\n private _config: DeepPartial<HRMConfig> | undefined;\n private _singleTenant: SingleTenantConfig | null = null;\n private _logger: Logger | undefined;\n\n /**\n * Set models - types are inferred automatically\n *\n * @example\n * ```typescript\n * .withModels({\n * EmployeeModel, // Your typed model\n * PayrollRecordModel,\n * TransactionModel,\n * AttendanceModel, // Optional\n * })\n * ```\n */\n withModels<\n E extends EmployeeDocument,\n P extends PayrollRecordDocument,\n T extends AnyDocument,\n A extends AnyDocument = AnyDocument,\n L extends LeaveRequestDocument = LeaveRequestDocument,\n TW extends TaxWithholdingDocument = TaxWithholdingDocument,\n >(\n models: ModelsConfig<E, P, T, A, L, TW>\n ): PayrollBuilder<E, P, T, A, L, TW> {\n // Cast to new builder type with inferred generics\n const builder = this as unknown as PayrollBuilder<E, P, T, A, L, TW>;\n builder._models = models;\n return builder;\n }\n\n /**\n * Set config overrides\n */\n withConfig(config: DeepPartial<HRMConfig>): this {\n this._config = config;\n return this;\n }\n\n /**\n * Enable single-tenant mode\n *\n * Use this when building a single-organization HRM (no organizationId needed)\n *\n * @example\n * ```typescript\n * const payroll = createPayrollInstance()\n * .withModels({ EmployeeModel, PayrollRecordModel, TransactionModel })\n * .withSingleTenant({ organizationId: 'my-company' })\n * .build();\n * ```\n */\n withSingleTenant(config: SingleTenantConfig): this {\n this._singleTenant = config;\n return this;\n }\n\n /**\n * Enable single-tenant mode (shorthand)\n *\n * Alias for withSingleTenant() - consistent with @classytic/clockin API\n *\n * @example\n * ```typescript\n * const payroll = createPayrollInstance()\n * .withModels({ ... })\n * .forSingleTenant() // ← No organizationId needed!\n * .build();\n * ```\n */\n forSingleTenant(config: SingleTenantConfig = {}): this {\n return this.withSingleTenant(config);\n }\n\n /**\n * Set custom logger\n */\n withLogger(logger: Logger): this {\n this._logger = logger;\n return this;\n }\n\n /**\n * Build and initialize Payroll instance with inferred types\n */\n build(): PayrollInstance<TEmployee, TPayrollRecord, TTransaction, TAttendance> {\n if (!this._models) {\n throw new Error('Models are required. Call withModels() first.');\n }\n\n const payroll = new Payroll<TEmployee, TPayrollRecord, TTransaction, TAttendance>();\n payroll.initialize({\n EmployeeModel: this._models.EmployeeModel,\n PayrollRecordModel: this._models.PayrollRecordModel,\n TransactionModel: this._models.TransactionModel,\n AttendanceModel: this._models.AttendanceModel,\n config: this._config,\n singleTenant: this._singleTenant,\n logger: this._logger,\n });\n\n return payroll;\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a new Payroll builder\n */\nexport function createPayrollInstance(): PayrollBuilder {\n return new PayrollBuilder();\n}\n\n// NOTE: No singleton exports.\n// Use `createPayrollInstance().withModels(...).build()` to create instances.\n","/**\n * @classytic/payroll - Employee Factory\n *\n * Clean object creation for employee documents\n * Builder pattern for fluent API\n */\n\nimport type {\n ObjectIdLike,\n EmploymentType,\n Department,\n Compensation,\n BankDetails,\n WorkSchedule,\n Allowance,\n Deduction,\n PaymentFrequency,\n TerminationReason,\n HRMConfig,\n} from '../types.js';\nimport { calculateProbationEnd } from '../utils/date.js';\nimport { HRM_CONFIG } from '../config.js';\n\n// ============================================================================\n// Employee Factory Types\n// ============================================================================\n\nexport interface CreateEmployeeParams {\n userId?: ObjectIdLike; // Optional for guest employees\n organizationId: ObjectIdLike;\n employment: {\n employeeId?: string;\n email?: string; // For guest employees\n type?: EmploymentType;\n department?: Department | string;\n position: string;\n hireDate?: Date;\n probationMonths?: number;\n workSchedule?: WorkSchedule;\n };\n compensation: {\n baseAmount: number;\n frequency?: PaymentFrequency;\n currency?: string;\n allowances?: Array<Partial<Allowance>>;\n deductions?: Array<Partial<Deduction>>;\n };\n bankDetails?: BankDetails;\n}\n\nexport interface EmployeeData {\n userId?: ObjectIdLike; // Optional for guest employees\n email?: string; // For guest employees\n organizationId: ObjectIdLike;\n employeeId: string;\n employmentType: EmploymentType;\n status: 'active';\n department?: Department;\n position: string;\n hireDate: Date;\n probationEndDate: Date | null;\n compensation: Compensation;\n workSchedule: WorkSchedule;\n bankDetails: BankDetails;\n payrollStats: {\n totalPaid: number;\n paymentsThisYear: number;\n averageMonthly: number;\n };\n}\n\nexport interface TerminationData {\n terminatedAt: Date;\n terminationReason: TerminationReason;\n terminationNotes?: string;\n terminatedBy: {\n userId?: ObjectIdLike;\n name?: string;\n role?: string;\n };\n}\n\n// ============================================================================\n// Email Normalization\n// ============================================================================\n\n/**\n * Normalize email address (lowercase + trim)\n * Ensures consistent email storage and lookup\n */\nfunction normalizeEmail(email: string | undefined): string | undefined {\n if (!email || typeof email !== 'string') return undefined;\n const trimmed = email.trim();\n return trimmed ? trimmed.toLowerCase() : undefined;\n}\n\n// ============================================================================\n// Employee Factory\n// ============================================================================\n\nexport class EmployeeFactory {\n /**\n * Create employee data object\n */\n static create(params: CreateEmployeeParams, config: HRMConfig = HRM_CONFIG): EmployeeData {\n const { userId, organizationId, employment, compensation, bankDetails } = params;\n const hireDate = employment.hireDate || new Date();\n\n // Normalize email (lowercase + trim) for consistent storage and lookup\n const normalizedEmail = normalizeEmail(employment.email);\n\n return {\n ...(userId ? { userId } : {}), // Only include userId if present\n ...(normalizedEmail ? { email: normalizedEmail } : {}), // Include normalized email for guest employees\n organizationId,\n employeeId: employment.employeeId || `EMP-${Date.now()}-${Math.random().toString(36).substr(2, 6).toUpperCase()}`,\n employmentType: employment.type || 'full_time',\n status: 'active',\n department: employment.department as Department | undefined,\n position: employment.position,\n hireDate,\n probationEndDate: calculateProbationEnd(\n hireDate,\n employment.probationMonths ?? config.employment.defaultProbationMonths\n ),\n compensation: this.createCompensation(compensation, config),\n workSchedule: employment.workSchedule || this.defaultWorkSchedule(),\n bankDetails: bankDetails || {},\n payrollStats: {\n totalPaid: 0,\n paymentsThisYear: 0,\n averageMonthly: 0,\n },\n };\n }\n\n /**\n * Create compensation object\n */\n static createCompensation(params: {\n baseAmount: number;\n frequency?: PaymentFrequency;\n currency?: string;\n allowances?: Array<Partial<Allowance>>;\n deductions?: Array<Partial<Deduction>>;\n }, config: HRMConfig = HRM_CONFIG): Compensation {\n return {\n baseAmount: params.baseAmount,\n frequency: params.frequency || 'monthly',\n currency: params.currency || config.payroll.defaultCurrency,\n allowances: (params.allowances || []).map((a) => ({\n type: a.type || 'other',\n name: a.name || a.type || 'other',\n amount: a.amount || 0,\n taxable: a.taxable,\n recurring: a.recurring,\n effectiveFrom: a.effectiveFrom,\n effectiveTo: a.effectiveTo,\n })),\n deductions: (params.deductions || []).map((d) => ({\n type: d.type || 'other',\n name: d.name || d.type || 'other',\n amount: d.amount || 0,\n auto: d.auto,\n recurring: d.recurring,\n description: d.description,\n effectiveFrom: d.effectiveFrom,\n effectiveTo: d.effectiveTo,\n })),\n grossSalary: 0,\n netSalary: 0,\n effectiveFrom: new Date(),\n lastModified: new Date(),\n };\n }\n\n /**\n * Create allowance object\n */\n static createAllowance(params: {\n type: Allowance['type'];\n amount: number;\n name?: string;\n isPercentage?: boolean;\n taxable?: boolean;\n recurring?: boolean;\n }): Allowance {\n return {\n type: params.type,\n name: params.name || params.type,\n amount: params.amount,\n isPercentage: params.isPercentage ?? false,\n taxable: params.taxable ?? true,\n recurring: params.recurring ?? true,\n effectiveFrom: new Date(),\n };\n }\n\n /**\n * Create deduction object\n */\n static createDeduction(params: {\n type: Deduction['type'];\n amount: number;\n name?: string;\n isPercentage?: boolean;\n auto?: boolean;\n recurring?: boolean;\n description?: string;\n }): Deduction {\n return {\n type: params.type,\n name: params.name || params.type,\n amount: params.amount,\n isPercentage: params.isPercentage ?? false,\n auto: params.auto ?? false,\n recurring: params.recurring ?? true,\n description: params.description,\n effectiveFrom: new Date(),\n };\n }\n\n /**\n * Default work schedule\n */\n static defaultWorkSchedule(): WorkSchedule {\n return {\n hoursPerWeek: 40,\n hoursPerDay: 8,\n workingDays: [1, 2, 3, 4, 5], // Mon-Fri\n shiftStart: '09:00',\n shiftEnd: '17:00',\n };\n }\n\n /**\n * Create termination data\n */\n static createTermination(params: {\n reason: TerminationReason;\n date?: Date;\n notes?: string;\n context?: {\n userId?: ObjectIdLike;\n userName?: string;\n userRole?: string;\n };\n }): TerminationData {\n return {\n terminatedAt: params.date || new Date(),\n terminationReason: params.reason,\n terminationNotes: params.notes,\n terminatedBy: {\n userId: params.context?.userId,\n name: params.context?.userName,\n role: params.context?.userRole,\n },\n };\n }\n}\n\n// ============================================================================\n// Employee Builder\n// ============================================================================\n\nexport class EmployeeBuilder {\n private data: Partial<CreateEmployeeParams> = {\n employment: {} as CreateEmployeeParams['employment'],\n compensation: {} as CreateEmployeeParams['compensation'],\n bankDetails: {},\n };\n\n /**\n * Set user ID\n */\n forUser(userId: ObjectIdLike): this {\n this.data.userId = userId;\n return this;\n }\n\n /**\n * Set organization ID\n */\n inOrganization(organizationId: ObjectIdLike): this {\n this.data.organizationId = organizationId;\n return this;\n }\n\n /**\n * Set employee ID\n */\n withEmployeeId(employeeId: string): this {\n this.data.employment = { ...this.data.employment!, employeeId };\n return this;\n }\n\n /**\n * Set department\n */\n inDepartment(department: Department): this {\n this.data.employment = { ...this.data.employment!, department };\n return this;\n }\n\n /**\n * Set position\n */\n asPosition(position: string): this {\n this.data.employment = { ...this.data.employment!, position };\n return this;\n }\n\n /**\n * Set employment type\n */\n withEmploymentType(type: EmploymentType): this {\n this.data.employment = { ...this.data.employment!, type };\n return this;\n }\n\n /**\n * Set hire date\n */\n hiredOn(date: Date): this {\n this.data.employment = { ...this.data.employment!, hireDate: date };\n return this;\n }\n\n /**\n * Set probation period\n */\n withProbation(months: number): this {\n this.data.employment = { ...this.data.employment!, probationMonths: months };\n return this;\n }\n\n /**\n * Set work schedule\n */\n withSchedule(schedule: WorkSchedule): this {\n this.data.employment = { ...this.data.employment!, workSchedule: schedule };\n return this;\n }\n\n /**\n * Set base salary\n */\n withBaseSalary(\n amount: number,\n frequency: PaymentFrequency = 'monthly',\n currency = 'BDT'\n ): this {\n this.data.compensation = {\n ...this.data.compensation!,\n baseAmount: amount,\n frequency,\n currency,\n };\n return this;\n }\n\n /**\n * Add allowance\n */\n addAllowance(\n type: Allowance['type'],\n amount: number,\n options: { taxable?: boolean; recurring?: boolean } = {}\n ): this {\n const allowances = this.data.compensation?.allowances || [];\n this.data.compensation = {\n ...this.data.compensation!,\n allowances: [\n ...allowances,\n { type, amount, taxable: options.taxable, recurring: options.recurring },\n ],\n };\n return this;\n }\n\n /**\n * Add deduction\n */\n addDeduction(\n type: Deduction['type'],\n amount: number,\n options: { auto?: boolean; recurring?: boolean; description?: string } = {}\n ): this {\n const deductions = this.data.compensation?.deductions || [];\n this.data.compensation = {\n ...this.data.compensation!,\n deductions: [\n ...deductions,\n {\n type,\n amount,\n auto: options.auto,\n recurring: options.recurring,\n description: options.description,\n },\n ],\n };\n return this;\n }\n\n /**\n * Set bank details\n */\n withBankDetails(bankDetails: BankDetails): this {\n this.data.bankDetails = bankDetails;\n return this;\n }\n\n /**\n * Build employee data\n */\n build(config: HRMConfig = HRM_CONFIG): EmployeeData {\n if (!this.data.organizationId) {\n throw new Error('organizationId is required');\n }\n if (!this.data.employment?.position) {\n throw new Error('position is required');\n }\n if (!this.data.compensation?.baseAmount) {\n throw new Error('baseAmount is required');\n }\n\n return EmployeeFactory.create(this.data as CreateEmployeeParams, config);\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create new employee builder\n */\nexport function createEmployee(): EmployeeBuilder {\n return new EmployeeBuilder();\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n EmployeeFactory,\n EmployeeBuilder,\n createEmployee,\n};\n\n","/**\n * @classytic/payroll - Employee Service\n *\n * High-level employee operations with dependency injection\n *\n * ⚠️ **INTERNAL USE ONLY**\n *\n * This service is for internal use by the Payroll class only.\n * All methods enforce organizationId isolation for multi-tenant safety.\n *\n * **For application code:**\n * - Use `Payroll` class methods (recommended, full orchestration)\n * - Use `findEmployeeSecure()` utility for secure lookups\n * - Do NOT use EmployeeService directly\n *\n * This service is intentionally not exported from the package.\n *\n * @internal\n */\n\nimport type { Model, ClientSession } from 'mongoose';\nimport type {\n ObjectIdLike,\n EmployeeDocument,\n EmployeeStatus,\n Department,\n EmploymentType,\n Compensation,\n OperationContext,\n HRMConfig,\n} from '../types.js';\nimport { EmployeeFactory, type CreateEmployeeParams } from '../factories/employee.factory.js';\nimport { employee as employeeQuery, toObjectId } from '../utils/query-builders.js';\nimport { isActive, isEmployed, canReceiveSalary } from '../utils/validation.js';\nimport { logger } from '../utils/logger.js';\nimport { HRM_CONFIG } from '../config.js';\n\n// ============================================================================\n// Employee Service\n// ============================================================================\n\nexport class EmployeeService {\n private readonly config: HRMConfig;\n\n constructor(\n private readonly EmployeeModel: Model<EmployeeDocument>,\n config?: HRMConfig\n ) {\n this.config = config || HRM_CONFIG;\n }\n\n /**\n * Find employee by ID with organization validation\n * \n * ⚠️ SECURITY: Always validates employee belongs to specified organization\n * \n * @throws {Error} If employee not found or doesn't belong to organization\n */\n async findById(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n options: { session?: ClientSession; populate?: boolean } = {}\n ): Promise<EmployeeDocument | null> {\n // Build secure query that enforces org isolation\n const query = {\n _id: toObjectId(employeeId),\n organizationId: toObjectId(organizationId),\n };\n\n let mongooseQuery = this.EmployeeModel.findOne(query);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n if (options.populate) {\n mongooseQuery = mongooseQuery.populate('userId', 'name email phone');\n }\n \n return mongooseQuery.exec();\n }\n\n /**\n * Find employee by user and organization\n */\n async findByUserId(\n userId: ObjectIdLike,\n organizationId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument | null> {\n const query = employeeQuery()\n .forUser(userId)\n .forOrganization(organizationId)\n .build();\n\n let mongooseQuery = this.EmployeeModel.findOne(query);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n return mongooseQuery.exec();\n }\n\n /**\n * Find employee by employeeId (human-readable ID)\n */\n async findByEmployeeId(\n employeeId: string,\n organizationId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument | null> {\n const query = employeeQuery()\n .forEmployeeId(employeeId)\n .forOrganization(organizationId)\n .build();\n\n let mongooseQuery = this.EmployeeModel.findOne(query);\n\n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n\n return mongooseQuery.exec();\n }\n\n /**\n * Find employee by email (guest employees)\n */\n async findByEmail(\n email: string,\n organizationId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument | null> {\n const query = employeeQuery()\n .forEmail(email)\n .forOrganization(organizationId)\n .build();\n\n let mongooseQuery = this.EmployeeModel.findOne(query);\n\n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n\n return mongooseQuery.exec();\n }\n\n /**\n * Find all guest employees (no userId)\n */\n async findGuestEmployees(\n organizationId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument[]> {\n const query = employeeQuery()\n .forOrganization(organizationId)\n .guestEmployees()\n .build();\n\n let mongooseQuery = this.EmployeeModel.find(query);\n\n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n\n return mongooseQuery.exec();\n }\n\n /**\n * Find active employees in organization\n */\n async findActive(\n organizationId: ObjectIdLike,\n options: { session?: ClientSession; projection?: Record<string, number> } = {}\n ): Promise<EmployeeDocument[]> {\n const query = employeeQuery()\n .forOrganization(organizationId)\n .active()\n .build();\n\n let mongooseQuery = this.EmployeeModel.find(query, options.projection);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n return mongooseQuery.exec();\n }\n\n /**\n * Find employed employees (not terminated)\n */\n async findEmployed(\n organizationId: ObjectIdLike,\n options: { session?: ClientSession; projection?: Record<string, number> } = {}\n ): Promise<EmployeeDocument[]> {\n const query = employeeQuery()\n .forOrganization(organizationId)\n .employed()\n .build();\n\n let mongooseQuery = this.EmployeeModel.find(query, options.projection);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n return mongooseQuery.exec();\n }\n\n /**\n * Find employees by department\n */\n async findByDepartment(\n organizationId: ObjectIdLike,\n department: Department,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument[]> {\n const query = employeeQuery()\n .forOrganization(organizationId)\n .inDepartment(department)\n .active()\n .build();\n\n let mongooseQuery = this.EmployeeModel.find(query);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n return mongooseQuery.exec();\n }\n\n /**\n * Find employees eligible for payroll\n */\n async findEligibleForPayroll(\n organizationId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument[]> {\n const query = employeeQuery()\n .forOrganization(organizationId)\n .employed()\n .build();\n\n let mongooseQuery = this.EmployeeModel.find(query);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n const employees = await mongooseQuery.exec();\n return employees.filter((emp) => canReceiveSalary(emp));\n }\n\n /**\n * Create new employee\n */\n async create(\n params: CreateEmployeeParams,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument> {\n const employeeData = EmployeeFactory.create(params, this.config);\n\n let employee: EmployeeDocument;\n\n // For guest employees, use insertOne to avoid Mongoose setting undefined fields to null\n // This ensures partial indexes work correctly (partial index only includes docs with userId)\n if (!params.userId) {\n // Guest employee - use direct MongoDB insertOne to preserve partial index behavior\n const dataToInsert: Record<string, any> = {};\n\n // Copy all fields from employeeData except userId/email which need special handling\n for (const [key, value] of Object.entries(employeeData)) {\n if (key === 'userId' || key === 'email') continue;\n dataToInsert[key] = value;\n }\n\n // Only include email if it exists and is not empty (critical for partial index)\n if (employeeData.email && employeeData.email !== '') {\n dataToInsert.email = employeeData.email;\n }\n\n // NEVER include userId for guest employees (partial index excludes docs without userId)\n // Add timestamps manually since we're bypassing Mongoose\n const now = new Date();\n dataToInsert.createdAt = now;\n dataToInsert.updatedAt = now;\n\n // Use direct MongoDB insertOne\n const insertOptions = options.session ? { session: options.session as any } : {};\n const result = await this.EmployeeModel.collection.insertOne(\n dataToInsert,\n insertOptions\n );\n\n // Convert back to Mongoose document\n employee = await this.EmployeeModel.findById(result.insertedId).session(options.session || null).exec() as EmployeeDocument;\n } else {\n // Regular employee with userId - use Mongoose create\n const [created] = await this.EmployeeModel.create([employeeData], {\n session: options.session,\n });\n employee = created;\n }\n\n logger.info('Employee created', {\n employeeId: employee.employeeId,\n organizationId: employee.organizationId.toString(),\n });\n\n return employee;\n }\n\n /**\n * Update employee status with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization before update\n */\n async updateStatus(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n status: EmployeeStatus,\n context: OperationContext = {},\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument> {\n const employee = await this.findById(employeeId, organizationId, options);\n if (!employee) {\n throw new Error(`Employee not found in organization ${organizationId}`);\n }\n\n employee.status = status;\n await employee.save({ session: options.session });\n\n logger.info('Employee status updated', {\n employeeId: employee.employeeId,\n organizationId: organizationId.toString(),\n newStatus: status,\n });\n\n return employee;\n }\n\n /**\n * Update employee compensation with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization before update\n * \n * NOTE: This merges the compensation fields rather than replacing the entire object.\n * To update allowances/deductions, use addAllowance/removeAllowance methods.\n */\n async updateCompensation(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n compensation: Partial<Compensation>,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument> {\n // First verify employee belongs to organization\n const currentEmployee = await this.findById(employeeId, organizationId, options);\n if (!currentEmployee) {\n throw new Error(`Employee not found in organization ${organizationId}`);\n }\n\n // Build update object that only sets provided fields\n const updateFields: Record<string, unknown> = {\n 'compensation.lastModified': new Date(),\n };\n\n // Only update specific fields if provided (preserve allowances/deductions)\n if (compensation.baseAmount !== undefined) {\n updateFields['compensation.baseAmount'] = compensation.baseAmount;\n }\n if (compensation.currency !== undefined) {\n updateFields['compensation.currency'] = compensation.currency;\n }\n if (compensation.frequency !== undefined) {\n updateFields['compensation.frequency'] = compensation.frequency;\n }\n if (compensation.effectiveFrom !== undefined) {\n updateFields['compensation.effectiveFrom'] = compensation.effectiveFrom;\n }\n // Note: allowances and deductions should NOT be updated here\n // Use addAllowance/removeAllowance methods instead\n\n // Use secure query with org filter\n const query = {\n _id: toObjectId(employeeId),\n organizationId: toObjectId(organizationId),\n };\n\n const employee = await this.EmployeeModel.findOneAndUpdate(\n query,\n { $set: updateFields },\n { new: true, runValidators: true, session: options.session }\n );\n\n if (!employee) {\n throw new Error(`Employee not found in organization ${organizationId}`);\n }\n\n logger.info('Employee compensation updated', {\n employeeId: employee.employeeId,\n organizationId: organizationId.toString(),\n });\n\n return employee;\n }\n\n /**\n * Get employee statistics for organization\n */\n async getEmployeeStats(\n organizationId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<{\n total: number;\n active: number;\n employed: number;\n canReceiveSalary: number;\n byStatus: Record<string, number>;\n byDepartment: Record<string, number>;\n }> {\n const query = employeeQuery().forOrganization(organizationId).build();\n \n let mongooseQuery = this.EmployeeModel.find(query);\n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n const employees = await mongooseQuery.exec();\n\n return {\n total: employees.length,\n active: employees.filter(isActive).length,\n employed: employees.filter(isEmployed).length,\n canReceiveSalary: employees.filter(canReceiveSalary).length,\n byStatus: this.groupByStatus(employees),\n byDepartment: this.groupByDepartment(employees),\n };\n }\n\n /**\n * Group employees by status\n */\n private groupByStatus(employees: EmployeeDocument[]): Record<string, number> {\n return employees.reduce(\n (acc, emp) => {\n acc[emp.status] = (acc[emp.status] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>\n );\n }\n\n /**\n * Group employees by department\n */\n private groupByDepartment(employees: EmployeeDocument[]): Record<string, number> {\n return employees.reduce(\n (acc, emp) => {\n const dept = emp.department || 'unassigned';\n acc[dept] = (acc[dept] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>\n );\n }\n\n /**\n * Check if employee is active\n */\n isActive(employee: EmployeeDocument): boolean {\n return isActive(employee);\n }\n\n /**\n * Check if employee is employed\n */\n isEmployed(employee: EmployeeDocument): boolean {\n return isEmployed(employee);\n }\n\n /**\n * Check if employee can receive salary\n */\n canReceiveSalary(employee: EmployeeDocument): boolean {\n return canReceiveSalary(employee);\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create employee service instance\n */\nexport function createEmployeeService(\n EmployeeModel: Model<EmployeeDocument>,\n config?: HRMConfig\n): EmployeeService {\n return new EmployeeService(EmployeeModel, config);\n}\n\n","/**\n * @classytic/payroll - Payroll Factory\n *\n * Clean object creation for payroll records\n * Immutable operations and builder pattern\n */\n\nimport type {\n ObjectIdLike,\n PayrollBreakdown,\n PayrollPeriod,\n PaymentMethod,\n Allowance,\n Deduction,\n Compensation,\n} from '../types.js';\nimport { getPayPeriod } from '../utils/date.js';\nimport { calculateGross, calculateNet, sumAllowances, sumDeductions } from '../utils/calculation.js';\nimport { HRM_CONFIG } from '../config.js';\n\n// ============================================================================\n// Payroll Factory Types\n// ============================================================================\n\nexport interface CreatePayrollParams {\n employeeId: ObjectIdLike;\n organizationId: ObjectIdLike;\n baseAmount: number;\n allowances?: Array<{ type: string; amount: number; taxable?: boolean }>;\n deductions?: Array<{ type: string; amount: number; description?: string }>;\n period?: { month?: number; year?: number };\n metadata?: {\n currency?: string;\n paymentMethod?: PaymentMethod;\n notes?: string;\n };\n}\n\nexport interface PayrollData {\n employeeId: ObjectIdLike;\n organizationId: ObjectIdLike;\n period: PayrollPeriod;\n breakdown: PayrollBreakdown;\n status: 'pending';\n processedAt: null;\n paidAt: null;\n metadata: {\n currency: string;\n paymentMethod?: PaymentMethod;\n notes?: string;\n };\n}\n\n// ============================================================================\n// Payroll Factory\n// ============================================================================\n\nexport class PayrollFactory {\n /**\n * Create payroll data object\n */\n static create(params: CreatePayrollParams): PayrollData {\n const {\n employeeId,\n organizationId,\n baseAmount,\n allowances = [],\n deductions = [],\n period = {},\n metadata = {},\n } = params;\n\n const calculatedAllowances = this.calculateAllowances(baseAmount, allowances);\n const calculatedDeductions = this.calculateDeductions(baseAmount, deductions);\n\n const gross = calculateGross(baseAmount, calculatedAllowances);\n const net = calculateNet(gross, calculatedDeductions);\n\n return {\n employeeId,\n organizationId,\n period: this.createPeriod(period),\n breakdown: {\n baseAmount,\n allowances: calculatedAllowances,\n deductions: calculatedDeductions,\n grossSalary: gross,\n netSalary: net,\n },\n status: 'pending',\n processedAt: null,\n paidAt: null,\n metadata: {\n currency: metadata.currency || HRM_CONFIG.payroll.defaultCurrency,\n paymentMethod: metadata.paymentMethod,\n notes: metadata.notes,\n },\n };\n }\n\n /**\n * Create pay period\n */\n static createPeriod(params: { month?: number; year?: number; payDate?: Date }): PayrollPeriod {\n const now = new Date();\n const month = params.month || now.getMonth() + 1;\n const year = params.year || now.getFullYear();\n const period = getPayPeriod(month, year);\n\n return {\n ...period,\n payDate: params.payDate || new Date(),\n };\n }\n\n /**\n * Calculate allowances from base amount\n */\n static calculateAllowances(\n baseAmount: number,\n allowances: Array<{ type: string; amount: number; taxable?: boolean; isPercentage?: boolean; value?: number }>\n ): Array<{ type: string; amount: number; taxable: boolean }> {\n return allowances.map((allowance) => {\n const amount =\n allowance.isPercentage && allowance.value !== undefined\n ? Math.round((baseAmount * allowance.value) / 100)\n : allowance.amount;\n\n return {\n type: allowance.type,\n amount,\n taxable: allowance.taxable ?? true,\n };\n });\n }\n\n /**\n * Calculate deductions from base amount\n */\n static calculateDeductions(\n baseAmount: number,\n deductions: Array<{ type: string; amount: number; description?: string; isPercentage?: boolean; value?: number }>\n ): Array<{ type: string; amount: number; description?: string }> {\n return deductions.map((deduction) => {\n const amount =\n deduction.isPercentage && deduction.value !== undefined\n ? Math.round((baseAmount * deduction.value) / 100)\n : deduction.amount;\n\n return {\n type: deduction.type,\n amount,\n description: deduction.description,\n };\n });\n }\n\n /**\n * Create bonus object\n */\n static createBonus(params: {\n type: string;\n amount: number;\n reason: string;\n approvedBy?: ObjectIdLike;\n }): { type: string; amount: number; reason: string; approvedBy?: ObjectIdLike; approvedAt: Date } {\n return {\n type: params.type,\n amount: params.amount,\n reason: params.reason,\n approvedBy: params.approvedBy,\n approvedAt: new Date(),\n };\n }\n\n /**\n * Mark payroll as paid (immutable)\n * Sets both top-level transactionId and metadata for compatibility\n */\n static markAsPaid<T extends { status: string; paidAt?: Date | null; processedAt?: Date | null; transactionId?: unknown; metadata?: Record<string, unknown> }>(\n payroll: T,\n params: { paidAt?: Date; transactionId?: ObjectIdLike; paymentMethod?: PaymentMethod } = {}\n ): T & { status: 'paid' } {\n return {\n ...payroll,\n status: 'paid' as const,\n paidAt: params.paidAt || new Date(),\n processedAt: payroll.processedAt || params.paidAt || new Date(),\n transactionId: params.transactionId || payroll.transactionId,\n metadata: {\n ...payroll.metadata,\n transactionId: params.transactionId,\n paymentMethod: params.paymentMethod || payroll.metadata?.paymentMethod,\n },\n };\n }\n\n /**\n * Mark payroll as processed (immutable)\n */\n static markAsProcessed<T extends { status: string; processedAt: Date | null }>(\n payroll: T,\n params: { processedAt?: Date } = {}\n ): T & { status: 'processing' } {\n return {\n ...payroll,\n status: 'processing' as const,\n processedAt: params.processedAt || new Date(),\n };\n }\n}\n\n// ============================================================================\n// Payroll Builder\n// ============================================================================\n\nexport class PayrollBuilder {\n private data: Partial<CreatePayrollParams> = {\n allowances: [],\n deductions: [],\n period: {},\n metadata: {},\n };\n\n /**\n * Set employee ID\n */\n forEmployee(employeeId: ObjectIdLike): this {\n this.data.employeeId = employeeId;\n return this;\n }\n\n /**\n * Set organization ID\n */\n inOrganization(organizationId: ObjectIdLike): this {\n this.data.organizationId = organizationId;\n return this;\n }\n\n /**\n * Set base amount\n */\n withBaseAmount(amount: number): this {\n this.data.baseAmount = amount;\n return this;\n }\n\n /**\n * Set pay period\n */\n forPeriod(month: number, year: number): this {\n this.data.period = { month, year };\n return this;\n }\n\n /**\n * Add allowance\n */\n addAllowance(\n type: string,\n value: number,\n isPercentage = false,\n name?: string\n ): this {\n this.data.allowances = [\n ...(this.data.allowances || []),\n {\n type,\n amount: isPercentage ? 0 : value,\n isPercentage,\n value: isPercentage ? value : undefined,\n } as { type: string; amount: number },\n ];\n return this;\n }\n\n /**\n * Add deduction\n */\n addDeduction(\n type: string,\n value: number,\n isPercentage = false,\n description?: string\n ): this {\n this.data.deductions = [\n ...(this.data.deductions || []),\n {\n type,\n amount: isPercentage ? 0 : value,\n isPercentage,\n value: isPercentage ? value : undefined,\n description,\n } as { type: string; amount: number; description?: string },\n ];\n return this;\n }\n\n /**\n * Add bonus\n */\n addBonus(amount: number, reason: string): this {\n return this.addAllowance('bonus', amount, false, reason);\n }\n\n /**\n * Set currency\n */\n withCurrency(currency: string): this {\n this.data.metadata = { ...this.data.metadata, currency };\n return this;\n }\n\n /**\n * Set payment method\n */\n withPaymentMethod(method: PaymentMethod): this {\n this.data.metadata = { ...this.data.metadata, paymentMethod: method };\n return this;\n }\n\n /**\n * Set notes\n */\n withNotes(notes: string): this {\n this.data.metadata = { ...this.data.metadata, notes };\n return this;\n }\n\n /**\n * Build payroll data\n */\n build(): PayrollData {\n if (!this.data.employeeId || !this.data.organizationId) {\n throw new Error('employeeId and organizationId are required');\n }\n if (!this.data.baseAmount) {\n throw new Error('baseAmount is required');\n }\n\n return PayrollFactory.create(this.data as CreatePayrollParams);\n }\n}\n\n// ============================================================================\n// Batch Payroll Factory\n// ============================================================================\n\nexport class BatchPayrollFactory {\n /**\n * Create payroll records for multiple employees\n */\n static createBatch(\n employees: Array<{\n _id: ObjectIdLike;\n organizationId: ObjectIdLike;\n compensation: Compensation;\n }>,\n params: { month: number; year: number; organizationId?: ObjectIdLike }\n ): PayrollData[] {\n return employees.map((employee) =>\n PayrollFactory.create({\n employeeId: employee._id,\n organizationId: params.organizationId || employee.organizationId,\n baseAmount: employee.compensation.baseAmount,\n allowances: employee.compensation.allowances || [],\n deductions: employee.compensation.deductions || [],\n period: { month: params.month, year: params.year },\n metadata: { currency: employee.compensation.currency },\n })\n );\n }\n\n /**\n * Calculate total payroll amounts\n */\n static calculateTotalPayroll(payrolls: Array<{ breakdown: PayrollBreakdown }>): {\n count: number;\n totalGross: number;\n totalNet: number;\n totalAllowances: number;\n totalDeductions: number;\n } {\n return payrolls.reduce(\n (totals, payroll) => ({\n count: totals.count + 1,\n totalGross: totals.totalGross + payroll.breakdown.grossSalary,\n totalNet: totals.totalNet + payroll.breakdown.netSalary,\n totalAllowances: totals.totalAllowances + sumAllowances(payroll.breakdown.allowances),\n totalDeductions: totals.totalDeductions + sumDeductions(payroll.breakdown.deductions),\n }),\n { count: 0, totalGross: 0, totalNet: 0, totalAllowances: 0, totalDeductions: 0 }\n );\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create new payroll builder\n */\nexport function createPayroll(): PayrollBuilder {\n return new PayrollBuilder();\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n PayrollFactory,\n PayrollBuilder,\n BatchPayrollFactory,\n createPayroll,\n};\n\n","/**\n * @classytic/payroll - Payroll Service\n *\n * High-level payroll operations with dependency injection\n */\n\nimport type { Model, ClientSession } from 'mongoose';\nimport type {\n ObjectIdLike,\n PayrollRecordDocument,\n EmployeeDocument,\n PayrollStatus,\n PaymentMethod,\n} from '../types.js';\nimport {\n PayrollFactory,\n BatchPayrollFactory,\n type PayrollData,\n} from '../factories/payroll.factory.js';\nimport { payroll as payrollQuery, toObjectId } from '../utils/query-builders.js';\nimport { getCurrentPeriod } from '../utils/date.js';\nimport { canReceiveSalary } from '../utils/validation.js';\nimport { logger } from '../utils/logger.js';\nimport type { EmployeeService } from './employee.service.js';\n\n// ============================================================================\n// Payroll Service\n// ============================================================================\n\nexport class PayrollService {\n constructor(\n private readonly PayrollModel: Model<PayrollRecordDocument>,\n private readonly employeeService: EmployeeService\n ) {}\n\n /**\n * Find payroll by ID\n */\n async findById(\n payrollId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument | null> {\n let query = this.PayrollModel.findById(toObjectId(payrollId));\n \n if (options.session) {\n query = query.session(options.session);\n }\n \n return query.exec();\n }\n\n /**\n * Find payrolls by employee\n */\n async findByEmployee(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike,\n options: { session?: ClientSession; limit?: number } = {}\n ): Promise<PayrollRecordDocument[]> {\n const query = payrollQuery()\n .forEmployee(employeeId)\n .forOrganization(organizationId)\n .build();\n\n let mongooseQuery = this.PayrollModel.find(query)\n .sort({ 'period.year': -1, 'period.month': -1 })\n .limit(options.limit || 12);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n return mongooseQuery.exec();\n }\n\n /**\n * Find payrolls for a period\n */\n async findForPeriod(\n organizationId: ObjectIdLike,\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument[]> {\n const query = payrollQuery()\n .forOrganization(organizationId)\n .forPeriod(month, year)\n .build();\n\n let mongooseQuery = this.PayrollModel.find(query);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n return mongooseQuery.exec();\n }\n\n /**\n * Find pending payrolls\n */\n async findPending(\n organizationId: ObjectIdLike,\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument[]> {\n const query = payrollQuery()\n .forOrganization(organizationId)\n .forPeriod(month, year)\n .pending()\n .build();\n\n let mongooseQuery = this.PayrollModel.find(query);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n return mongooseQuery.exec();\n }\n\n /**\n * Find payroll by employee and period\n */\n async findByEmployeeAndPeriod(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike,\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument | null> {\n const query = payrollQuery()\n .forEmployee(employeeId)\n .forOrganization(organizationId)\n .forPeriod(month, year)\n .build();\n\n let mongooseQuery = this.PayrollModel.findOne(query);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n return mongooseQuery.exec();\n }\n\n /**\n * Create payroll record\n */\n async create(\n data: PayrollData,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument> {\n const [payroll] = await this.PayrollModel.create([data], {\n session: options.session,\n });\n\n logger.info('Payroll record created', {\n payrollId: payroll._id.toString(),\n employeeId: payroll.employeeId.toString(),\n });\n\n return payroll;\n }\n\n /**\n * Generate payroll for employee with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization\n */\n async generateForEmployee(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike,\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument> {\n // Use secure findById with org validation\n const employee = await this.employeeService.findById(employeeId, organizationId, options);\n if (!employee) {\n throw new Error(`Employee not found in organization ${organizationId}`);\n }\n\n if (!canReceiveSalary(employee)) {\n throw new Error('Employee not eligible for payroll');\n }\n\n // Check if payroll already exists\n const existing = await this.findByEmployeeAndPeriod(\n employeeId,\n organizationId,\n month,\n year,\n options\n );\n if (existing) {\n throw new Error('Payroll already exists for this period');\n }\n\n const payrollData = PayrollFactory.create({\n employeeId,\n organizationId,\n baseAmount: employee.compensation.baseAmount,\n allowances: employee.compensation.allowances || [],\n deductions: employee.compensation.deductions || [],\n period: { month, year },\n metadata: { currency: employee.compensation.currency },\n });\n\n return this.create(payrollData, options);\n }\n\n /**\n * Generate batch payroll\n */\n async generateBatch(\n organizationId: ObjectIdLike,\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<{\n success: boolean;\n generated: number;\n skipped: number;\n payrolls: PayrollRecordDocument[];\n message: string;\n }> {\n const employees = await this.employeeService.findEligibleForPayroll(\n organizationId,\n options\n );\n\n if (employees.length === 0) {\n return {\n success: true,\n generated: 0,\n skipped: 0,\n payrolls: [],\n message: 'No eligible employees',\n };\n }\n\n // Get existing payrolls\n const existingPayrolls = await this.findForPeriod(\n organizationId,\n month,\n year,\n options\n );\n const existingEmployeeIds = new Set(\n existingPayrolls.map((p) => p.employeeId.toString())\n );\n\n // Filter out employees who already have payroll\n const eligibleEmployees = employees.filter(\n (emp) => !existingEmployeeIds.has(emp._id.toString())\n );\n\n if (eligibleEmployees.length === 0) {\n return {\n success: true,\n generated: 0,\n skipped: employees.length,\n payrolls: [],\n message: 'Payrolls already exist for all employees',\n };\n }\n\n const payrollsData = BatchPayrollFactory.createBatch(eligibleEmployees, {\n month,\n year,\n organizationId,\n });\n\n const created = await this.PayrollModel.insertMany(payrollsData, {\n session: options.session,\n });\n\n logger.info('Batch payroll generated', {\n organizationId: organizationId.toString(),\n month,\n year,\n count: created.length,\n });\n\n return {\n success: true,\n generated: created.length,\n skipped: existingEmployeeIds.size,\n payrolls: created as PayrollRecordDocument[],\n message: `Generated ${created.length} payrolls`,\n };\n }\n\n /**\n * Mark payroll as paid with organization validation\n * \n * ⚠️ SECURITY: Validates payroll belongs to organization\n */\n async markAsPaid(\n payrollId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n paymentDetails: {\n paidAt?: Date;\n transactionId?: ObjectIdLike;\n paymentMethod?: PaymentMethod;\n } = {},\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument> {\n // Verify payroll belongs to organization\n const query = {\n _id: toObjectId(payrollId),\n organizationId: toObjectId(organizationId),\n };\n\n let payrollFindQuery = this.PayrollModel.findOne(query);\n if (options.session) {\n payrollFindQuery = payrollFindQuery.session(options.session);\n }\n \n const payroll = await payrollFindQuery;\n if (!payroll) {\n throw new Error(`Payroll not found in organization ${organizationId}`);\n }\n\n if (payroll.status === 'paid') {\n throw new Error('Payroll already paid');\n }\n\n const payrollObj = payroll.toObject() as {\n status: string;\n paidAt: Date | null;\n processedAt: Date | null;\n metadata: Record<string, unknown>;\n };\n const updatedData = PayrollFactory.markAsPaid(payrollObj, paymentDetails);\n\n const updated = await this.PayrollModel.findByIdAndUpdate(\n payrollId,\n updatedData,\n { new: true, runValidators: true, session: options.session }\n );\n\n if (!updated) {\n throw new Error('Failed to update payroll');\n }\n\n logger.info('Payroll marked as paid', {\n payrollId: payrollId.toString(),\n });\n\n return updated;\n }\n\n /**\n * Mark payroll as processed with organization validation\n * \n * ⚠️ SECURITY: Validates payroll belongs to organization\n */\n async markAsProcessed(\n payrollId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument> {\n // Verify payroll belongs to organization\n const query = {\n _id: toObjectId(payrollId),\n organizationId: toObjectId(organizationId),\n };\n\n let payrollFindQuery = this.PayrollModel.findOne(query);\n if (options.session) {\n payrollFindQuery = payrollFindQuery.session(options.session);\n }\n \n const payroll = await payrollFindQuery;\n if (!payroll) {\n throw new Error(`Payroll not found in organization ${organizationId}`);\n }\n\n const payrollObj = payroll.toObject() as { status: string; processedAt: Date | null };\n const updatedData = PayrollFactory.markAsProcessed(payrollObj);\n\n const updated = await this.PayrollModel.findByIdAndUpdate(\n payrollId,\n updatedData,\n { new: true, runValidators: true, session: options.session }\n );\n\n if (!updated) {\n throw new Error('Failed to update payroll');\n }\n\n return updated;\n }\n\n /**\n * Calculate period summary\n */\n async calculatePeriodSummary(\n organizationId: ObjectIdLike,\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<{\n period: { month: number; year: number };\n count: number;\n totalGross: number;\n totalNet: number;\n totalAllowances: number;\n totalDeductions: number;\n byStatus: Record<string, number>;\n }> {\n const payrolls = await this.findForPeriod(organizationId, month, year, options);\n const summary = BatchPayrollFactory.calculateTotalPayroll(payrolls);\n\n return {\n period: { month, year },\n ...summary,\n byStatus: this.groupByStatus(payrolls),\n };\n }\n\n /**\n * Get employee payroll history\n */\n async getEmployeePayrollHistory(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike,\n limit = 12,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument[]> {\n return this.findByEmployee(employeeId, organizationId, { ...options, limit });\n }\n\n /**\n * Get overview stats\n */\n async getOverviewStats(\n organizationId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<{\n currentPeriod: { month: number; year: number };\n count: number;\n totalGross: number;\n totalNet: number;\n totalAllowances: number;\n totalDeductions: number;\n byStatus: Record<string, number>;\n }> {\n const { month, year } = getCurrentPeriod();\n const result = await this.calculatePeriodSummary(organizationId, month, year, options);\n return {\n currentPeriod: result.period,\n count: result.count,\n totalGross: result.totalGross,\n totalNet: result.totalNet,\n totalAllowances: result.totalAllowances,\n totalDeductions: result.totalDeductions,\n byStatus: result.byStatus,\n };\n }\n\n /**\n * Group payrolls by status\n */\n private groupByStatus(payrolls: PayrollRecordDocument[]): Record<string, number> {\n return payrolls.reduce(\n (acc, payroll) => {\n acc[payroll.status] = (acc[payroll.status] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>\n );\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create payroll service instance\n */\nexport function createPayrollService(\n PayrollModel: Model<PayrollRecordDocument>,\n employeeService: EmployeeService\n): PayrollService {\n return new PayrollService(PayrollModel, employeeService);\n}\n\n","/**\n * @classytic/payroll - Compensation Factory\n *\n * Clean compensation structure creation\n * Presets for common compensation packages\n */\n\nimport type {\n Compensation,\n Allowance,\n Deduction,\n PaymentFrequency,\n CompensationBreakdownResult,\n} from '../types.js';\nimport { calculateGross, calculateNet, applyPercentage } from '../utils/calculation.js';\nimport { HRM_CONFIG } from '../config.js';\n\n// ============================================================================\n// Compensation Factory Types\n// ============================================================================\n\nexport interface CreateCompensationParams {\n baseAmount: number;\n frequency?: PaymentFrequency;\n currency?: string;\n allowances?: Array<{\n type: Allowance['type'];\n value: number;\n isPercentage?: boolean;\n name?: string;\n taxable?: boolean;\n }>;\n deductions?: Array<{\n type: Deduction['type'];\n value: number;\n isPercentage?: boolean;\n name?: string;\n auto?: boolean;\n }>;\n effectiveFrom?: Date;\n}\n\n// ============================================================================\n// Compensation Factory\n// ============================================================================\n\nexport class CompensationFactory {\n /**\n * Create compensation object\n */\n static create(params: CreateCompensationParams): Compensation {\n const {\n baseAmount,\n frequency = 'monthly',\n currency = HRM_CONFIG.payroll.defaultCurrency,\n allowances = [],\n deductions = [],\n effectiveFrom = new Date(),\n } = params;\n\n return {\n baseAmount,\n frequency,\n currency,\n allowances: allowances.map((a) => this.createAllowance(a, baseAmount)),\n deductions: deductions.map((d) => this.createDeduction(d, baseAmount)),\n effectiveFrom,\n lastModified: new Date(),\n };\n }\n\n /**\n * Create allowance\n */\n static createAllowance(\n params: {\n type: Allowance['type'];\n value: number;\n isPercentage?: boolean;\n name?: string;\n taxable?: boolean;\n },\n baseAmount?: number\n ): Allowance {\n const amount = params.isPercentage && baseAmount\n ? applyPercentage(baseAmount, params.value)\n : params.value;\n\n return {\n type: params.type,\n name: params.name || params.type,\n amount,\n isPercentage: params.isPercentage ?? false,\n value: params.isPercentage ? params.value : undefined,\n taxable: params.taxable ?? true,\n recurring: true,\n effectiveFrom: new Date(),\n };\n }\n\n /**\n * Create deduction\n */\n static createDeduction(\n params: {\n type: Deduction['type'];\n value: number;\n isPercentage?: boolean;\n name?: string;\n auto?: boolean;\n },\n baseAmount?: number\n ): Deduction {\n const amount = params.isPercentage && baseAmount\n ? applyPercentage(baseAmount, params.value)\n : params.value;\n\n return {\n type: params.type,\n name: params.name || params.type,\n amount,\n isPercentage: params.isPercentage ?? false,\n value: params.isPercentage ? params.value : undefined,\n auto: params.auto ?? false,\n recurring: true,\n effectiveFrom: new Date(),\n };\n }\n\n /**\n * Update base amount (immutable)\n */\n static updateBaseAmount(\n compensation: Compensation,\n newAmount: number,\n effectiveFrom = new Date()\n ): Compensation {\n return {\n ...compensation,\n baseAmount: newAmount,\n lastModified: effectiveFrom,\n };\n }\n\n /**\n * Add allowance (immutable)\n */\n static addAllowance(\n compensation: Compensation,\n allowance: Parameters<typeof this.createAllowance>[0]\n ): Compensation {\n return {\n ...compensation,\n allowances: [\n ...compensation.allowances,\n this.createAllowance(allowance, compensation.baseAmount),\n ],\n lastModified: new Date(),\n };\n }\n\n /**\n * Remove allowance (immutable)\n */\n static removeAllowance(\n compensation: Compensation,\n allowanceType: Allowance['type']\n ): Compensation {\n return {\n ...compensation,\n allowances: compensation.allowances.filter((a) => a.type !== allowanceType),\n lastModified: new Date(),\n };\n }\n\n /**\n * Add deduction (immutable)\n */\n static addDeduction(\n compensation: Compensation,\n deduction: Parameters<typeof this.createDeduction>[0]\n ): Compensation {\n return {\n ...compensation,\n deductions: [\n ...compensation.deductions,\n this.createDeduction(deduction, compensation.baseAmount),\n ],\n lastModified: new Date(),\n };\n }\n\n /**\n * Remove deduction (immutable)\n */\n static removeDeduction(\n compensation: Compensation,\n deductionType: Deduction['type']\n ): Compensation {\n return {\n ...compensation,\n deductions: compensation.deductions.filter((d) => d.type !== deductionType),\n lastModified: new Date(),\n };\n }\n\n /**\n * Calculate compensation breakdown\n */\n static calculateBreakdown(compensation: Compensation): CompensationBreakdownResult {\n const { baseAmount, allowances, deductions } = compensation;\n\n // Calculate actual amounts for percentage-based items\n const calculatedAllowances = allowances.map((a) => ({\n ...a,\n calculatedAmount: a.isPercentage && a.value !== undefined\n ? applyPercentage(baseAmount, a.value)\n : a.amount,\n }));\n\n const calculatedDeductions = deductions.map((d) => ({\n ...d,\n calculatedAmount: d.isPercentage && d.value !== undefined\n ? applyPercentage(baseAmount, d.value)\n : d.amount,\n }));\n\n const grossAmount = calculateGross(\n baseAmount,\n calculatedAllowances.map((a) => ({ amount: a.calculatedAmount }))\n );\n const netAmount = calculateNet(\n grossAmount,\n calculatedDeductions.map((d) => ({ amount: d.calculatedAmount }))\n );\n\n return {\n baseAmount,\n allowances: calculatedAllowances,\n deductions: calculatedDeductions,\n grossAmount,\n netAmount: Math.max(0, netAmount),\n };\n }\n\n /**\n * Apply salary increment (immutable)\n */\n static applyIncrement(\n compensation: Compensation,\n params: { percentage?: number; amount?: number; effectiveFrom?: Date }\n ): Compensation {\n const newBaseAmount = params.amount\n ? compensation.baseAmount + params.amount\n : compensation.baseAmount * (1 + (params.percentage || 0) / 100);\n\n return this.updateBaseAmount(\n compensation,\n Math.round(newBaseAmount),\n params.effectiveFrom\n );\n }\n}\n\n// ============================================================================\n// Compensation Builder\n// ============================================================================\n\nexport class CompensationBuilder {\n private data: CreateCompensationParams = {\n baseAmount: 0,\n frequency: 'monthly',\n currency: HRM_CONFIG.payroll.defaultCurrency,\n allowances: [],\n deductions: [],\n };\n\n /**\n * Set base amount\n */\n withBase(\n amount: number,\n frequency: PaymentFrequency = 'monthly',\n currency = HRM_CONFIG.payroll.defaultCurrency\n ): this {\n this.data.baseAmount = amount;\n this.data.frequency = frequency;\n this.data.currency = currency;\n return this;\n }\n\n /**\n * Add allowance\n */\n addAllowance(\n type: Allowance['type'],\n value: number,\n isPercentage = false,\n name?: string\n ): this {\n this.data.allowances = [\n ...(this.data.allowances || []),\n { type, value, isPercentage, name },\n ];\n return this;\n }\n\n /**\n * Add deduction\n */\n addDeduction(\n type: Deduction['type'],\n value: number,\n isPercentage = false,\n name?: string\n ): this {\n this.data.deductions = [\n ...(this.data.deductions || []),\n { type, value, isPercentage, name },\n ];\n return this;\n }\n\n /**\n * Set effective date\n */\n effectiveFrom(date: Date): this {\n this.data.effectiveFrom = date;\n return this;\n }\n\n /**\n * Build compensation\n */\n build(): Compensation {\n if (!this.data.baseAmount) {\n throw new Error('baseAmount is required');\n }\n return CompensationFactory.create(this.data);\n }\n}\n\n// ============================================================================\n// Compensation Presets\n// ============================================================================\n\nexport const CompensationPresets = {\n /**\n * Basic compensation (base only)\n */\n basic(baseAmount: number): Compensation {\n return new CompensationBuilder()\n .withBase(baseAmount)\n .build();\n },\n\n /**\n * With house rent allowance\n */\n withHouseRent(baseAmount: number, rentPercentage = 50): Compensation {\n return new CompensationBuilder()\n .withBase(baseAmount)\n .addAllowance('housing', rentPercentage, true, 'House Rent')\n .build();\n },\n\n /**\n * With medical allowance\n */\n withMedical(baseAmount: number, medicalPercentage = 10): Compensation {\n return new CompensationBuilder()\n .withBase(baseAmount)\n .addAllowance('medical', medicalPercentage, true, 'Medical Allowance')\n .build();\n },\n\n /**\n * Standard package (house rent + medical + transport)\n */\n standard(baseAmount: number): Compensation {\n return new CompensationBuilder()\n .withBase(baseAmount)\n .addAllowance('housing', 50, true, 'House Rent')\n .addAllowance('medical', 10, true, 'Medical Allowance')\n .addAllowance('transport', 5, true, 'Transport Allowance')\n .build();\n },\n\n /**\n * With provident fund\n */\n withProvidentFund(baseAmount: number, pfPercentage = 10): Compensation {\n return new CompensationBuilder()\n .withBase(baseAmount)\n .addAllowance('housing', 50, true, 'House Rent')\n .addAllowance('medical', 10, true, 'Medical Allowance')\n .addDeduction('provident_fund', pfPercentage, true, 'Provident Fund')\n .build();\n },\n\n /**\n * Executive package\n */\n executive(baseAmount: number): Compensation {\n return new CompensationBuilder()\n .withBase(baseAmount)\n .addAllowance('housing', 60, true, 'House Rent')\n .addAllowance('medical', 15, true, 'Medical Allowance')\n .addAllowance('transport', 10, true, 'Transport Allowance')\n .addAllowance('mobile', 5, true, 'Mobile Allowance')\n .addDeduction('provident_fund', 10, true, 'Provident Fund')\n .build();\n },\n};\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create new compensation builder\n */\nexport function createCompensation(): CompensationBuilder {\n return new CompensationBuilder();\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n CompensationFactory,\n CompensationBuilder,\n CompensationPresets,\n createCompensation,\n};\n\n","/**\n * @classytic/payroll - Compensation Service\n *\n * High-level compensation operations with dependency injection\n */\n\nimport type { Model, ClientSession } from 'mongoose';\nimport type {\n ObjectIdLike,\n EmployeeDocument,\n Compensation,\n Allowance,\n Deduction,\n Department,\n CompensationBreakdownResult,\n} from '../types.js';\nimport {\n CompensationFactory,\n CompensationPresets,\n} from '../factories/compensation.factory.js';\nimport { toObjectId } from '../utils/query-builders.js';\nimport { logger } from '../utils/logger.js';\n\n// ============================================================================\n// Compensation Service\n// ============================================================================\n\nexport class CompensationService {\n constructor(private readonly EmployeeModel: Model<EmployeeDocument>) {}\n\n /**\n * Get employee compensation with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization\n */\n async getEmployeeCompensation(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n options: { session?: ClientSession } = {}\n ): Promise<Compensation> {\n const employee = await this.findEmployee(employeeId, organizationId, options);\n return employee.compensation;\n }\n\n /**\n * Calculate compensation breakdown with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization\n */\n async calculateBreakdown(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const compensation = await this.getEmployeeCompensation(employeeId, organizationId, options);\n return CompensationFactory.calculateBreakdown(compensation);\n }\n\n /**\n * Update base amount with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization before update\n */\n async updateBaseAmount(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n newAmount: number,\n effectiveFrom = new Date(),\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, organizationId, options);\n\n const updatedCompensation = CompensationFactory.updateBaseAmount(\n employee.compensation,\n newAmount,\n effectiveFrom\n );\n\n employee.compensation = updatedCompensation;\n await employee.save({ session: options.session });\n\n logger.info('Compensation base amount updated', {\n employeeId: employee.employeeId,\n organizationId: organizationId.toString(),\n newAmount,\n });\n\n return this.calculateBreakdown(employeeId, organizationId, options);\n }\n\n /**\n * Apply salary increment with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization before update\n */\n async applyIncrement(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n params: { percentage?: number; amount?: number; effectiveFrom?: Date },\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, organizationId, options);\n const previousAmount = employee.compensation.baseAmount;\n\n const updatedCompensation = CompensationFactory.applyIncrement(\n employee.compensation,\n params\n );\n\n employee.compensation = updatedCompensation;\n await employee.save({ session: options.session });\n\n logger.info('Salary increment applied', {\n employeeId: employee.employeeId,\n organizationId: organizationId.toString(),\n previousAmount,\n newAmount: updatedCompensation.baseAmount,\n percentage: params.percentage,\n });\n\n return this.calculateBreakdown(employeeId, organizationId, options);\n }\n\n /**\n * Add allowance with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization before update\n */\n async addAllowance(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n allowance: {\n type: Allowance['type'];\n value: number;\n isPercentage?: boolean;\n name?: string;\n taxable?: boolean;\n },\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, organizationId, options);\n\n const updatedCompensation = CompensationFactory.addAllowance(\n employee.compensation,\n allowance\n );\n\n employee.compensation = updatedCompensation;\n await employee.save({ session: options.session });\n\n logger.info('Allowance added', {\n employeeId: employee.employeeId,\n organizationId: organizationId.toString(),\n type: allowance.type,\n value: allowance.value,\n });\n\n return this.calculateBreakdown(employeeId, organizationId, options);\n }\n\n /**\n * Remove allowance with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization before update\n */\n async removeAllowance(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n allowanceType: Allowance['type'],\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, organizationId, options);\n\n const updatedCompensation = CompensationFactory.removeAllowance(\n employee.compensation,\n allowanceType\n );\n\n employee.compensation = updatedCompensation;\n await employee.save({ session: options.session });\n\n logger.info('Allowance removed', {\n employeeId: employee.employeeId,\n organizationId: organizationId.toString(),\n type: allowanceType,\n });\n\n return this.calculateBreakdown(employeeId, organizationId, options);\n }\n\n /**\n * Add deduction with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization before update\n */\n async addDeduction(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n deduction: {\n type: Deduction['type'];\n value: number;\n isPercentage?: boolean;\n name?: string;\n auto?: boolean;\n },\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, organizationId, options);\n\n const updatedCompensation = CompensationFactory.addDeduction(\n employee.compensation,\n deduction\n );\n\n employee.compensation = updatedCompensation;\n await employee.save({ session: options.session });\n\n logger.info('Deduction added', {\n employeeId: employee.employeeId,\n organizationId: organizationId.toString(),\n type: deduction.type,\n value: deduction.value,\n });\n\n return this.calculateBreakdown(employeeId, organizationId, options);\n }\n\n /**\n * Remove deduction with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization before update\n */\n async removeDeduction(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n deductionType: Deduction['type'],\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, organizationId, options);\n\n const updatedCompensation = CompensationFactory.removeDeduction(\n employee.compensation,\n deductionType\n );\n\n employee.compensation = updatedCompensation;\n await employee.save({ session: options.session });\n\n logger.info('Deduction removed', {\n employeeId: employee.employeeId,\n organizationId: organizationId.toString(),\n type: deductionType,\n });\n\n return this.calculateBreakdown(employeeId, organizationId, options);\n }\n\n /**\n * Set standard compensation with organization validation\n * \n * ⚠️ SECURITY: Validates employee belongs to organization before update\n */\n async setStandardCompensation(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n baseAmount: number,\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, organizationId, options);\n\n employee.compensation = CompensationPresets.standard(baseAmount);\n await employee.save({ session: options.session });\n\n logger.info('Standard compensation set', {\n employeeId: employee.employeeId,\n organizationId: organizationId.toString(),\n baseAmount,\n });\n\n return this.calculateBreakdown(employeeId, organizationId, options);\n }\n\n /**\n * Compare compensation between two employees\n * \n * ⚠️ SECURITY: Validates both employees belong to organization\n */\n async compareCompensation(\n employeeId1: ObjectIdLike,\n employeeId2: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n options: { session?: ClientSession } = {}\n ): Promise<{\n employee1: CompensationBreakdownResult;\n employee2: CompensationBreakdownResult;\n difference: { base: number; gross: number; net: number };\n ratio: { base: number; gross: number; net: number };\n }> {\n const breakdown1 = await this.calculateBreakdown(employeeId1, organizationId, options);\n const breakdown2 = await this.calculateBreakdown(employeeId2, organizationId, options);\n\n return {\n employee1: breakdown1,\n employee2: breakdown2,\n difference: {\n base: breakdown2.baseAmount - breakdown1.baseAmount,\n gross: breakdown2.grossAmount - breakdown1.grossAmount,\n net: breakdown2.netAmount - breakdown1.netAmount,\n },\n ratio: {\n base: breakdown1.baseAmount > 0 ? breakdown2.baseAmount / breakdown1.baseAmount : 0,\n gross: breakdown1.grossAmount > 0 ? breakdown2.grossAmount / breakdown1.grossAmount : 0,\n net: breakdown1.netAmount > 0 ? breakdown2.netAmount / breakdown1.netAmount : 0,\n },\n };\n }\n\n /**\n * Get department compensation stats\n */\n async getDepartmentCompensationStats(\n organizationId: ObjectIdLike,\n department: Department,\n options: { session?: ClientSession } = {}\n ): Promise<{\n department: string;\n employeeCount: number;\n totalBase: number;\n totalGross: number;\n totalNet: number;\n averageBase: number;\n averageGross: number;\n averageNet: number;\n }> {\n let query = this.EmployeeModel.find({\n organizationId: toObjectId(organizationId),\n department,\n status: { $in: ['active', 'on_leave'] },\n });\n\n if (options.session) {\n query = query.session(options.session);\n }\n\n const employees = await query.exec();\n\n const breakdowns = employees.map((emp) =>\n CompensationFactory.calculateBreakdown(emp.compensation)\n );\n\n const totals = breakdowns.reduce(\n (acc, breakdown) => ({\n totalBase: acc.totalBase + breakdown.baseAmount,\n totalGross: acc.totalGross + breakdown.grossAmount,\n totalNet: acc.totalNet + breakdown.netAmount,\n }),\n { totalBase: 0, totalGross: 0, totalNet: 0 }\n );\n\n const count = employees.length || 1;\n\n return {\n department,\n employeeCount: employees.length,\n ...totals,\n averageBase: Math.round(totals.totalBase / count),\n averageGross: Math.round(totals.totalGross / count),\n averageNet: Math.round(totals.totalNet / count),\n };\n }\n\n /**\n * Get organization compensation stats\n */\n async getOrganizationCompensationStats(\n organizationId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<{\n employeeCount: number;\n totalBase: number;\n totalGross: number;\n totalNet: number;\n averageBase: number;\n averageGross: number;\n averageNet: number;\n byDepartment: Record<string, { count: number; totalNet: number }>;\n }> {\n let query = this.EmployeeModel.find({\n organizationId: toObjectId(organizationId),\n status: { $in: ['active', 'on_leave'] },\n });\n\n if (options.session) {\n query = query.session(options.session);\n }\n\n const employees = await query.exec();\n\n const breakdowns = employees.map((emp) =>\n CompensationFactory.calculateBreakdown(emp.compensation)\n );\n\n const totals = breakdowns.reduce(\n (acc, breakdown) => ({\n totalBase: acc.totalBase + breakdown.baseAmount,\n totalGross: acc.totalGross + breakdown.grossAmount,\n totalNet: acc.totalNet + breakdown.netAmount,\n }),\n { totalBase: 0, totalGross: 0, totalNet: 0 }\n );\n\n const byDepartment: Record<string, { count: number; totalNet: number }> = {};\n employees.forEach((emp, i) => {\n const dept = emp.department || 'unassigned';\n if (!byDepartment[dept]) {\n byDepartment[dept] = { count: 0, totalNet: 0 };\n }\n byDepartment[dept].count++;\n byDepartment[dept].totalNet += breakdowns[i].netAmount;\n });\n\n const count = employees.length || 1;\n\n return {\n employeeCount: employees.length,\n ...totals,\n averageBase: Math.round(totals.totalBase / count),\n averageGross: Math.round(totals.totalGross / count),\n averageNet: Math.round(totals.totalNet / count),\n byDepartment,\n };\n }\n\n /**\n * Find employee helper with organization validation\n * \n * ⚠️ SECURITY: Always validates employee belongs to organization\n */\n private async findEmployee(\n employeeId: ObjectIdLike,\n organizationId: ObjectIdLike, // Required for multi-tenant isolation\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument> {\n // Build secure query that enforces org isolation\n const query = {\n _id: toObjectId(employeeId),\n organizationId: toObjectId(organizationId),\n };\n\n let mongooseQuery = this.EmployeeModel.findOne(query);\n \n if (options.session) {\n mongooseQuery = mongooseQuery.session(options.session);\n }\n \n const employee = await mongooseQuery.exec();\n if (!employee) {\n throw new Error(`Employee not found in organization ${organizationId}`);\n }\n return employee;\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create compensation service instance\n */\nexport function createCompensationService(\n EmployeeModel: Model<EmployeeDocument>\n): CompensationService {\n return new CompensationService(EmployeeModel);\n}\n\n","/**\n * @classytic/payroll - Salary Calculator\n *\n * Pure functions for complete salary breakdown calculations.\n * No database dependencies - can be used client-side!\n *\n * This is the SINGLE SOURCE OF TRUTH for all salary calculations.\n *\n * @packageDocumentation\n */\n\nimport type {\n Compensation,\n PayrollBreakdown,\n Allowance,\n Deduction,\n TaxBracket,\n} from '../types.js';\nimport { calculateGross, calculateNet, sumAllowances, sumDeductions, applyTaxBrackets } from '../utils/calculation.js';\nimport { countWorkingDays } from '../core/config.js';\nimport { calculateProRating, type ProRatingInput, type ProRatingResult } from './prorating.calculator.js';\nimport { calculateAttendanceDeduction, calculateDailyRate, type AttendanceDeductionInput } from './attendance.calculator.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Input for salary breakdown calculation\n */\nexport interface SalaryCalculationInput {\n /**\n * Employee data (minimal subset needed for calculation)\n */\n employee: {\n hireDate: Date;\n terminationDate?: Date | null;\n compensation: Compensation;\n workSchedule?: {\n workingDays?: number[];\n hoursPerDay?: number;\n };\n };\n\n /**\n * Salary period\n */\n period: {\n month: number;\n year: number;\n startDate: Date;\n endDate: Date;\n };\n\n /**\n * Attendance data (optional)\n */\n attendance?: {\n expectedDays?: number;\n actualDays?: number;\n } | null;\n\n /**\n * Processing options\n */\n options?: {\n holidays?: Date[];\n workSchedule?: {\n workingDays?: number[];\n hoursPerDay?: number;\n };\n skipTax?: boolean;\n skipAttendance?: boolean;\n skipProration?: boolean;\n };\n\n /**\n * Configuration (minimal subset)\n */\n config: {\n allowProRating: boolean;\n autoDeductions: boolean;\n defaultCurrency: string;\n attendanceIntegration: boolean;\n };\n\n /**\n * Tax brackets for the employee's currency\n */\n taxBrackets: TaxBracket[];\n}\n\n/**\n * Processed allowance with calculated amount\n */\nexport interface ProcessedAllowance {\n type: string;\n amount: number;\n taxable: boolean;\n originalAmount?: number; // Before pro-rating\n isPercentage?: boolean;\n value?: number;\n}\n\n/**\n * Processed deduction with calculated amount\n */\nexport interface ProcessedDeduction {\n type: string;\n amount: number;\n description?: string;\n originalAmount?: number; // Before pro-rating\n isPercentage?: boolean;\n value?: number;\n}\n\n// ============================================================================\n// Pure Functions\n// ============================================================================\n\n/**\n * Calculate complete salary breakdown\n *\n * This is the SINGLE SOURCE OF TRUTH for salary calculations.\n * All payroll processing uses this function.\n *\n * @example\n * ```typescript\n * const breakdown = calculateSalaryBreakdown({\n * employee: {\n * hireDate: new Date('2024-01-01'),\n * compensation: {\n * baseAmount: 100000,\n * currency: 'USD',\n * allowances: [{ type: 'housing', amount: 20000, taxable: true }],\n * deductions: [{ type: 'insurance', amount: 5000 }],\n * },\n * },\n * period: {\n * month: 3,\n * year: 2024,\n * startDate: new Date('2024-03-01'),\n * endDate: new Date('2024-03-31'),\n * },\n * attendance: {\n * expectedDays: 22,\n * actualDays: 20, // 2 days absent\n * },\n * options: {\n * holidays: [new Date('2024-03-26')],\n * },\n * config: {\n * allowProRating: true,\n * autoDeductions: true,\n * defaultCurrency: 'USD',\n * attendanceIntegration: true,\n * },\n * taxBrackets: [...],\n * });\n * ```\n *\n * @param input - Salary calculation parameters\n * @returns Complete payroll breakdown\n *\n * @pure This function has no side effects and doesn't access database\n */\nexport function calculateSalaryBreakdown(input: SalaryCalculationInput): PayrollBreakdown {\n const { employee, period, attendance, options = {}, config, taxBrackets } = input;\n\n const comp = employee.compensation;\n const originalBaseAmount = comp.baseAmount;\n\n // 1. Calculate pro-rating (if applicable)\n const proRating = calculateProRatingForSalary(\n employee.hireDate,\n employee.terminationDate || null,\n period.startDate,\n period.endDate,\n options,\n employee.workSchedule\n );\n\n // 2. Apply pro-rating to base salary\n let baseAmount = originalBaseAmount;\n if (proRating.isProRated && config.allowProRating && !options.skipProration) {\n baseAmount = Math.round(baseAmount * proRating.ratio);\n }\n\n // 3. Filter allowances by effective date\n const effectiveAllowances = (comp.allowances || [])\n .filter((a) => isEffectiveForPeriod(a, period.startDate, period.endDate));\n\n // 4. Filter deductions by effective date\n const effectiveDeductions = (comp.deductions || [])\n .filter((d) => isEffectiveForPeriod(d, period.startDate, period.endDate))\n .filter((d) => d.auto || d.recurring);\n\n // 5. Calculate allowances (handle percentages and pro-rating)\n const allowances = processAllowances(effectiveAllowances, originalBaseAmount, proRating, config);\n\n // 6. Calculate deductions (handle percentages and pro-rating)\n const deductions = processDeductions(effectiveDeductions, originalBaseAmount, proRating, config);\n\n // 7. Calculate attendance deduction\n if (!options.skipAttendance && config.attendanceIntegration && attendance) {\n const attendanceDeductionResult = calculateAttendanceDeductionFromData(\n attendance,\n baseAmount,\n proRating.effectiveWorkingDays\n );\n\n if (attendanceDeductionResult.hasDeduction) {\n deductions.push({\n type: 'absence',\n amount: attendanceDeductionResult.deductionAmount,\n description: `Unpaid leave deduction (${attendanceDeductionResult.absentDays} days)`,\n });\n }\n }\n\n // 8. Calculate gross salary\n const grossSalary = calculateGross(baseAmount, allowances);\n\n // 9. Calculate taxable amount (only taxable allowances)\n const taxableAllowances = allowances.filter((a) => a.taxable);\n const taxableAmount = baseAmount + sumAllowances(taxableAllowances);\n\n // 10. Calculate tax\n let taxAmount = 0;\n if (!options.skipTax && taxBrackets.length > 0 && config.autoDeductions) {\n // Annualize the taxable amount for tax bracket calculation\n const annualTaxable = taxableAmount * 12;\n const annualTax = applyTaxBrackets(annualTaxable, taxBrackets);\n taxAmount = Math.round(annualTax / 12); // Monthly tax\n }\n\n // Add tax to deductions if applicable\n if (taxAmount > 0) {\n deductions.push({\n type: 'tax',\n amount: taxAmount,\n description: 'Income tax',\n });\n }\n\n // 11. Calculate net salary\n const netSalary = calculateNet(grossSalary, deductions);\n\n // 12. Build final breakdown\n return {\n baseAmount,\n allowances,\n deductions,\n grossSalary,\n netSalary,\n taxableAmount,\n taxAmount,\n workingDays: proRating.periodWorkingDays,\n actualDays: proRating.effectiveWorkingDays,\n proRatedAmount: (proRating.isProRated && !options.skipProration) ? baseAmount : 0,\n attendanceDeduction: attendance\n ? deductions.find((d) => d.type === 'absence')?.amount || 0\n : 0,\n };\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Check if allowance/deduction is effective for a given period\n */\nfunction isEffectiveForPeriod(\n item: { effectiveFrom?: Date | null; effectiveTo?: Date | null },\n periodStart: Date,\n periodEnd: Date\n): boolean {\n const effectiveFrom = item.effectiveFrom ? new Date(item.effectiveFrom) : new Date(0);\n const effectiveTo = item.effectiveTo ? new Date(item.effectiveTo) : new Date('2099-12-31');\n\n // Item is effective if its range overlaps with the period\n return effectiveFrom <= periodEnd && effectiveTo >= periodStart;\n}\n\n/**\n * Calculate pro-rating for salary calculation\n */\nfunction calculateProRatingForSalary(\n hireDate: Date,\n terminationDate: Date | null,\n periodStart: Date,\n periodEnd: Date,\n options: SalaryCalculationInput['options'],\n employeeWorkSchedule?: { workingDays?: number[] }\n): ProRatingResult {\n // Work schedule: prefer operation override, then employee schedule, then Mon-Fri default\n const workingDays =\n options?.workSchedule?.workingDays ||\n employeeWorkSchedule?.workingDays ||\n [1, 2, 3, 4, 5];\n\n const holidays = options?.holidays || [];\n\n return calculateProRating({\n hireDate,\n terminationDate,\n periodStart,\n periodEnd,\n workingDays,\n holidays,\n });\n}\n\n/**\n * Process allowances (handle percentages and pro-rating)\n */\nfunction processAllowances(\n allowances: Allowance[],\n originalBaseAmount: number,\n proRating: ProRatingResult,\n config: SalaryCalculationInput['config']\n): ProcessedAllowance[] {\n return allowances.map((a) => {\n // Calculate from original base (percentage) or use fixed amount\n let amount = a.isPercentage && a.value !== undefined\n ? Math.round((originalBaseAmount * a.value) / 100)\n : a.amount;\n\n const originalAmount = amount;\n\n // Apply pro-rating ONCE if needed\n if (proRating.isProRated && config.allowProRating) {\n amount = Math.round(amount * proRating.ratio);\n }\n\n return {\n type: a.type,\n amount,\n taxable: a.taxable ?? true,\n originalAmount,\n isPercentage: a.isPercentage,\n value: a.value,\n };\n });\n}\n\n/**\n * Process deductions (handle percentages and pro-rating)\n */\nfunction processDeductions(\n deductions: Deduction[],\n originalBaseAmount: number,\n proRating: ProRatingResult,\n config: SalaryCalculationInput['config']\n): ProcessedDeduction[] {\n return deductions.map((d) => {\n // Calculate from original base (percentage) or use fixed amount\n let amount = d.isPercentage && d.value !== undefined\n ? Math.round((originalBaseAmount * d.value) / 100)\n : d.amount;\n\n const originalAmount = amount;\n\n // Apply pro-rating ONCE if needed\n if (proRating.isProRated && config.allowProRating) {\n amount = Math.round(amount * proRating.ratio);\n }\n\n return {\n type: d.type,\n amount,\n description: d.description,\n originalAmount,\n isPercentage: d.isPercentage,\n value: d.value,\n };\n });\n}\n\n/**\n * Calculate attendance deduction from attendance data\n */\nfunction calculateAttendanceDeductionFromData(\n attendance: { expectedDays?: number; actualDays?: number },\n baseAmount: number,\n effectiveWorkingDays: number\n): {\n hasDeduction: boolean;\n deductionAmount: number;\n absentDays: number;\n} {\n const expectedDays = attendance.expectedDays ?? effectiveWorkingDays;\n const actualDays = attendance.actualDays;\n\n if (actualDays === undefined) {\n return { hasDeduction: false, deductionAmount: 0, absentDays: 0 };\n }\n\n // Daily rate based on expected working days for THIS employee in THIS period\n const dailyRate = calculateDailyRate(baseAmount, expectedDays);\n\n const result = calculateAttendanceDeduction({\n expectedWorkingDays: expectedDays,\n actualWorkingDays: actualDays,\n dailyRate,\n });\n\n return {\n hasDeduction: result.hasDeduction,\n deductionAmount: result.deductionAmount,\n absentDays: result.absentDays,\n };\n}\n\n","/**\n * @classytic/payroll - Configuration & Calculation Utilities\n *\n * DESIGN PRINCIPLES:\n * 1. Accept data, don't manage it\n * 2. Pure functions - easy to test, no side effects\n * 3. Smart defaults that work out of the box\n * 4. Override at operation time when needed\n *\n * The payroll package CALCULATES, it doesn't STORE calendars/holidays.\n * Your app manages that data and passes it when needed.\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Work schedule configuration */\nexport interface WorkSchedule {\n /** Working days (0=Sun, 1=Mon, ..., 6=Sat). Default: Mon-Fri */\n workingDays: number[];\n /** Hours per work day. Default: 8 */\n hoursPerDay: number;\n}\n\n/** Options passed when processing payroll */\nexport interface PayrollProcessingOptions {\n /** Holidays in this period (from YOUR app's holiday model) */\n holidays?: Date[];\n /** Override work schedule for this operation */\n workSchedule?: Partial<WorkSchedule>;\n /** Skip tax calculation */\n skipTax?: boolean;\n /** Skip proration (pay full amount regardless of hire/termination date) */\n skipProration?: boolean;\n /** Skip attendance deduction */\n skipAttendance?: boolean;\n}\n\n/** Working days calculation result */\nexport interface WorkingDaysResult {\n /** Total calendar days in period */\n totalDays: number;\n /** Working days (excluding weekends and holidays) */\n workingDays: number;\n /** Weekend days */\n weekends: number;\n /** Holiday count */\n holidays: number;\n}\n\n/** Proration calculation result */\nexport interface ProrationResult {\n /** Proration ratio (0-1) */\n ratio: number;\n /** Reason for proration */\n reason: 'full' | 'new_hire' | 'termination' | 'both';\n /** Whether salary should be prorated */\n isProrated: boolean;\n}\n\n/** Tax calculation result */\nexport interface TaxResult {\n /** Tax amount */\n amount: number;\n /** Effective tax rate */\n effectiveRate: number;\n}\n\n/** Attendance data (from YOUR attendance system) */\nexport interface AttendanceInput {\n /** Expected work days in period */\n expectedDays: number;\n /** Actual days worked */\n actualDays: number;\n}\n\n/** Complete salary calculation result */\nexport interface SalaryCalculationResult {\n /** Original base salary */\n baseSalary: number;\n /** Prorated base salary */\n proratedBase: number;\n /** Total allowances */\n totalAllowances: number;\n /** Total deductions (excluding tax) */\n totalDeductions: number;\n /** Attendance deduction */\n attendanceDeduction: number;\n /** Gross salary (prorated base + allowances) */\n grossSalary: number;\n /** Tax amount */\n taxAmount: number;\n /** Net salary (gross - all deductions - tax) */\n netSalary: number;\n /** Proration details */\n proration: ProrationResult;\n /** Working days details */\n workingDays: WorkingDaysResult;\n /** Itemized breakdown */\n breakdown: {\n allowances: Array<{ type: string; amount: number; taxable: boolean }>;\n deductions: Array<{ type: string; amount: number }>;\n };\n}\n\n// ============================================================================\n// Default Configuration\n// ============================================================================\n\n/**\n * Default tax brackets (US federal example)\n * For multi-jurisdiction support, use the jurisdiction system instead\n */\nexport const DEFAULT_TAX_BRACKETS: Array<{ min: number; max: number; rate: number }> = [\n { min: 0, max: 10000, rate: 0.10 },\n { min: 10000, max: 40000, rate: 0.12 },\n { min: 40000, max: 85000, rate: 0.22 },\n { min: 85000, max: 165000, rate: 0.24 },\n { min: 165000, max: 215000, rate: 0.32 },\n { min: 215000, max: 540000, rate: 0.35 },\n { min: 540000, max: Infinity, rate: 0.37 },\n];\n\nexport const DEFAULT_WORK_SCHEDULE: WorkSchedule = {\n workingDays: [1, 2, 3, 4, 5], // Monday to Friday\n hoursPerDay: 8,\n};\n\n// ============================================================================\n// Pure Calculation Functions\n// ============================================================================\n\n/**\n * Count working days in a date range\n *\n * @example\n * const result = countWorkingDays(\n * new Date('2024-03-01'),\n * new Date('2024-03-31'),\n * { workingDays: [1,2,3,4,5], holidays: companyHolidays }\n * );\n */\nexport function countWorkingDays(\n startDate: Date,\n endDate: Date,\n options: {\n workingDays?: number[];\n holidays?: Date[];\n } = {}\n): WorkingDaysResult {\n const workDays = options.workingDays || DEFAULT_WORK_SCHEDULE.workingDays;\n const holidaySet = new Set(\n (options.holidays || []).map(d => new Date(d).toDateString())\n );\n\n let totalDays = 0;\n let workingDays = 0;\n let holidays = 0;\n let weekends = 0;\n\n const current = new Date(startDate);\n current.setHours(0, 0, 0, 0);\n const end = new Date(endDate);\n end.setHours(0, 0, 0, 0);\n\n while (current <= end) {\n totalDays++;\n const isHoliday = holidaySet.has(current.toDateString());\n const isWorkDay = workDays.includes(current.getDay());\n\n if (isHoliday) {\n holidays++;\n } else if (isWorkDay) {\n workingDays++;\n } else {\n weekends++;\n }\n\n current.setDate(current.getDate() + 1);\n }\n\n return { totalDays, workingDays, weekends, holidays };\n}\n\n/**\n * Calculate proration ratio for partial months\n *\n * @example\n * const proration = calculateProration(\n * employee.hireDate,\n * employee.terminationDate,\n * periodStart,\n * periodEnd\n * );\n */\nexport function calculateProration(\n hireDate: Date,\n terminationDate: Date | null | undefined,\n periodStart: Date,\n periodEnd: Date\n): ProrationResult {\n const hire = new Date(hireDate);\n hire.setHours(0, 0, 0, 0);\n const term = terminationDate ? new Date(terminationDate) : null;\n if (term) term.setHours(0, 0, 0, 0);\n const start = new Date(periodStart);\n start.setHours(0, 0, 0, 0);\n const end = new Date(periodEnd);\n end.setHours(0, 0, 0, 0);\n\n // Employee not active in this period\n if (hire > end || (term && term < start)) {\n return { ratio: 0, reason: 'full', isProrated: true };\n }\n\n // Effective dates within the period\n const effectiveStart = hire > start ? hire : start;\n const effectiveEnd = term && term < end ? term : end;\n\n // Calculate days\n const totalDays = Math.ceil((end.getTime() - start.getTime()) / 86400000) + 1;\n const actualDays = Math.ceil((effectiveEnd.getTime() - effectiveStart.getTime()) / 86400000) + 1;\n const ratio = Math.min(1, Math.max(0, actualDays / totalDays));\n\n // Determine reason\n const isNewHire = hire > start;\n const isTermination = term !== null && term < end;\n \n let reason: ProrationResult['reason'] = 'full';\n if (isNewHire && isTermination) {\n reason = 'both';\n } else if (isNewHire) {\n reason = 'new_hire';\n } else if (isTermination) {\n reason = 'termination';\n }\n\n return { ratio, reason, isProrated: ratio < 1 };\n}\n\n/**\n * Internal simple tax calculation\n * For multi-jurisdiction tax, use the jurisdiction system\n * @internal\n */\nfunction calculateSimpleTax(\n monthlyIncome: number,\n brackets: Array<{ min: number; max: number; rate: number }> = DEFAULT_TAX_BRACKETS\n): TaxResult {\n const annualIncome = monthlyIncome * 12;\n let annualTax = 0;\n\n for (const bracket of brackets) {\n if (annualIncome <= bracket.min) continue;\n const taxableInBracket = Math.min(annualIncome, bracket.max) - bracket.min;\n annualTax += taxableInBracket * bracket.rate;\n }\n\n const monthlyTax = Math.round(annualTax / 12);\n const effectiveRate = monthlyIncome > 0 ? monthlyTax / monthlyIncome : 0;\n\n return { amount: monthlyTax, effectiveRate };\n}\n\n/**\n * Calculate attendance deduction\n *\n * @example\n * const deduction = calculateAttendanceDeduction(22, 20, dailyRate);\n */\nexport function calculateAttendanceDeduction(\n expectedDays: number,\n actualDays: number,\n dailyRate: number,\n maxDeductionPercent = 100\n): number {\n const absentDays = Math.max(0, expectedDays - actualDays);\n const deduction = Math.round(absentDays * dailyRate);\n const maxDeduction = Math.round((dailyRate * expectedDays * maxDeductionPercent) / 100);\n return Math.min(deduction, maxDeduction);\n}\n\n/**\n * Calculate complete salary breakdown\n *\n * This is the main function for salary calculation.\n * Pass all data from YOUR app, get back complete breakdown.\n *\n * Note: Uses simple tax calculation. For multi-jurisdiction tax,\n * use the jurisdiction system instead.\n *\n * @example\n * const result = calculateSalaryBreakdown({\n * baseSalary: 100000,\n * hireDate: employee.hireDate,\n * terminationDate: employee.terminationDate,\n * periodStart: new Date('2024-03-01'),\n * periodEnd: new Date('2024-03-31'),\n * allowances: [{ type: 'housing', amount: 20000, taxable: true }],\n * deductions: [{ type: 'provident_fund', amount: 5000 }],\n * options: { holidays: companyHolidays },\n * attendance: { expectedDays: 22, actualDays: 20 },\n * });\n */\nexport function calculateSalaryBreakdown(params: {\n baseSalary: number;\n hireDate: Date;\n terminationDate?: Date | null;\n periodStart: Date;\n periodEnd: Date;\n allowances?: Array<{ type: string; amount: number; taxable?: boolean }>;\n deductions?: Array<{ type: string; amount: number }>;\n options?: PayrollProcessingOptions;\n attendance?: AttendanceInput;\n}): SalaryCalculationResult {\n const {\n baseSalary,\n hireDate,\n terminationDate,\n periodStart,\n periodEnd,\n allowances = [],\n deductions = [],\n options = {},\n attendance,\n } = params;\n\n // 1. Calculate working days\n const workSchedule = { ...DEFAULT_WORK_SCHEDULE, ...options.workSchedule };\n const workingDays = countWorkingDays(periodStart, periodEnd, {\n workingDays: workSchedule.workingDays,\n holidays: options.holidays,\n });\n\n // 2. Calculate proration\n const proration = options.skipProration\n ? { ratio: 1, reason: 'full' as const, isProrated: false }\n : calculateProration(hireDate, terminationDate, periodStart, periodEnd);\n\n // 3. Prorate base salary\n const proratedBase = Math.round(baseSalary * proration.ratio);\n\n // 4. Process allowances (prorate)\n const processedAllowances = allowances.map(a => ({\n type: a.type,\n amount: Math.round(a.amount * proration.ratio),\n taxable: a.taxable ?? true,\n }));\n const totalAllowances = processedAllowances.reduce((sum, a) => sum + a.amount, 0);\n\n // 5. Process deductions (prorate)\n const processedDeductions = deductions.map(d => ({\n type: d.type,\n amount: Math.round(d.amount * proration.ratio),\n }));\n\n // 6. Attendance deduction\n let attendanceDeduction = 0;\n if (attendance && !options.skipAttendance && workingDays.workingDays > 0) {\n const dailyRate = proratedBase / workingDays.workingDays;\n attendanceDeduction = calculateAttendanceDeduction(\n attendance.expectedDays,\n attendance.actualDays,\n dailyRate\n );\n if (attendanceDeduction > 0) {\n processedDeductions.push({ type: 'attendance', amount: attendanceDeduction });\n }\n }\n\n // 7. Calculate gross salary\n const grossSalary = proratedBase + totalAllowances;\n\n // 8. Calculate tax (simple calculation - for multi-jurisdiction, use jurisdiction system)\n let taxAmount = 0;\n if (!options.skipTax) {\n const taxableAllowances = processedAllowances\n .filter(a => a.taxable)\n .reduce((sum, a) => sum + a.amount, 0);\n const taxableIncome = proratedBase + taxableAllowances;\n const taxResult = calculateSimpleTax(taxableIncome);\n taxAmount = taxResult.amount;\n if (taxAmount > 0) {\n processedDeductions.push({ type: 'tax', amount: taxAmount });\n }\n }\n\n // 9. Calculate net salary\n const totalDeductions = processedDeductions\n .filter(d => d.type !== 'tax') // Exclude only tax, include attendance\n .reduce((sum, d) => sum + d.amount, 0);\n const netSalary = grossSalary - totalDeductions - taxAmount;\n\n return {\n baseSalary,\n proratedBase,\n totalAllowances,\n totalDeductions,\n attendanceDeduction,\n grossSalary,\n taxAmount,\n netSalary,\n proration,\n workingDays,\n breakdown: {\n allowances: processedAllowances,\n deductions: processedDeductions,\n },\n };\n}\n\n/**\n * Get pay period dates for a given month\n *\n * @example\n * const period = getPayPeriod(3, 2024); // March 2024\n */\nexport function getPayPeriod(\n month: number,\n year: number,\n payDay = 28\n): { startDate: Date; endDate: Date; payDate: Date } {\n const startDate = new Date(year, month - 1, 1);\n const endDate = new Date(year, month, 0); // Last day of month\n const payDate = new Date(year, month - 1, Math.min(payDay, endDate.getDate()));\n return { startDate, endDate, payDate };\n}\n\n","/**\n * @classytic/payroll - Pro-Rating Calculator\n *\n * Pure functions for salary pro-rating calculations.\n * No database dependencies - can be used client-side!\n *\n * Handles:\n * - Mid-period hires\n * - Mid-period terminations\n * - Working days (not calendar days)\n * - Holidays exclusion\n *\n * @packageDocumentation\n */\n\nimport { countWorkingDays } from '../core/config.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Input for pro-rating calculation\n */\nexport interface ProRatingInput {\n /**\n * Employee hire date\n */\n hireDate: Date;\n\n /**\n * Employee termination date (null if still employed)\n */\n terminationDate: Date | null;\n\n /**\n * Start of the salary period\n */\n periodStart: Date;\n\n /**\n * End of the salary period\n */\n periodEnd: Date;\n\n /**\n * Working days of the week (1=Monday, 7=Sunday)\n * @default [1, 2, 3, 4, 5] (Monday-Friday)\n */\n workingDays: number[];\n\n /**\n * Public holidays to exclude from working days\n * @default []\n */\n holidays?: Date[];\n}\n\n/**\n * Result of pro-rating calculation\n */\nexport interface ProRatingResult {\n /**\n * Whether the salary needs to be pro-rated\n */\n isProRated: boolean;\n\n /**\n * Pro-rating ratio (0-1)\n * 1 = full salary, 0.5 = half salary, etc.\n */\n ratio: number;\n\n /**\n * Total working days in the period\n */\n periodWorkingDays: number;\n\n /**\n * Working days the employee was actually employed\n */\n effectiveWorkingDays: number;\n\n /**\n * Effective start date (max of hire date and period start)\n */\n effectiveStart: Date;\n\n /**\n * Effective end date (min of termination date and period end)\n */\n effectiveEnd: Date;\n}\n\n// ============================================================================\n// Pure Functions\n// ============================================================================\n\n/**\n * Calculate pro-rating for mid-period hires/terminations\n *\n * This function uses WORKING DAYS (not calendar days) for accurate pro-rating.\n *\n * @example\n * ```typescript\n * // Employee hired on March 15th, process March salary\n * const result = calculateProRating({\n * hireDate: new Date('2024-03-15'),\n * terminationDate: null,\n * periodStart: new Date('2024-03-01'),\n * periodEnd: new Date('2024-03-31'),\n * workingDays: [1, 2, 3, 4, 5], // Mon-Fri\n * });\n * \n * console.log(result);\n * // {\n * // isProRated: true,\n * // ratio: 0.64, // Worked 14 out of 22 working days\n * // periodWorkingDays: 22,\n * // effectiveWorkingDays: 14\n * // }\n * ```\n *\n * @param input - Pro-rating calculation parameters\n * @returns Pro-rating result with ratio and working days breakdown\n *\n * @pure This function has no side effects and doesn't access external state\n */\nexport function calculateProRating(input: ProRatingInput): ProRatingResult {\n const { hireDate, terminationDate, periodStart, periodEnd, workingDays, holidays = [] } = input;\n\n const hire = new Date(hireDate);\n const termination = terminationDate ? new Date(terminationDate) : null;\n\n // Determine the actual start and end dates for this employee in this period\n const effectiveStart = hire > periodStart ? hire : periodStart;\n const effectiveEnd = termination && termination < periodEnd ? termination : periodEnd;\n\n // If employee wasn't active during this period at all\n if (effectiveStart > periodEnd || (termination && termination < periodStart)) {\n const periodWorkingDays = countWorkingDays(periodStart, periodEnd, { workingDays, holidays }).workingDays;\n return {\n isProRated: true,\n ratio: 0,\n periodWorkingDays,\n effectiveWorkingDays: 0,\n effectiveStart: periodStart,\n effectiveEnd: periodStart, // Effectively zero days\n };\n }\n\n // Calculate working days for the full period\n const periodWorkingDays = countWorkingDays(periodStart, periodEnd, { workingDays, holidays }).workingDays;\n\n // Calculate working days the employee was actually employed\n const effectiveWorkingDays = countWorkingDays(effectiveStart, effectiveEnd, { workingDays, holidays }).workingDays;\n\n // Calculate ratio\n const ratio = periodWorkingDays > 0 \n ? Math.min(1, Math.max(0, effectiveWorkingDays / periodWorkingDays)) \n : 0;\n\n // Is pro-rated if ratio is less than 1\n const isProRated = ratio < 1;\n\n return {\n isProRated,\n ratio,\n periodWorkingDays,\n effectiveWorkingDays,\n effectiveStart,\n effectiveEnd,\n };\n}\n\n/**\n * Calculate pro-rated amount from base amount and ratio\n *\n * @example\n * ```typescript\n * const proRatedSalary = applyProRating(100000, 0.64); // 64000\n * ```\n *\n * @param baseAmount - Original amount\n * @param ratio - Pro-rating ratio (0-1)\n * @returns Pro-rated amount (rounded)\n *\n * @pure No side effects\n */\nexport function applyProRating(baseAmount: number, ratio: number): number {\n return Math.round(baseAmount * ratio);\n}\n\n/**\n * Check if pro-rating should be applied for a given hire/termination scenario\n *\n * @param hireDate - Employee hire date\n * @param terminationDate - Employee termination date (null if active)\n * @param periodStart - Salary period start\n * @param periodEnd - Salary period end\n * @returns True if pro-rating is needed\n *\n * @pure No side effects\n */\nexport function shouldProRate(\n hireDate: Date,\n terminationDate: Date | null,\n periodStart: Date,\n periodEnd: Date\n): boolean {\n const hire = new Date(hireDate);\n const termination = terminationDate ? new Date(terminationDate) : null;\n\n // Pro-rate if hired after period start\n if (hire > periodStart) return true;\n\n // Pro-rate if terminated before period end\n if (termination && termination < periodEnd) return true;\n\n return false;\n}\n\n","/**\n * @classytic/payroll - Attendance Deduction Calculator\n *\n * Pure functions for calculating salary deductions based on attendance.\n * No database dependencies - can be used client-side!\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Input for attendance deduction calculation\n */\nexport interface AttendanceDeductionInput {\n /**\n * Expected working days in the period (for this specific employee)\n * Should account for hire/termination dates\n */\n expectedWorkingDays: number;\n\n /**\n * Actual working days the employee was present\n */\n actualWorkingDays: number;\n\n /**\n * Daily salary rate for this employee\n * Calculated as: baseAmount / expectedWorkingDays\n */\n dailyRate: number;\n}\n\n/**\n * Result of attendance deduction calculation\n */\nexport interface AttendanceDeductionResult {\n /**\n * Number of absent days\n */\n absentDays: number;\n\n /**\n * Total deduction amount\n */\n deductionAmount: number;\n\n /**\n * Daily rate used for calculation\n */\n dailyRate: number;\n\n /**\n * Whether any deduction was applied\n */\n hasDeduction: boolean;\n}\n\n// ============================================================================\n// Pure Functions\n// ============================================================================\n\n/**\n * Calculate attendance deduction based on absent days\n *\n * @example\n * ```typescript\n * const result = calculateAttendanceDeduction({\n * expectedWorkingDays: 22,\n * actualWorkingDays: 20, // 2 days absent\n * dailyRate: 4545, // 100000 / 22\n * });\n *\n * console.log(result);\n * // {\n * // absentDays: 2,\n * // deductionAmount: 9090,\n * // dailyRate: 4545,\n * // hasDeduction: true\n * // }\n * ```\n *\n * @param input - Attendance deduction parameters\n * @returns Deduction result with breakdown\n *\n * @pure This function has no side effects\n */\nexport function calculateAttendanceDeduction(input: AttendanceDeductionInput): AttendanceDeductionResult {\n const { expectedWorkingDays, actualWorkingDays, dailyRate } = input;\n\n // Guard against negative values\n const expected = Math.max(0, expectedWorkingDays);\n const actual = Math.max(0, actualWorkingDays);\n const rate = Math.max(0, dailyRate);\n\n // Calculate absent days (cannot be negative)\n const absentDays = Math.max(0, expected - actual);\n\n // Calculate deduction amount\n const deductionAmount = Math.round(absentDays * rate);\n\n return {\n absentDays,\n deductionAmount,\n dailyRate: rate,\n hasDeduction: deductionAmount > 0,\n };\n}\n\n/**\n * Calculate daily rate from monthly salary and working days\n *\n * @example\n * ```typescript\n * const daily = calculateDailyRate(100000, 22); // 4545\n * ```\n *\n * @param monthlySalary - Monthly base salary\n * @param workingDays - Working days in the month\n * @returns Daily rate (rounded)\n *\n * @pure No side effects\n */\nexport function calculateDailyRate(monthlySalary: number, workingDays: number): number {\n if (workingDays <= 0) return 0;\n return Math.round(monthlySalary / workingDays);\n}\n\n/**\n * Calculate hourly rate from monthly salary\n *\n * @example\n * ```typescript\n * const hourly = calculateHourlyRate(100000, 22, 8); // 568\n * ```\n *\n * @param monthlySalary - Monthly base salary\n * @param workingDays - Working days in the month\n * @param hoursPerDay - Hours per working day (default: 8)\n * @returns Hourly rate (rounded)\n *\n * @pure No side effects\n */\nexport function calculateHourlyRate(\n monthlySalary: number,\n workingDays: number,\n hoursPerDay: number = 8\n): number {\n const dailyRate = calculateDailyRate(monthlySalary, workingDays);\n if (hoursPerDay <= 0) return 0;\n return Math.round(dailyRate / hoursPerDay);\n}\n\n/**\n * Calculate deduction for partial day absence (half-day, quarter-day, etc.)\n *\n * @example\n * ```typescript\n * // Half-day absence\n * const deduction = calculatePartialDayDeduction(4545, 0.5); // 2272\n * ```\n *\n * @param dailyRate - Daily salary rate\n * @param fractionAbsent - Fraction of day absent (0-1)\n * @returns Deduction amount (rounded)\n *\n * @pure No side effects\n */\nexport function calculatePartialDayDeduction(dailyRate: number, fractionAbsent: number): number {\n const fraction = Math.min(1, Math.max(0, fractionAbsent));\n return Math.round(dailyRate * fraction);\n}\n\n/**\n * Calculate total attendance deduction including full and partial day absences\n *\n * @example\n * ```typescript\n * const result = calculateTotalAttendanceDeduction({\n * dailyRate: 4545,\n * fullDayAbsences: 2,\n * partialDayAbsences: [0.5, 0.25], // Half-day + quarter-day\n * });\n * \n * console.log(result);\n * // {\n * // fullDayDeduction: 9090,\n * // partialDayDeduction: 3408,\n * // totalDeduction: 12498\n * // }\n * ```\n *\n * @param input - Absence breakdown\n * @returns Deduction breakdown and total\n *\n * @pure No side effects\n */\nexport function calculateTotalAttendanceDeduction(input: {\n dailyRate: number;\n fullDayAbsences?: number;\n partialDayAbsences?: number[];\n}): {\n fullDayDeduction: number;\n partialDayDeduction: number;\n totalDeduction: number;\n} {\n const { dailyRate, fullDayAbsences = 0, partialDayAbsences = [] } = input;\n\n // Full day deductions\n const fullDayDeduction = Math.round(dailyRate * Math.max(0, fullDayAbsences));\n\n // Partial day deductions\n const partialDayDeduction = partialDayAbsences.reduce(\n (sum, fraction) => sum + calculatePartialDayDeduction(dailyRate, fraction),\n 0\n );\n\n return {\n fullDayDeduction,\n partialDayDeduction,\n totalDeduction: fullDayDeduction + partialDayDeduction,\n };\n}\n\n"]}