@classytic/payroll 1.0.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +535 -574
- package/dist/attendance.calculator-BZcv2iii.d.ts +336 -0
- package/dist/calculators/index.d.ts +4 -0
- package/dist/calculators/index.js +439 -0
- package/dist/calculators/index.js.map +1 -0
- package/dist/core/index.d.ts +321 -0
- package/dist/core/index.js +1962 -0
- package/dist/core/index.js.map +1 -0
- package/dist/error-helpers-Bm6lMny2.d.ts +740 -0
- package/dist/index-BKLkuSAs.d.ts +3858 -0
- package/dist/index.d.ts +2684 -0
- package/dist/index.js +11454 -0
- package/dist/index.js.map +1 -0
- package/dist/payroll-states-DBt0XVm-.d.ts +598 -0
- package/dist/prorating.calculator-C33fWBQf.d.ts +135 -0
- package/dist/schemas/index.d.ts +4 -0
- package/dist/schemas/index.js +1472 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/types-bZdAJueH.d.ts +2271 -0
- package/dist/utils/index.d.ts +1007 -0
- package/dist/utils/index.js +1789 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +81 -24
- package/src/config.js +0 -177
- package/src/core/compensation.manager.js +0 -242
- package/src/core/employment.manager.js +0 -224
- package/src/core/payroll.manager.js +0 -499
- package/src/enums.js +0 -141
- package/src/factories/compensation.factory.js +0 -198
- package/src/factories/employee.factory.js +0 -173
- package/src/factories/payroll.factory.js +0 -247
- package/src/hrm.orchestrator.js +0 -139
- package/src/index.js +0 -172
- package/src/init.js +0 -41
- package/src/models/payroll-record.model.js +0 -126
- package/src/plugins/employee.plugin.js +0 -157
- package/src/schemas/employment.schema.js +0 -126
- package/src/services/compensation.service.js +0 -231
- package/src/services/employee.service.js +0 -162
- package/src/services/payroll.service.js +0 -213
- package/src/utils/calculation.utils.js +0 -91
- package/src/utils/date.utils.js +0 -120
- package/src/utils/logger.js +0 -36
- package/src/utils/query-builders.js +0 -185
- package/src/utils/validation.utils.js +0 -122
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/enums.ts","../src/utils/logger.ts","../src/utils/money.ts","../src/core/state-machine.ts","../src/core/payroll-states.ts","../src/utils/date.ts","../src/utils/query-builders.ts","../src/utils/calculation.ts","../src/errors/index.ts","../src/core/config.ts","../src/utils/validation.ts","../src/calculators/prorating.calculator.ts","../src/utils/type-guards.ts","../src/utils/leave.ts","../src/utils/employee-lookup.ts","../src/utils/org-resolution.ts","../src/utils/employee-identity.ts","../src/utils/error-helpers.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/factories/employee.factory.ts","../src/factories/transaction.factory.ts","../src/payroll.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/calculators/attendance.calculator.ts","../src/core/repository-plugins.ts","../src/managers/repository.manager.ts","../src/managers/salary-processing.manager.ts","../src/utils/employee-type-guards.ts","../src/managers/bulk-operations.manager.ts","../src/managers/employee-operations.manager.ts","../src/managers/compensation.manager.ts","../src/managers/payroll-history.manager.ts","../src/managers/payroll-state.manager.ts","../src/types/transaction.interface.ts","../src/core/timeline-audit.ts","../src/index.ts","../src/schemas/index.ts","../src/schemas/common.ts","../src/schemas/leave.ts","../src/models/leave-request.model.ts","../src/models/tax-withholding.model.ts","../src/schemas/tax-withholding.ts","../src/plugins/employee.plugin.ts","../src/attendance.ts","../src/holidays.ts","../src/calculators/index.ts","../src/shift-compliance/calculators/late-penalty.ts","../src/shift-compliance/calculators/overtime.ts","../src/shift-compliance/calculators/index.ts","../src/shift-compliance/config.ts","../src/shift-compliance/builders.ts","../src/shift-compliance/schemas.ts","../src/core/mongokit-plugins/payroll-audit.plugin.ts"],"names":["logger","employee","periodWorkingDays","operationName","payroll","PayrollStatusMachine","TaxWithholdingService","isValidObjectId","config","Schema","matchStage","mongoose"],"mappings":"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","file":"index.js","sourcesContent":["/**\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 VOIDED: 'voided',\n REVERSED: 'reversed',\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/** Check if payroll can be voided (not yet paid) */\nexport function isVoidablePayrollStatus(status: PayrollStatus): boolean {\n return status === PAYROLL_STATUS.PENDING ||\n status === PAYROLL_STATUS.PROCESSING ||\n status === PAYROLL_STATUS.FAILED;\n}\n\n/** Check if payroll requires reversal (already paid) */\nexport function requiresReversalPayrollStatus(status: PayrollStatus): boolean {\n return status === PAYROLL_STATUS.PAID;\n}\n\n/** Check if payroll is in a terminal void/reverse state */\nexport function isVoidedOrReversedStatus(status: PayrollStatus): boolean {\n return status === PAYROLL_STATUS.VOIDED || status === PAYROLL_STATUS.REVERSED;\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 CANCELLED: 'cancelled',\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\nexport function isCancelledTaxStatus(status: import('./types.js').TaxStatus): boolean {\n return status === TAX_STATUS.CANCELLED;\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 - 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 (respects loggingEnabled flag)\n */\nexport function getLogger(): Logger {\n return {\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}\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 (respects loggingEnabled flag)\n */\nexport function createChildLogger(prefix: string): Logger {\n const parent = currentLogger;\n return {\n info: (message: string, meta?: Record<string, unknown>) => {\n if (loggingEnabled) parent.info(`[${prefix}] ${message}`, meta);\n },\n error: (message: string, meta?: Record<string, unknown>) => {\n if (loggingEnabled) parent.error(`[${prefix}] ${message}`, meta);\n },\n warn: (message: string, meta?: Record<string, unknown>) => {\n if (loggingEnabled) parent.warn(`[${prefix}] ${message}`, meta);\n },\n debug: (message: string, meta?: Record<string, unknown>) => {\n if (loggingEnabled) parent.debug(`[${prefix}] ${message}`, meta);\n },\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 * Money calculation utilities for payroll compliance\n *\n * Uses banker's rounding (round half to even) to prevent systematic bias\n * in financial calculations, as recommended for payroll systems.\n *\n * PRECISION: All functions default to 2 decimal places (cents/paise precision)\n * to maintain accuracy in payroll calculations. Amounts are stored as floating\n * point numbers with decimal precision (e.g., 1000.50 for $1,000.50).\n *\n * ## Design Decision: Floating Point Storage\n *\n * This module uses floating-point numbers (IEEE 754 double precision) for money\n * storage rather than integer minor units (cents) or MongoDB Decimal128.\n *\n * ### Tradeoffs:\n *\n * **Why floating point:**\n * - Simpler API (developers think in dollars, not cents)\n * - More intuitive JSON serialization (100.50 vs 10050)\n * - Sufficient precision for payroll (15 significant digits)\n * - Banker's rounding mitigates cumulative drift\n *\n * **Why NOT integer cents:**\n * - Would require breaking schema changes\n * - All consumer code needs conversion (amount / 100)\n * - More verbose for reporting/display\n *\n * **Why NOT Decimal128:**\n * - MongoDB-specific, reduces portability\n * - Requires special BSON handling in application code\n * - Overkill for typical payroll amounts (< $10M/employee/year)\n *\n * ### Mitigation:\n * - All calculations go through roundMoney() with banker's rounding\n * - Final amounts always rounded to 2 decimal places before storage\n * - Aggregations use MongoDB $round operator for consistency\n *\n * @see https://en.wikipedia.org/wiki/Banker%27s_rounding\n */\n\n/**\n * Banker's rounding (round half to even) with decimal precision\n *\n * When rounding 0.5, rounds to the nearest even number:\n * - 2.5 → 2 (even)\n * - 3.5 → 4 (even)\n * - 4.5 → 4 (even)\n *\n * This prevents systematic bias in cumulative rounding that occurs\n * with standard rounding (always up), which is critical for payroll compliance.\n *\n * @param value - The number to round\n * @param decimals - Number of decimal places (default: 2 for cent precision)\n * @returns The rounded value\n */\nexport function roundMoney(value: number, decimals = 2): number {\n const multiplier = Math.pow(10, decimals);\n const scaled = value * multiplier;\n const fraction = scaled - Math.floor(scaled);\n\n // If exactly 0.5 (within tolerance), round to nearest even\n // Use 1e-10 tolerance to handle floating-point imprecision\n if (Math.abs(fraction - 0.5) < 1e-10) {\n const floor = Math.floor(scaled);\n const rounded = floor % 2 === 0 ? floor : floor + 1;\n return rounded / multiplier;\n }\n\n // Otherwise use standard rounding\n return Math.round(scaled) / multiplier;\n}\n\n/**\n * Round money with validation for negative values\n *\n * @param value - The number to round\n * @param decimals - Number of decimal places (default: 2 for cent precision)\n * @returns The rounded value (never negative for deductions)\n */\nexport function roundMoneyPositive(value: number, decimals = 2): number {\n return Math.max(0, roundMoney(value, decimals));\n}\n\n/**\n * Calculate percentage of an amount with banker's rounding\n *\n * @param amount - Base amount\n * @param percentage - Percentage (e.g., 10 for 10%)\n * @param decimals - Decimal places to round to (default: 2 for cent precision)\n * @returns Rounded percentage amount\n */\nexport function percentageOf(amount: number, percentage: number, decimals = 2): number {\n return roundMoney((amount * percentage) / 100, decimals);\n}\n\n/**\n * Prorate an amount by a ratio with banker's rounding\n *\n * @param amount - Base amount\n * @param ratio - Proration ratio (0 to 1)\n * @param decimals - Decimal places (default: 2 for cent precision)\n * @returns Prorated amount\n */\nexport function prorateAmount(amount: number, ratio: number, decimals = 2): number {\n return roundMoney(amount * ratio, decimals);\n}\n","/**\r\n * @classytic/payroll - State Machine\r\n *\r\n * Minimal state machine implementation for status management.\r\n * Enforces valid transitions and provides clear error messages.\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * State transition definition\r\n */\r\nexport interface StateTransition<TState extends string> {\r\n from: TState | TState[];\r\n to: TState;\r\n}\r\n\r\n/**\r\n * State machine configuration\r\n */\r\nexport interface StateMachineConfig<TState extends string> {\r\n /** All valid states */\r\n states: readonly TState[];\r\n /** Initial state */\r\n initial: TState;\r\n /** Valid transitions */\r\n transitions: StateTransition<TState>[];\r\n /** Terminal states (no outgoing transitions) */\r\n terminal?: TState[];\r\n}\r\n\r\n/**\r\n * Transition result\r\n */\r\nexport type TransitionResult<TState extends string> =\r\n | { success: true; from: TState; to: TState }\r\n | { success: false; from: TState; to: TState; error: string };\r\n\r\n// ============================================================================\r\n// State Machine Class\r\n// ============================================================================\r\n\r\n/**\r\n * Minimal state machine for status management\r\n *\r\n * @example\r\n * const machine = new StateMachine({\r\n * states: ['pending', 'processing', 'paid', 'voided'] as const,\r\n * initial: 'pending',\r\n * transitions: [\r\n * { from: 'pending', to: 'processing' },\r\n * { from: 'pending', to: 'voided' },\r\n * { from: 'processing', to: 'paid' },\r\n * ],\r\n * terminal: ['paid', 'voided'],\r\n * });\r\n *\r\n * machine.canTransition('pending', 'processing'); // true\r\n * machine.canTransition('paid', 'pending'); // false\r\n */\r\nexport class StateMachine<TState extends string> {\r\n private readonly validTransitions: Map<TState, Set<TState>>;\r\n private readonly terminalStates: Set<TState>;\r\n\r\n constructor(private readonly config: StateMachineConfig<TState>) {\r\n // Build transition map for O(1) lookup\r\n this.validTransitions = new Map();\r\n for (const state of config.states) {\r\n this.validTransitions.set(state, new Set());\r\n }\r\n\r\n for (const transition of config.transitions) {\r\n const fromStates = Array.isArray(transition.from)\r\n ? transition.from\r\n : [transition.from];\r\n\r\n for (const from of fromStates) {\r\n this.validTransitions.get(from)?.add(transition.to);\r\n }\r\n }\r\n\r\n this.terminalStates = new Set(config.terminal || []);\r\n }\r\n\r\n /**\r\n * Get the initial state\r\n */\r\n get initial(): TState {\r\n return this.config.initial;\r\n }\r\n\r\n /**\r\n * Get all valid states\r\n */\r\n get states(): readonly TState[] {\r\n return this.config.states;\r\n }\r\n\r\n /**\r\n * Check if a state is valid\r\n */\r\n isValidState(state: string): state is TState {\r\n return this.config.states.includes(state as TState);\r\n }\r\n\r\n /**\r\n * Check if a state is terminal (no outgoing transitions)\r\n */\r\n isTerminal(state: TState): boolean {\r\n return this.terminalStates.has(state);\r\n }\r\n\r\n /**\r\n * Check if transition from one state to another is valid\r\n */\r\n canTransition(from: TState, to: TState): boolean {\r\n return this.validTransitions.get(from)?.has(to) ?? false;\r\n }\r\n\r\n /**\r\n * Get all valid next states from current state\r\n */\r\n getNextStates(from: TState): TState[] {\r\n return Array.from(this.validTransitions.get(from) || []);\r\n }\r\n\r\n /**\r\n * Validate a transition and return result\r\n */\r\n validateTransition(from: TState, to: TState): TransitionResult<TState> {\r\n if (!this.isValidState(from)) {\r\n return {\r\n success: false,\r\n from,\r\n to,\r\n error: `Invalid current state: '${from}'`,\r\n };\r\n }\r\n\r\n if (!this.isValidState(to)) {\r\n return {\r\n success: false,\r\n from,\r\n to,\r\n error: `Invalid target state: '${to}'`,\r\n };\r\n }\r\n\r\n if (this.isTerminal(from)) {\r\n return {\r\n success: false,\r\n from,\r\n to,\r\n error: `Cannot transition from terminal state '${from}'`,\r\n };\r\n }\r\n\r\n if (!this.canTransition(from, to)) {\r\n const validNext = this.getNextStates(from);\r\n return {\r\n success: false,\r\n from,\r\n to,\r\n error: `Invalid transition: '${from}' → '${to}'. Valid transitions from '${from}': [${validNext.join(', ')}]`,\r\n };\r\n }\r\n\r\n return { success: true, from, to };\r\n }\r\n\r\n /**\r\n * Assert a transition is valid, throw if not\r\n */\r\n assertTransition(from: TState, to: TState): void {\r\n const result = this.validateTransition(from, to);\r\n if (!result.success) {\r\n throw new Error(result.error);\r\n }\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Factory Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Create a state machine instance\r\n */\r\nexport function createStateMachine<TState extends string>(\r\n config: StateMachineConfig<TState>\r\n): StateMachine<TState> {\r\n return new StateMachine(config);\r\n}\r\n","/**\r\n * @classytic/payroll - Payroll State Machines\r\n *\r\n * Defines valid state transitions for all status types.\r\n * Single source of truth for status management.\r\n */\r\n\r\nimport { createStateMachine, type StateMachine } from './state-machine.js';\r\n\r\n// ============================================================================\r\n// Payroll Record Status\r\n// ============================================================================\r\n\r\n/**\r\n * PayrollStatus state machine\r\n *\r\n * State diagram:\r\n * ```\r\n * PENDING ──┬──> PROCESSING ──┬──> PAID ──> REVERSED\r\n * │ │ │\r\n * │ │ └──> FAILED ──┐\r\n * │ │ │\r\n * │ └──> VOIDED <──────────┘\r\n * │ ↑\r\n * └──────────────┘\r\n * ```\r\n *\r\n * - PENDING: Initial state, payroll created but not processed\r\n * - PROCESSING: Currently being processed (bulk operations)\r\n * - PAID: Payment completed successfully\r\n * - FAILED: Processing failed (can retry → pending, or void)\r\n * - VOIDED: Cancelled before payment (can restore → pending)\r\n * - REVERSED: Payment reversed after completion (terminal)\r\n */\r\nexport const PayrollStatusMachine = createStateMachine({\r\n states: ['pending', 'processing', 'paid', 'failed', 'voided', 'reversed'] as const,\r\n initial: 'pending',\r\n transitions: [\r\n // Normal flow\r\n { from: 'pending', to: 'processing' },\r\n { from: 'processing', to: 'paid' },\r\n\r\n // Direct payment (skip processing for single salary)\r\n { from: 'pending', to: 'paid' },\r\n\r\n // Failure handling\r\n { from: 'processing', to: 'failed' },\r\n { from: 'failed', to: 'pending' }, // Retry\r\n\r\n // Void (unpaid only - pending, processing, or failed)\r\n { from: ['pending', 'processing', 'failed'], to: 'voided' },\r\n\r\n // Reversal (paid only)\r\n { from: 'paid', to: 'reversed' },\r\n\r\n // Restore voided (back to pending for re-processing)\r\n { from: 'voided', to: 'pending' },\r\n ],\r\n terminal: ['reversed'], // Only reversed is truly terminal\r\n});\r\n\r\nexport type PayrollStatusState = typeof PayrollStatusMachine.states[number];\r\n\r\n// ============================================================================\r\n// Tax Withholding Status\r\n// ============================================================================\r\n\r\n/**\r\n * TaxStatus state machine\r\n *\r\n * State diagram:\r\n * ```\r\n * PENDING ──┬──> SUBMITTED ──> PAID\r\n * │\r\n * └──> CANCELLED\r\n * ```\r\n *\r\n * - PENDING: Tax withheld, not yet submitted to government\r\n * - SUBMITTED: Submitted to tax authority, awaiting confirmation\r\n * - PAID: Payment confirmed by tax authority\r\n * - CANCELLED: Invalidated (payroll voided/reversed)\r\n */\r\nexport const TaxStatusMachine = createStateMachine({\r\n states: ['pending', 'submitted', 'paid', 'cancelled'] as const,\r\n initial: 'pending',\r\n transitions: [\r\n { from: 'pending', to: 'submitted' },\r\n { from: 'submitted', to: 'paid' },\r\n\r\n // Direct payment (some jurisdictions)\r\n { from: 'pending', to: 'paid' },\r\n\r\n // Cancellation (from any non-terminal state)\r\n { from: ['pending', 'submitted'], to: 'cancelled' },\r\n ],\r\n terminal: ['paid', 'cancelled'],\r\n});\r\n\r\nexport type TaxStatusState = typeof TaxStatusMachine.states[number];\r\n\r\n// ============================================================================\r\n// Leave Request Status\r\n// ============================================================================\r\n\r\n/**\r\n * LeaveRequestStatus state machine\r\n *\r\n * State diagram:\r\n * ```\r\n * PENDING ──┬──> APPROVED\r\n * │\r\n * ├──> REJECTED\r\n * │\r\n * └──> CANCELLED\r\n * ```\r\n */\r\nexport const LeaveRequestStatusMachine = createStateMachine({\r\n states: ['pending', 'approved', 'rejected', 'cancelled'] as const,\r\n initial: 'pending',\r\n transitions: [\r\n { from: 'pending', to: 'approved' },\r\n { from: 'pending', to: 'rejected' },\r\n { from: 'pending', to: 'cancelled' },\r\n\r\n // Cancel approved leave (before it starts)\r\n { from: 'approved', to: 'cancelled' },\r\n ],\r\n terminal: ['rejected', 'cancelled'],\r\n});\r\n\r\nexport type LeaveRequestStatusState = typeof LeaveRequestStatusMachine.states[number];\r\n\r\n// ============================================================================\r\n// Employee Status\r\n// ============================================================================\r\n\r\n/**\r\n * EmployeeStatus state machine\r\n *\r\n * State diagram:\r\n * ```\r\n * ACTIVE ←──┬──→ ON_LEAVE\r\n * │\r\n * ├──→ SUSPENDED ──→ ACTIVE\r\n * │\r\n * └──→ TERMINATED\r\n * ```\r\n */\r\nexport const EmployeeStatusMachine = createStateMachine({\r\n states: ['active', 'on_leave', 'suspended', 'terminated'] as const,\r\n initial: 'active',\r\n transitions: [\r\n // Leave management\r\n { from: 'active', to: 'on_leave' },\r\n { from: 'on_leave', to: 'active' },\r\n\r\n // Suspension\r\n { from: ['active', 'on_leave'], to: 'suspended' },\r\n { from: 'suspended', to: 'active' },\r\n\r\n // Termination (from any state)\r\n { from: ['active', 'on_leave', 'suspended'], to: 'terminated' },\r\n\r\n // Re-hire (back to active)\r\n { from: 'terminated', to: 'active' },\r\n ],\r\n terminal: [], // No terminal states (re-hire possible)\r\n});\r\n\r\nexport type EmployeeStatusState = typeof EmployeeStatusMachine.states[number];\r\n\r\n// ============================================================================\r\n// Exports\r\n// ============================================================================\r\n\r\nexport {\r\n StateMachine,\r\n createStateMachine,\r\n type StateMachineConfig,\r\n type StateTransition,\r\n type TransitionResult,\r\n} from './state-machine.js';\r\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 Normalization\n// ============================================================================\n\n/**\n * Convert a date to a UTC-based date string for consistent comparison.\n *\n * Unlike `Date.toDateString()` which uses the local timezone, this produces\n * a locale-independent string based on the date's year/month/day components.\n * Use this for holiday set lookups to avoid timezone-dependent mismatches.\n */\nexport function toUTCDateString(date: Date): string {\n const d = new Date(date);\n d.setHours(0, 0, 0, 0);\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\n}\n\n// ============================================================================\n// Date Differences\n// ============================================================================\n\n/**\n * Calculate difference in days between two dates.\n *\n * Normalizes both dates to midnight before computing to avoid\n * inconsistencies from time-of-day differences or DST transitions.\n */\nexport function diffInDays(start: Date, end: Date): number {\n const s = new Date(start);\n const e = new Date(end);\n s.setHours(0, 0, 0, 0);\n e.setHours(0, 0, 0, 0);\n return Math.ceil((e.getTime() - s.getTime()) / (1000 * 60 * 60 * 24));\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 (monthly periods)\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 pay period based on payment frequency\n *\n * Creates the correct period boundaries based on the employee's payment frequency:\n * - monthly: full calendar month\n * - bi_weekly: 14 days ending on paymentDate\n * - weekly: 7 days ending on paymentDate\n * - daily/hourly: single day (paymentDate)\n *\n * @param frequency - Payment frequency\n * @param paymentDate - Date of payment (used as end of period for non-monthly)\n * @param month - Month (1-12) for accounting purposes\n * @param year - Year for accounting purposes\n * @returns Pay period with appropriate boundaries\n */\nexport function getPayPeriodForFrequency(\n frequency: PaymentFrequency,\n paymentDate: Date,\n month: number,\n year: number\n): PayPeriodInfo & { workingDays: number } {\n switch (frequency) {\n case 'monthly': {\n const period = getPayPeriod(month, year);\n const workingDays = getWorkingDaysInMonth(year, month);\n return { ...period, workingDays };\n }\n\n case 'bi_weekly': {\n // 14-day period ending on paymentDate\n const endDate = startOfDay(paymentDate);\n const startDate = addDays(endDate, -13); // 14 days total (0-13)\n const workingDays = countWeekdaysInRange(startDate, endDate);\n return { month, year, startDate, endDate, workingDays };\n }\n\n case 'weekly': {\n // 7-day period ending on paymentDate\n const endDate = startOfDay(paymentDate);\n const startDate = addDays(endDate, -6); // 7 days total (0-6)\n const workingDays = countWeekdaysInRange(startDate, endDate);\n return { month, year, startDate, endDate, workingDays };\n }\n\n case 'daily':\n case 'hourly': {\n // Single day period\n const date = startOfDay(paymentDate);\n const workingDays = isWeekday(date) ? 1 : 0;\n return { month, year, startDate: date, endDate: date, workingDays };\n }\n\n default:\n // Fallback to monthly\n return getPayPeriodForFrequency('monthly', paymentDate, month, year);\n }\n}\n\n/**\n * Count weekdays (Mon-Fri) in a date range (inclusive)\n */\nfunction countWeekdaysInRange(start: Date, end: Date): number {\n let count = 0;\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 return count;\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 * Check if an item with effectiveFrom/effectiveTo dates is effective for a given period.\n *\n * Used for filtering allowances, deductions, and other time-bounded compensation items.\n * An item is considered effective if its date range overlaps with the period.\n *\n * @param item - Object with optional effectiveFrom and effectiveTo dates\n * @param periodStart - Start of the period to check\n * @param periodEnd - End of the period to check\n * @returns true if the item is effective during any part of the period\n *\n * @example\n * ```typescript\n * const allowance = { effectiveFrom: new Date('2024-01-01'), effectiveTo: null };\n * const periodStart = new Date('2024-03-01');\n * const periodEnd = new Date('2024-03-31');\n *\n * isEffectiveForPeriod(allowance, periodStart, periodEnd); // true\n * ```\n */\nexport function 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 * 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 toUTCDateString,\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 isEffectiveForPeriod,\n getPayPeriodDateRange,\n formatDateForDB,\n parseDBDate,\n formatPeriod,\n parsePeriod,\n getMonthName,\n getShortMonthName,\n};\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 * Uses $exists: true and $ne: null to exclude both missing fields and null values\n */\n userLinkedEmployees(): this {\n return this.where('userId', { $exists: true, $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 - 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} from '../types.js';\nimport { roundMoney } from './money.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 * ROUNDING POLICY FOR FINANCIAL CALCULATIONS\n *\n * Monetary amounts are stored as floating point numbers in major units with\n * decimal precision (e.g., 1000.50 for $1,000.50 or ₹1,000.50).\n *\n * PRECISION: All calculations preserve 2 decimal places (cent/paise precision)\n * to maintain accuracy required for payroll compliance.\n *\n * Rounding Rules:\n * 1. Banker's Rounding (Round Half to Even): Used for fair rounding over many transactions\n * 2. All intermediate calculations maintain full precision\n * 3. Final amounts rounded to 2 decimals using banker's rounding\n * 4. Tax calculations use banker's rounding for compliance\n *\n * Example:\n * Input: 1000.50 base + 15% tax\n * Calculation: 1000.50 * 0.15 = 150.075 → rounds to 150.08 (banker's rounding to 2 decimals)\n * Result: Tax = 150.08\n *\n * @see https://en.wikipedia.org/wiki/Rounding#Round_half_to_even\n */\n\n/**\n * Banker's Rounding (Round Half to Even) - Integer precision\n *\n * Rounds to the nearest integer using banker's rounding (round half to even).\n * This prevents systematic bias in rounding over many transactions.\n *\n * Uses epsilon check for safe floating-point comparison.\n *\n * Examples:\n * 0.5 → 0 (even)\n * 1.5 → 2 (even)\n * 2.5 → 2 (even)\n * 3.5 → 4 (even)\n *\n * @param value - The number to round\n * @returns Rounded integer\n * @note For money calculations with decimal precision, use `roundMoney()` instead\n */\nexport function bankersRound(value: number): number {\n const floor = Math.floor(value);\n const fraction = value - floor;\n\n // Use epsilon check for safer floating-point comparison\n if (Math.abs(fraction - 0.5) < Number.EPSILON) {\n // If halfway, round to even\n return floor % 2 === 0 ? floor : floor + 1;\n }\n\n // Otherwise use standard rounding\n return Math.round(value);\n}\n\n/**\n * Apply percentage to amount with banker's rounding (2 decimal precision)\n *\n * @param amount - Amount in major units (e.g., dollars, rupees)\n * @param percentage - Percentage to apply (e.g., 15 for 15%)\n * @param decimals - Decimal places for precision (default: 2 for cent precision)\n * @returns Result in major units, properly rounded to 2 decimals\n * @note Uses banker's rounding (round half to even) to preserve cent precision.\n * Equivalent to percentageOf() from money.ts.\n */\nexport function applyPercentage(amount: number, percentage: number, decimals = 2): number {\n // Use centralized roundMoney for consistent banker's rounding across codebase\n const result = (amount * percentage) / 100;\n return roundMoney(result, decimals);\n}\n\n/**\n * Calculate percentage of total\n */\nexport function calculatePercentage(part: number, total: number): number {\n return total > 0 ? bankersRound((part / total) * 100) : 0;\n}\n\n/**\n * Round to decimal places using banker's rounding\n */\nexport function roundTo(value: number, decimals = 2): number {\n const factor = Math.pow(10, decimals);\n return bankersRound(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// Tax Calculations\n// ============================================================================\n\n/**\n * Apply tax brackets to calculate tax\n *\n * Uses banker's rounding for compliance (rounds to 2 decimal places).\n * Consistent with all other money calculations in the system.\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 // Use roundMoney for consistency with all other money calculations\n return roundMoney(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// 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 roundMoney(hourlyRate * overtimeHours * multiplier, 2);\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 roundMoney(monthlySalary / hoursPerMonth, 2);\n}\n\n/**\n * Calculate daily rate from monthly salary\n */\nexport function calculateDailyRate(\n monthlySalary: number,\n daysPerMonth = 22\n): number {\n return roundMoney(monthlySalary / daysPerMonth, 2);\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 applyTaxBrackets,\n calculateTax,\n calculateOvertime,\n calculateHourlyRate,\n calculateDailyRate,\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 payrollRunType?: string,\n context?: Record<string, unknown>\n ) {\n const runTypeInfo = payrollRunType ? ` (${payrollRunType})` : '';\n super(\n `Payroll already processed for employee ${employeeId} in ${month}/${year}${runTypeInfo}`,\n 'DUPLICATE_PAYROLL',\n 409,\n { employeeId, month, year, payrollRunType, ...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 * Security error (unauthorized access, cross-organization access, etc.)\n */\nexport class SecurityError extends PayrollError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, 'SECURITY_ERROR', 403, 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 VOIDED_PAYROLL_REPROCESS: 409,\n VALIDATION_ERROR: 400,\n EMPLOYEE_TERMINATED: 400,\n ALREADY_PROCESSED: 409,\n NOT_ELIGIBLE: 400,\n SECURITY_ERROR: 403,\n EXPORT_NOT_FOUND: 404,\n EXPORT_ORG_MISMATCH: 403,\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 - 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\nimport { roundMoney } from '../utils/money.js';\nimport { toUTCDateString } from '../utils/date.js';\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 /**\n * Reason for proration:\n * - 'full': Employee worked the entire period (ratio = 1)\n * - 'new_hire': Employee was hired during the period\n * - 'termination': Employee was terminated during the period\n * - 'both': Both hired and terminated within the period\n * - 'not_active': Employee was not active at all during the period (ratio = 0)\n */\n reason: 'full' | 'new_hire' | 'termination' | 'both' | 'not_active';\n /** Whether salary should be prorated */\n isProrated: boolean;\n}\n\n/** Attendance data (from YOUR attendance system) */\nexport interface AttendanceInput {\n /**\n * Expected work days in period.\n * If not provided, derived from employee's workSchedule and period dates.\n */\n expectedDays?: number;\n /** Actual days worked */\n actualDays: number;\n}\n\n// ============================================================================\n// Default Configuration\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 => toUTCDateString(d))\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(toUTCDateString(current));\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: 'not_active', 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// NOTE: calculateAttendanceDeduction has been moved to calculators/attendance.calculator.ts\n// The calculator version uses banker's rounding and returns a detailed result object.\n// Re-export from core/index.ts for backward compatibility.\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 - 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// Plugin Method Validators\n// ============================================================================\n\n/**\n * Check if an object has a specific method (typically from a Mongoose plugin)\n *\n * @param obj - Object to check\n * @param method - Method name to verify\n * @returns true if object has the method as a function\n *\n * @example\n * ```typescript\n * if (hasPluginMethod(employee, 'canReceiveSalary')) {\n * employee.canReceiveSalary();\n * }\n * ```\n */\nexport function hasPluginMethod(obj: unknown, method: string): boolean {\n return typeof obj === 'object' && obj !== null && typeof (obj as Record<string, unknown>)[method] === 'function';\n}\n\n/**\n * Assert that an object has a specific plugin method, throwing an error if not\n *\n * @param obj - Object to check\n * @param method - Method name to verify\n * @param context - Context message for error\n * @throws Error if method is not found\n */\nexport function assertPluginMethod(obj: unknown, method: string, context: string): void {\n if (!hasPluginMethod(obj, method)) {\n throw new Error(\n `Method '${method}' not found on object. Did you forget to apply the appropriate plugin? ` +\n `Context: ${context}`\n );\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 // Plugin method validators\n hasPluginMethod,\n assertPluginMethod,\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';\nimport { roundMoney } from '../utils/money.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 using Date.getDay() convention (0=Sunday, 1=Monday, ..., 6=Saturday)\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 roundMoney(baseAmount * ratio, 2);\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","/**\r\n * @classytic/payroll - Type Guards\r\n *\r\n * Type-safe utilities for runtime type checking,\r\n * especially for error handling and MongoDB errors.\r\n *\r\n * @module @classytic/payroll/utils/type-guards\r\n */\r\n\r\nimport { MongoServerError } from 'mongodb';\r\nimport type { EmployeeDocument } from '../types.js';\r\n\r\n/**\r\n * Check if error is a MongoDB error\r\n *\r\n * @param error - Unknown error object\r\n * @returns True if MongoDB error\r\n *\r\n * @example\r\n * ```typescript\r\n * try {\r\n * await model.create(data);\r\n * } catch (error) {\r\n * if (isMongoError(error)) {\r\n * console.log('MongoDB error code:', error.code);\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isMongoError(error: unknown): error is MongoServerError {\r\n return error instanceof MongoServerError;\r\n}\r\n\r\n/**\r\n * Check if error is a MongoDB duplicate key error (E11000)\r\n *\r\n * @param error - Unknown error object\r\n * @returns True if duplicate key error\r\n *\r\n * @example\r\n * ```typescript\r\n * try {\r\n * await PayrollModel.create(record);\r\n * } catch (error) {\r\n * if (isDuplicateKeyError(error)) {\r\n * const field = parseDuplicateKeyError(error);\r\n * throw new DuplicatePayrollError(`Duplicate ${field}`);\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isDuplicateKeyError(error: unknown): error is MongoServerError & { code: 11000 } {\r\n return isMongoError(error) && error.code === 11000;\r\n}\r\n\r\n/**\r\n * Parse field name from MongoDB duplicate key error\r\n *\r\n * @param error - MongoDB duplicate key error\r\n * @returns Field name that caused the duplicate, or 'unknown'\r\n *\r\n * @example\r\n * ```typescript\r\n * if (isDuplicateKeyError(error)) {\r\n * const field = parseDuplicateKeyError(error);\r\n * // field might be 'employeeId', 'email', etc.\r\n * }\r\n * ```\r\n */\r\nexport function parseDuplicateKeyError(error: MongoServerError): string {\r\n const message = error.message || '';\r\n\r\n // MongoDB error message format: \"E11000 duplicate key error collection: ... dup key: { fieldName: ... }\"\r\n const match = message.match(/dup key: \\{ ([^:]+):/);\r\n if (match && match[1]) {\r\n return match[1].trim();\r\n }\r\n\r\n // Fallback: try to extract from errmsg\r\n const errmsgMatch = message.match(/index: ([^_]+)_/);\r\n if (errmsgMatch && errmsgMatch[1]) {\r\n return errmsgMatch[1].trim();\r\n }\r\n\r\n return 'unknown';\r\n}\r\n\r\n/**\r\n * Check if error is a MongoDB transaction error\r\n *\r\n * @param error - Unknown error object\r\n * @returns True if transaction-related error\r\n */\r\nexport function isTransactionError(error: unknown): error is MongoServerError {\r\n if (!isMongoError(error)) return false;\r\n\r\n const message = (error.message || '').toLowerCase();\r\n return (\r\n message.includes('transaction') ||\r\n message.includes('session') ||\r\n message.includes('replica set') ||\r\n error.code === 251 || // NoSuchTransaction\r\n error.code === 225 || // TransactionTooOld\r\n error.code === 244 || // TransactionAborted\r\n error.code === 256 || // TransactionCommitted\r\n error.code === 257 // TransactionCoordinatorSteppingDown\r\n );\r\n}\r\n\r\n/**\r\n * Check if MongoDB transactions are unsupported (standalone server)\r\n *\r\n * @param error - Unknown error object\r\n * @returns True if error indicates transactions are not supported\r\n */\r\nexport function isTransactionUnsupportedError(error: unknown): boolean {\r\n if (!isMongoError(error)) return false;\r\n\r\n const message = (error.message || '').toLowerCase();\r\n return (\r\n message.includes('transaction numbers are only allowed on a replica set member') ||\r\n message.includes('transactions are only supported on replica sets') ||\r\n message.includes('mongos') ||\r\n error.code === 20 // IllegalOperation\r\n );\r\n}\r\n\r\n/**\r\n * Check if error is a connection error\r\n *\r\n * @param error - Unknown error object\r\n * @returns True if connection error\r\n */\r\nexport function isConnectionError(error: unknown): error is MongoServerError {\r\n if (!isMongoError(error)) return false;\r\n\r\n return (\r\n error.code === 11600 || // InterruptedAtShutdown\r\n error.code === 11602 || // InterruptedDueToReplStateChange\r\n error.code === 91 || // ShutdownInProgress\r\n error.code === 89 || // NetworkTimeout\r\n error.code === 6 // HostUnreachable\r\n );\r\n}\r\n\r\n/**\r\n * Type guard: Check if employee is a guest employee (no userId)\r\n *\r\n * @param employee - Employee document\r\n * @returns True if guest employee\r\n *\r\n * @example\r\n * ```typescript\r\n * if (isGuestEmployee(employee)) {\r\n * // Handle guest-specific logic\r\n * console.log('Guest employee:', employee.email);\r\n * }\r\n * ```\r\n */\r\nexport function isGuestEmployee(employee: EmployeeDocument): boolean {\r\n return !employee.userId;\r\n}\r\n\r\n/**\r\n * Type guard: Check if employee has a user ID\r\n *\r\n * @param employee - Employee document\r\n * @returns True if employee has userId (not guest)\r\n */\r\nexport function hasUserId(employee: EmployeeDocument): employee is EmployeeDocument & { userId: NonNullable<EmployeeDocument['userId']> } {\r\n return !!employee.userId;\r\n}\r\n\r\n/**\r\n * Type guard: Check if employee has a customer ID (from populated userId)\r\n *\r\n * @param employee - Employee document\r\n * @returns True if customer ID exists\r\n */\r\nexport function hasCustomerId(employee: EmployeeDocument): boolean {\r\n return !!employee.userId;\r\n}\r\n\r\n/**\r\n * Check if error is a validation error\r\n *\r\n * @param error - Unknown error object\r\n * @returns True if Mongoose/MongoDB validation error\r\n */\r\nexport function isValidationError(error: unknown): error is Error & { name: 'ValidationError' } {\r\n return error instanceof Error && error.name === 'ValidationError';\r\n}\r\n\r\n/**\r\n * Type guard for Error instances\r\n *\r\n * @param error - Unknown value\r\n * @returns True if Error instance\r\n */\r\nexport function isError(error: unknown): error is Error {\r\n return error instanceof Error;\r\n}\r\n\r\n/**\r\n * Safe error message extraction\r\n *\r\n * @param error - Unknown error object\r\n * @returns Error message or generic fallback\r\n *\r\n * @example\r\n * ```typescript\r\n * try {\r\n * await dangerousOperation();\r\n * } catch (error) {\r\n * logger.error(getErrorMessage(error));\r\n * }\r\n * ```\r\n */\r\nexport function getErrorMessage(error: unknown): string {\r\n if (isError(error)) {\r\n return error.message;\r\n }\r\n\r\n if (typeof error === 'string') {\r\n return error;\r\n }\r\n\r\n if (error && typeof error === 'object' && 'message' in error) {\r\n return String(error.message);\r\n }\r\n\r\n return 'Unknown error occurred';\r\n}\r\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';\nimport { diffInDays, toUTCDateString } from './date.js';\nimport { roundMoney } from './money.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) => toUTCDateString(d)));\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(toUTCDateString(current));\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 = roundMoney(baseSalary / workingDaysInMonth, 2);\n return roundMoney(dailyRate * unpaidDays, 2);\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// 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 - Secure Employee Lookup\n *\n * Multi-tenant safe employee lookup utilities\n * Enforces organizationId isolation on all queries\n */\n\nimport type { Model, ClientSession } 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 * Strict multi-tenant mode\n *\n * When true (default), throws if organizationId is not provided.\n * This prevents accidental cross-tenant data leaks.\n *\n * Set to false ONLY for:\n * - Single-tenant applications with auto-inject configured\n * - Migration scripts with explicit security review\n *\n * @default true (secure by default)\n * @since v3.0.0\n */\n strictMultiTenant?: boolean;\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?: ClientSession;\n\n /**\n * Fields to populate\n */\n populate?: string | string[];\n}\n\n/**\n * Securely find an employee by various identifiers\n *\n * SECURITY: By default (strictMultiTenant=true), this function REQUIRES organizationId\n * and will throw an error if not provided. This prevents cross-tenant data leaks.\n *\n * @param model - Employee model\n * @param options - Lookup options\n * @returns Employee document or throws EmployeeNotFoundError\n * @throws Error if organizationId not provided in strict mode (default)\n *\n * @example\n * // By ObjectId _id (organizationId required)\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 * // Single-tenant mode (explicitly opt-out of strict mode)\n * const emp = await findEmployeeSecure(Employee, {\n * employeeId: \"EMP-001\",\n * strictMultiTenant: false, // Only for single-tenant apps!\n * });\n */\nexport async function findEmployeeSecure<T extends EmployeeDocument>(\n model: Model<T>,\n options: SecureEmployeeLookupOptions\n): Promise<T> {\n const {\n organizationId,\n strictMultiTenant = true, // SECURITY: Default to strict mode to prevent cross-tenant leaks\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, unknown> = {};\n\n // STRICT MODE: Enforce organizationId in multi-tenant apps\n if (strictMultiTenant && !organizationId) {\n throw new Error(\n 'findEmployeeSecure requires organizationId in strict multi-tenant mode. ' +\n 'Set strictMultiTenant: false for single-tenant apps.'\n );\n }\n\n // 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 // Normalize email (lowercase + trim) to match schema storage format\n query.email = email.toLowerCase().trim();\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, unknown>;\n session?: ClientSession;\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?: ObjectIdLike; 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 // FIX: Check if single-tenant mode is enabled AND autoInject is not disabled\n if (container?.isSingleTenant()) {\n const singleTenantConfig = container.getSingleTenantConfig();\n const autoInjectEnabled = singleTenantConfig?.autoInject !== false; // default: true\n\n if (autoInjectEnabled) {\n const orgId = container.getOrganizationId();\n if (orgId) {\n return toObjectId(orgId);\n }\n // Single-tenant with autoInject but no organizationId configured\n const operationName = operation || 'Operation';\n throw new Error(\n `${operationName}: Single-tenant mode with autoInject enabled requires organizationId in configuration.\\n\\n` +\n 'Fix by configuring organizationId:\\n' +\n ' const payroll = createPayrollInstance()\\n' +\n ' .withModels({ ... })\\n' +\n ' .forSingleTenant({ organizationId: YOUR_ORG_ID, autoInject: true })\\n' +\n ' .build();\\n\\n' +\n 'Or provide organizationId explicitly in each operation:\\n' +\n ` await payroll.${operation || 'method'}({ organizationId: org._id, ... });`\n );\n }\n // autoInject is explicitly disabled - fall through to require explicit orgId\n }\n\n // 4. Error - no organizationId found (multi-tenant or single-tenant with autoInject: false)\n const operationName = operation || 'Operation';\n const isSingleTenantNoAutoInject = container?.isSingleTenant() &&\n container.getSingleTenantConfig()?.autoInject === false;\n\n if (isSingleTenantNoAutoInject) {\n throw new Error(\n `${operationName} requires organizationId (autoInject is disabled in single-tenant config).\\n\\n` +\n 'Provide organizationId explicitly:\\n' +\n ` await payroll.${operation || 'method'}({ organizationId: org._id, ... });`\n );\n }\n\n throw new Error(\n `${operationName} requires organizationId in multi-tenant mode.\\n\\n` +\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\\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 - 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// NOTE: buildEmployeeQuery has been removed from this file.\n// Use buildEmployeeQuery from query-builders.ts instead, which has a more flexible API.\n// The removed function duplicated functionality and was intentionally not exported.\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","/**\r\n * @classytic/payroll - Error Helpers\r\n *\r\n * Higher-level error handling utilities that combine type guards\r\n * and error classes for common payroll error scenarios.\r\n *\r\n * Uses:\r\n * - `../errors/index.js` for PayrollError classes\r\n * - `./type-guards.js` for MongoDB error type checking\r\n *\r\n * @module @classytic/payroll/utils/error-helpers\r\n */\r\n\r\nimport {\r\n PayrollError,\r\n DuplicatePayrollError,\r\n extractErrorInfo,\r\n toPayrollError,\r\n} from '../errors/index.js';\r\nimport {\r\n isDuplicateKeyError,\r\n parseDuplicateKeyError,\r\n isTransactionError,\r\n isTransactionUnsupportedError,\r\n isConnectionError,\r\n getErrorMessage,\r\n} from './type-guards.js';\r\n\r\n// ============================================================================\r\n// Transaction Error Handling\r\n// ============================================================================\r\n\r\nexport interface TransactionErrorResult {\r\n /** Whether the error is transaction-related */\r\n isTransactionError: boolean;\r\n /** Whether transactions are unsupported (standalone MongoDB) */\r\n isUnsupported: boolean;\r\n /** Whether the operation can be safely retried */\r\n retryable: boolean;\r\n /** Wrapped PayrollError with context */\r\n error: PayrollError;\r\n /** Original error for logging */\r\n originalError: unknown;\r\n}\r\n\r\n/**\r\n * Handle transaction-specific errors with categorization and retry guidance.\r\n *\r\n * Categorizes transaction errors into:\r\n * - **Unsupported**: Standalone MongoDB without replica set (non-retryable, graceful fallback)\r\n * - **Transient**: Network issues, coordinator changes (retryable)\r\n * - **Connection**: Server unreachable, shutdown (retryable after delay)\r\n * - **Other**: Unknown transaction errors (non-retryable)\r\n *\r\n * @param error - Unknown error from a transaction operation\r\n * @param operationName - Name of the operation for context (e.g., 'processSalary')\r\n * @returns Structured error result with retry guidance\r\n *\r\n * @example\r\n * ```typescript\r\n * try {\r\n * await processWithTransaction(session);\r\n * } catch (error) {\r\n * const result = handleTransactionError(error, 'processSalary');\r\n * if (result.isUnsupported) {\r\n * // Fall back to non-transactional processing\r\n * await processWithoutTransaction();\r\n * } else if (result.retryable) {\r\n * // Retry the operation\r\n * await retry(() => processWithTransaction(session));\r\n * } else {\r\n * throw result.error;\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function handleTransactionError(\r\n error: unknown,\r\n operationName: string\r\n): TransactionErrorResult {\r\n const isUnsupported = isTransactionUnsupportedError(error);\r\n const isTxError = isTransactionError(error);\r\n const isConnError = isConnectionError(error);\r\n\r\n const retryable = isTxError && !isUnsupported;\r\n\r\n const wrappedError = toPayrollError(error);\r\n wrappedError.context.operationName = operationName;\r\n wrappedError.context.transactionError = true;\r\n\r\n if (isUnsupported) {\r\n wrappedError.context.reason = 'transactions_unsupported';\r\n } else if (isConnError) {\r\n wrappedError.context.reason = 'connection_error';\r\n } else if (isTxError) {\r\n wrappedError.context.reason = 'transaction_conflict';\r\n }\r\n\r\n return {\r\n isTransactionError: isTxError || isUnsupported,\r\n isUnsupported,\r\n retryable,\r\n error: wrappedError,\r\n originalError: error,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Duplicate Key Error Handling\r\n// ============================================================================\r\n\r\nexport interface DuplicateKeyErrorResult {\r\n /** Whether the error is a duplicate key error */\r\n isDuplicate: boolean;\r\n /** The field name that caused the duplicate */\r\n field: string;\r\n /** Wrapped DuplicatePayrollError or PayrollError */\r\n error: PayrollError;\r\n}\r\n\r\n/**\r\n * Handle MongoDB duplicate key errors with field extraction.\r\n *\r\n * Converts raw MongoDB E11000 errors into structured DuplicatePayrollError\r\n * or PayrollError with the duplicate field identified.\r\n *\r\n * @param error - Unknown error from a create/update operation\r\n * @param context - Additional context for the error\r\n * @returns Structured duplicate key error result\r\n *\r\n * @example\r\n * ```typescript\r\n * try {\r\n * await PayrollRecord.create(data);\r\n * } catch (error) {\r\n * const result = handleDuplicateKeyError(error, {\r\n * employeeId: 'EMP-001',\r\n * month: 1,\r\n * year: 2024,\r\n * });\r\n * if (result.isDuplicate) {\r\n * throw result.error; // DuplicatePayrollError with field info\r\n * }\r\n * throw error; // Re-throw non-duplicate errors\r\n * }\r\n * ```\r\n */\r\nexport function handleDuplicateKeyError(\r\n error: unknown,\r\n context?: { employeeId?: string; month?: number; year?: number }\r\n): DuplicateKeyErrorResult {\r\n if (!isDuplicateKeyError(error)) {\r\n return {\r\n isDuplicate: false,\r\n field: '',\r\n error: toPayrollError(error),\r\n };\r\n }\r\n\r\n const field = parseDuplicateKeyError(error);\r\n\r\n const wrappedError = context?.employeeId && context?.month && context?.year\r\n ? new DuplicatePayrollError(context.employeeId, context.month, context.year, undefined, { duplicateField: field })\r\n : toPayrollError(error);\r\n\r\n return {\r\n isDuplicate: true,\r\n field,\r\n error: wrappedError,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// General Payroll Error Handling\r\n// ============================================================================\r\n\r\nexport interface PayrollErrorResult {\r\n /** Error code for programmatic handling */\r\n code: string;\r\n /** HTTP status code */\r\n status: number;\r\n /** Human-readable error message */\r\n message: string;\r\n /** Additional context */\r\n context: Record<string, unknown>;\r\n /** Whether the error is operational (expected) vs programmer error */\r\n operational: boolean;\r\n /** Whether the operation can be retried */\r\n retryable: boolean;\r\n}\r\n\r\n/**\r\n * Handle any payroll operation error and produce a structured result.\r\n *\r\n * Combines error classification from type-guards with PayrollError\r\n * extraction to produce a unified error result suitable for API responses,\r\n * logging, or retry decisions.\r\n *\r\n * @param error - Unknown error from any payroll operation\r\n * @param operationName - Name of the operation for context\r\n * @returns Structured error result\r\n *\r\n * @example\r\n * ```typescript\r\n * try {\r\n * await payroll.processSalary(params);\r\n * } catch (error) {\r\n * const result = handlePayrollError(error, 'processSalary');\r\n * logger.error(result.message, { code: result.code, context: result.context });\r\n * res.status(result.status).json({ error: result });\r\n * }\r\n * ```\r\n */\r\nexport function handlePayrollError(\r\n error: unknown,\r\n operationName: string\r\n): PayrollErrorResult {\r\n const info = extractErrorInfo(error);\r\n\r\n // Determine if retryable\r\n const retryable =\r\n isConnectionError(error) ||\r\n (isTransactionError(error) && !isTransactionUnsupportedError(error));\r\n\r\n // Determine if operational\r\n const operational = error instanceof PayrollError\r\n ? error.isOperational()\r\n : false;\r\n\r\n return {\r\n code: info.code,\r\n status: info.status,\r\n message: info.message,\r\n context: {\r\n ...info.context,\r\n operationName,\r\n },\r\n operational,\r\n retryable,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Error Message Formatting\r\n// ============================================================================\r\n\r\n/**\r\n * Format error for user-facing display.\r\n *\r\n * Strips internal details and produces a clean message suitable\r\n * for API responses or UI display.\r\n *\r\n * @param error - Unknown error\r\n * @returns User-safe error message\r\n */\r\nexport function formatUserError(error: unknown): string {\r\n if (error instanceof PayrollError) {\r\n // PayrollErrors have controlled messages safe for users\r\n return error.message;\r\n }\r\n\r\n if (isDuplicateKeyError(error)) {\r\n const field = parseDuplicateKeyError(error);\r\n return `A record with this ${field} already exists`;\r\n }\r\n\r\n if (isTransactionUnsupportedError(error)) {\r\n return 'Database does not support transactions. Please use a replica set.';\r\n }\r\n\r\n if (isConnectionError(error)) {\r\n return 'Database connection error. Please try again.';\r\n }\r\n\r\n // Generic fallback - don't expose internal details\r\n return 'An unexpected error occurred';\r\n}\r\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 isEffectiveForPeriod,\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// Money Utilities (Banker's Rounding for Payroll Compliance)\n// ============================================================================\n\nexport {\n roundMoney,\n roundMoneyPositive,\n percentageOf,\n prorateAmount,\n} from './money.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 applyTaxBrackets,\n calculateTax,\n calculateOvertime,\n calculateHourlyRate,\n calculateDailyRate,\n default as calculationUtils,\n} from './calculation.js';\n\n// Pro-rating utilities - use calculators/prorating.calculator.ts for advanced features\nexport {\n calculateProRating,\n applyProRating,\n} from '../calculators/prorating.calculator.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// ============================================================================\n// Error Helpers (High-Level Error Handling)\n// ============================================================================\n\nexport {\n handleTransactionError,\n handleDuplicateKeyError,\n handlePayrollError,\n formatUserError,\n type TransactionErrorResult,\n type DuplicateKeyErrorResult,\n type PayrollErrorResult,\n} from './error-helpers.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 TaxWithholdingModel,\n TaxType,\n TaxStatus,\n ObjectIdLike,\n ObjectId,\n PayrollBreakdown,\n PayrollPeriod,\n AnyModel,\n AnyDocument,\n OperationContext,\n GetPendingTaxParams,\n TaxSummaryParams,\n TaxSummaryResult,\n MarkTaxPaidParams,\n} from '../types.js';\nimport type { EventBus } from '../core/events.js';\nimport { TaxStatusMachine } from '../core/payroll-states.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: TaxWithholdingModel;\n TransactionModel?: AnyModel;\n events?: EventBus;\n}\n\nexport interface CreateFromBreakdownParams {\n organizationId: ObjectId;\n employeeId: ObjectId;\n /** Human-readable employee ID (e.g., \"EMP-001\") for event payloads */\n employeeBusinessId?: string;\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: TaxWithholdingModel,\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 all\n * TaxWithholding records in a single batch operation (one DB roundtrip).\n * Events are emitted for each created withholding after the batch insert.\n *\n * @param params - Breakdown data, employee info, and session\n * @returns Array of created TaxWithholdingDocuments (empty if no tax deductions)\n */\n async createFromBreakdown(params: CreateFromBreakdownParams): Promise<TaxWithholdingDocument[]> {\n const {\n organizationId,\n employeeId,\n employeeBusinessId,\n userId,\n payrollRecordId,\n transactionId,\n period,\n breakdown,\n currency = 'USD',\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 // Prepare all withholding data for batch creation\n const withholdingDataArray = taxDeductions.map(deduction => {\n const taxType = this.mapDeductionTypeToTaxType(deduction.type);\n const taxRate = breakdown.taxableAmount && breakdown.taxableAmount > 0\n ? deduction.amount / breakdown.taxableAmount\n : 0;\n\n return {\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\n // Batch create all withholdings in a single database operation\n // Performance: 2-5x faster than sequential creates (1 roundtrip vs N roundtrips)\n const withholdings = await this.TaxWithholdingModel.create(\n withholdingDataArray,\n { session }\n );\n\n // Emit tax:withheld event for each created withholding\n if (this.events) {\n withholdings.forEach(withholding => {\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: employeeBusinessId || employeeId.toString(),\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\n // Log batch creation summary\n if (withholdings.length > 0) {\n logger.info('Tax withholdings batch created', {\n count: withholdings.length,\n employeeId: employeeId.toString(),\n taxTypes: withholdings.map(w => w.taxType),\n totalAmount: withholdings.reduce((sum, w) => sum + w.amount, 0),\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.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() as Promise<TaxWithholdingDocument[]>;\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.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 using bulkWrite (single DB roundtrip), optionally creates\n * a government payment transaction, and emits tax:paid event.\n *\n * State transitions are pre-validated in memory before the batch update\n * to ensure all withholdings can transition to 'paid' status.\n *\n * @param params - Mark paid parameters (IDs, reference number, notes)\n * @returns Updated withholdings and optional government transaction\n * @throws Error if any withholding cannot transition to 'paid' status\n */\n async markPaid(params: MarkTaxPaidParams): Promise<{\n withholdings: TaxWithholdingDocument[];\n transaction?: AnyDocument;\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: AnyDocument | null = 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' as 'outflow',\n tags: ['tax', 'government', 'withholding'],\n amount: totalAmount,\n net: totalAmount,\n currency: withholdings[0].currency || 'USD',\n method: 'bank',\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 // Pre-validate all state transitions before batch update\n for (const withholding of withholdings) {\n const transition = TaxStatusMachine.validateTransition(withholding.status, TAX_STATUS.PAID);\n if (!transition.success) {\n throw new Error(`Cannot mark withholding ${withholding._id} as paid: ${transition.error}`);\n }\n }\n\n // Batch update all withholdings in a single database operation\n // Performance: 1 roundtrip instead of N sequential saves\n const bulkOps = withholdings.map(w => ({\n updateOne: {\n filter: { _id: w._id },\n update: {\n $set: {\n status: TAX_STATUS.PAID,\n governmentTransactionId: governmentTransaction?._id,\n referenceNumber,\n paidAt,\n },\n },\n },\n }));\n\n await this.TaxWithholdingModel.bulkWrite(bulkOps, { session });\n\n // Sync in-memory documents to match database state\n for (const withholding of withholdings) {\n withholding.status = TAX_STATUS.PAID;\n withholding.governmentTransactionId = governmentTransaction?._id;\n withholding.referenceNumber = referenceNumber;\n withholding.paidAt = paidAt;\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 as number,\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 ?? undefined,\n };\n }\n\n /**\n * Get tax withholdings for a specific payroll record\n *\n * @param organizationId - Required for multi-tenant isolation\n * @param payrollRecordId - The payroll record ID to find withholdings for\n */\n async getByPayrollRecord(\n organizationId: ObjectIdLike,\n payrollRecordId: ObjectIdLike\n ): Promise<TaxWithholdingDocument[]> {\n // Use direct query with organizationId enforcement for security\n return this.TaxWithholdingModel.find({\n organizationId: toObjectId(organizationId),\n payrollRecordId: toObjectId(payrollRecordId),\n }).exec();\n }\n\n /**\n * Void/cancel tax withholdings for a payroll record\n *\n * Used when voiding or reversing a payroll to invalidate associated tax withholdings.\n * Changes status to 'cancelled' and adds void metadata.\n *\n * @returns Number of withholdings voided\n */\n async voidByPayrollRecord(params: {\n payrollRecordId: ObjectIdLike;\n organizationId: ObjectIdLike;\n reason: string;\n voidedBy?: ObjectIdLike;\n session?: ClientSession;\n }): Promise<{ voidedCount: number; withholdings: TaxWithholdingDocument[] }> {\n const { payrollRecordId, organizationId, reason, voidedBy, session } = params;\n\n // Find all withholdings for this payroll record\n const withholdings = await this.TaxWithholdingModel.find({\n payrollRecordId: toObjectId(payrollRecordId),\n organizationId: toObjectId(organizationId),\n status: { $in: ['pending', 'submitted'] }, // Only cancel pending/submitted (per TaxStatusMachine)\n }).session(session || null);\n\n if (withholdings.length === 0) {\n return { voidedCount: 0, withholdings: [] };\n }\n\n // Update all withholdings to cancelled status (with state machine validation)\n const voidedAt = new Date();\n const successfullyVoided: TaxWithholdingDocument[] = [];\n const failedVoids: Array<{ id: string; status: string; error: string }> = [];\n\n for (const withholding of withholdings) {\n // Validate state transition\n const transition = TaxStatusMachine.validateTransition(\n withholding.status,\n TAX_STATUS.CANCELLED\n );\n if (!transition.success) {\n failedVoids.push({\n id: withholding._id.toString(),\n status: withholding.status,\n error: transition.error,\n });\n continue; // Skip withholdings that cannot be cancelled\n }\n\n try {\n withholding.status = TAX_STATUS.CANCELLED;\n withholding.voidedAt = voidedAt;\n withholding.voidedBy = voidedBy ? toObjectId(voidedBy) : undefined;\n withholding.voidReason = reason;\n withholding.notes = `${withholding.notes || ''}\\n[VOIDED] ${reason}`.trim();\n await withholding.save({ session });\n successfullyVoided.push(withholding);\n } catch (error) {\n failedVoids.push({\n id: withholding._id.toString(),\n status: withholding.status,\n error: (error as Error).message,\n });\n }\n }\n\n // Log warning if some couldn't be voided\n if (failedVoids.length > 0) {\n logger.warn(`Could not void ${failedVoids.length} of ${withholdings.length} tax withholdings`, {\n payrollRecordId: payrollRecordId.toString(),\n failures: failedVoids,\n });\n }\n\n // Emit tax:voided event only for successfully voided withholdings\n if (this.events && successfullyVoided.length > 0) {\n this.events.emitSync('tax:voided', {\n withholdings: successfullyVoided.map((w) => ({\n id: w._id,\n taxType: w.taxType,\n amount: w.amount,\n })),\n payrollRecordId: toObjectId(payrollRecordId),\n organizationId: toObjectId(organizationId),\n reason,\n voidedAt,\n voidedBy,\n });\n }\n\n logger.info('Tax withholdings voided', {\n requested: withholdings.length,\n successful: successfullyVoided.length,\n failed: failedVoids.length,\n payrollRecordId: payrollRecordId.toString(),\n reason,\n });\n\n return {\n voidedCount: successfullyVoided.length, // Return accurate count\n withholdings: successfullyVoided,\n };\n }\n\n /**\n * Get tax withholdings for a specific employee\n *\n * @param organizationId - Required for multi-tenant isolation\n * @param employeeId - The employee ID to find withholdings for\n * @param options - Optional filters for year, taxType, status\n */\n async getByEmployee(\n organizationId: ObjectIdLike,\n employeeId: ObjectIdLike,\n options?: { year?: number; taxType?: TaxType; status?: TaxStatus }\n ): Promise<TaxWithholdingDocument[]> {\n // Build query with organizationId enforcement for security\n const query: Record<string, unknown> = {\n organizationId: toObjectId(organizationId),\n employeeId: toObjectId(employeeId),\n };\n\n if (options?.year) {\n query['period.year'] = options.year;\n }\n if (options?.taxType) {\n query.taxType = options.taxType;\n }\n if (options?.status) {\n query.status = options.status;\n }\n\n return this.TaxWithholdingModel.find(query).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 * In single-tenant mode with autoInject enabled (default), automatically\n * injects the configured organizationId into the context.\n *\n * @throws Error if autoInject is enabled but no organizationId is configured\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 // FIX: Check if single-tenant mode is enabled (config exists)\n const isSingleTenant = !!this._singleTenant;\n const autoInjectEnabled = isSingleTenant && this._singleTenant?.autoInject !== false;\n\n if (autoInjectEnabled && !overrides?.organizationId) {\n const orgId = this.getOrganizationId();\n if (orgId) {\n context.organizationId = orgId;\n } else {\n // Single-tenant mode with autoInject but no organizationId configured\n throw new Error(\n 'Single-tenant mode with autoInject enabled requires organizationId in configuration. ' +\n 'Configure it via forSingleTenant({ organizationId: YOUR_ORG_ID }) or provide it explicitly.'\n );\n }\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';\nimport { roundMoney } from './utils/money.js';\n\n// ============================================================================\n// Default Configuration\n// ============================================================================\n\nexport const HRM_CONFIG: HRMConfig = {\n dataRetention: {\n /**\n * Default retention period for payroll records in seconds\n *\n * STANDARD APPROACH: expireAt field + configurable TTL index\n *\n * ## How It Works:\n * 1. Set expireAt date on each payroll record\n * 2. Call PayrollRecord.configureRetention() at app startup\n * 3. MongoDB deletes documents when expireAt is reached\n *\n * ## Usage:\n *\n * @example Configure at initialization\n * ```typescript\n * await payroll.init({ ... });\n * await PayrollRecord.configureRetention(0); // 0 = delete when expireAt reached\n * ```\n *\n * @example Set expireAt per record\n * ```typescript\n * const expireAt = PayrollRecord.calculateExpireAt(7); // 7 years\n * await PayrollRecord.updateOne({ _id }, { expireAt });\n * ```\n *\n * ## Jurisdiction Requirements:\n * - USA: 7 years → 220752000 seconds\n * - EU/UK: 6 years → 189216000 seconds\n * - Germany: 10 years → 315360000 seconds\n * - India: 8 years → 252288000 seconds\n *\n * Set to 0 to disable TTL\n */\n payrollRecordsTTL: 63072000, // 2 years - adjust per jurisdiction\n exportWarningDays: 30,\n archiveBeforeDeletion: true,\n },\n\n payroll: {\n defaultCurrency: 'USD',\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// These brackets represent progressive tax rates AFTER the tax-free threshold.\n// The threshold is handled separately via jurisdictionTaxConfig.standardDeduction\n// or thresholdsByCategory. Do NOT include a 0% bracket for the tax-free amount —\n// that would cause a double deduction when used with standardDeduction.\n// ============================================================================\n\nexport const TAX_BRACKETS: Record<string, TaxBracket[]> = {\n // Bangladesh FY 2024-25 rates (after tax-free threshold)\n BDT: [\n { min: 0, max: 100000, rate: 0.05 },\n { min: 100000, max: 400000, rate: 0.10 },\n { min: 400000, max: 700000, rate: 0.15 },\n { min: 700000, max: 1100000, rate: 0.20 },\n { min: 1100000, 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 *\n * Uses banker's rounding to prevent systematic bias in tax calculations.\n * Tax is calculated progressively across brackets and rounded once at the end.\n *\n * @param annualIncome - Annual income in major units (dollars/rupees/taka)\n * @param currency - Currency code (default: 'USD')\n * @returns Tax amount in major units, properly rounded with banker's rounding\n */\nexport function calculateTax(annualIncome: number, currency = 'USD'): 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\n // Use roundMoney for consistency with all other money calculations\n // This ensures identical rounding behavior across all tax calculations\n return roundMoney(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 roundMoney((amount * periodsPerYear) / 12, 2);\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 roundMoney(amount * periodsPerYear, 2);\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 ObjectIdLike,\n OperationContext,\n} from '../types.js';\nimport { getLogger } from '../utils/logger.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 exportId?: string;\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\nexport interface TaxVoidedEventPayload {\n withholdings: Array<{\n id: ObjectId;\n taxType: string;\n amount: number;\n }>;\n payrollRecordId: ObjectId;\n organizationId: ObjectId;\n reason: string;\n voidedAt: Date;\n voidedBy?: ObjectIdLike;\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 'tax:voided': TaxVoidedEventPayload;\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 getLogger().error(`Event handler error for ${event}`, {\n error: error instanceof Error ? error.message : String(error),\n });\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';\nimport { getLogger } from '../utils/logger.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 (handlerError) {\n // Ignore errors in error handlers to prevent infinite loops\n // But log at debug level for troubleshooting\n getLogger().debug('Error handler threw an error', {\n hook: hookName,\n handlerError: handlerError instanceof Error ? handlerError.message : String(handlerError),\n });\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 // Logger not available in hook context, this is a static error handler\n // Use getLogger() for consistent logging\n getLogger().error(`[Payroll Error] ${context}:`, { error: 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 *\n * Ensures operations are not duplicated when called with the same key.\n * Uses Stripe-style idempotency pattern for payroll operations.\n *\n * ## Key Format (v2.9.0+)\n *\n * Idempotency keys support multiple payroll frequencies:\n *\n * **Monthly frequency:**\n * ```\n * payroll:{organizationId}:{employeeId}:{year}-{month}:{payrollRunType}\n * ```\n *\n * **Non-monthly frequencies (weekly, bi_weekly, daily, hourly):**\n * ```\n * payroll:{organizationId}:{employeeId}:{year}-{month}:{startDate}:{payrollRunType}\n * ```\n *\n * This allows:\n * - Different payroll types (regular, supplemental, retroactive) in the same period\n * - Multiple weekly/bi-weekly/daily payroll runs within the same calendar month\n *\n * ## Important: In-Memory Cache Limitations\n *\n * This implementation uses an **in-memory LRU cache** which has the following limitations:\n *\n * - **Does NOT persist across server restarts** - cache is lost on restart\n * - **Does NOT work across multiple server instances** - each instance has its own cache\n * - **Only prevents duplicates within the same process lifetime**\n *\n * For production deployments with horizontal scaling or high availability requirements,\n * you should implement database-backed idempotency. See the Payroll class documentation\n * for implementation examples.\n *\n * ## Duplicate Protection (v2.9.0+)\n *\n * Primary duplicate protection is via **database unique compound index**:\n * `{ organizationId, employeeId, period.month, period.year, period.startDate, payrollRunType }`\n *\n * This prevents race conditions under concurrent load. The partial filter\n * excludes voided records to allow re-processing after restoration.\n *\n * The in-memory cache is a secondary optimization layer, not the primary protection.\n *\n * @see https://stripe.com/docs/api/idempotent_requests\n */\n\nimport { LRUCache } from 'lru-cache';\nimport type { ObjectIdLike } from '../types.js';\nimport { getLogger } from '../utils/logger.js';\n\nexport interface IdempotentResult<T = unknown> {\n value: T;\n cached: boolean;\n createdAt: Date;\n}\n\n/**\n * In-memory idempotency manager for preventing duplicate operations.\n *\n * @warning This is an in-memory cache. For production horizontal scaling,\n * implement database-backed idempotency instead.\n */\nexport class IdempotencyManager {\n private cache: LRUCache<string, { value: unknown; createdAt: Date }>;\n private static hasLoggedWarning = false;\n\n constructor(options: { max?: number; ttl?: number; suppressWarning?: boolean } = {}) {\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 // Log production warning once per process\n if (\n !options.suppressWarning &&\n !IdempotencyManager.hasLoggedWarning &&\n process.env.NODE_ENV === 'production'\n ) {\n IdempotencyManager.hasLoggedWarning = true;\n getLogger().warn(\n 'IdempotencyManager: Using in-memory cache. ' +\n 'For horizontal scaling, implement database-backed idempotency. ' +\n 'See @classytic/payroll documentation for implementation guidance.',\n { cacheMax: options.max || 10000, cacheTTL: options.ttl || 86400000 }\n );\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 as T,\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 * Payroll run types for idempotency key generation\n */\nexport type PayrollRunType = 'regular' | 'off-cycle' | 'supplemental' | 'retroactive';\n\n/**\n * Generate idempotency key for payroll operations\n *\n * Includes payrollRunType to allow multiple payroll runs per period\n * (e.g., regular + supplemental bonus + retroactive adjustment)\n *\n * For non-monthly frequencies (weekly, bi_weekly, daily, hourly), the periodStartDate\n * is included to differentiate multiple runs within the same calendar month.\n *\n * @param organizationId - Organization ID\n * @param employeeId - Employee ID\n * @param month - Payroll month (1-12)\n * @param year - Payroll year\n * @param payrollRunType - Type of payroll run (default: 'regular')\n * @param periodStartDate - Period start date (required for non-monthly frequencies)\n */\nexport function generatePayrollIdempotencyKey(\n organizationId: ObjectIdLike,\n employeeId: ObjectIdLike,\n month: number,\n year: number,\n payrollRunType: PayrollRunType = 'regular',\n periodStartDate?: Date\n): string {\n // For non-monthly frequencies, include the period start date to differentiate\n // multiple runs within the same calendar month\n if (periodStartDate) {\n const startDateStr = periodStartDate.toISOString().split('T')[0]; // YYYY-MM-DD\n return `payroll:${organizationId}:${employeeId}:${year}-${month}:${startDateStr}:${payrollRunType}`;\n }\n return `payroll:${organizationId}:${employeeId}:${year}-${month}:${payrollRunType}`;\n}\n","/**\n * Webhook System\n * Sends HTTP notifications when payroll events occur\n */\n\nimport crypto from 'crypto';\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 WebhookManagerOptions {\n /**\n * Maximum number of delivery log entries to retain (default: 1000).\n * Oldest entries are pruned when the limit is exceeded.\n */\n maxLogSize?: number;\n /**\n * Whether to store full payloads in the delivery log (default: false).\n * When false, only metadata (event, url, status, error, sentAt) is stored,\n * preventing PII from accumulating in memory.\n */\n storePayloads?: boolean;\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 private readonly maxLogSize: number;\n private readonly storePayloads: boolean;\n\n constructor(options?: WebhookManagerOptions) {\n this.maxLogSize = options?.maxLogSize ?? 1000;\n this.storePayloads = options?.storePayloads ?? false;\n }\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: this.storePayloads ? payload : undefined,\n attempt: 0,\n status: 'pending',\n };\n\n this.deliveryLog.push(delivery);\n this.pruneLog();\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 timestamp = Math.floor(Date.now() / 1000);\n const deliveredAt = new Date().toISOString();\n\n const requestBody = {\n event,\n payload,\n deliveredAt,\n };\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Payroll-Event': event,\n 'X-Payroll-Delivery': deliveryId,\n 'X-Payroll-Timestamp': timestamp.toString(),\n ...webhook.headers,\n };\n\n if (webhook.secret) {\n headers['X-Payroll-Signature'] = this.generateSignature(requestBody, webhook.secret, timestamp);\n }\n\n const response = await fetch(webhook.url, {\n method: 'POST',\n headers,\n body: JSON.stringify(requestBody),\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 transient errors: 5xx, 429 (rate limit), 408 (timeout)\n const shouldRetry = (\n response.status >= 500 ||\n response.status === 429 ||\n response.status === 408\n );\n\n if (shouldRetry && attempt < maxRetries) {\n // Exponential backoff with jitter\n const backoff = Math.pow(2, attempt) * 1000;\n const jitter = Math.random() * 1000;\n await this.sleep(backoff + jitter);\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-SHA256 signature for webhook (Stripe-style)\n *\n * Format: t=<timestamp>,v1=<hmac_signature>\n *\n * The signed payload is: timestamp.JSON(requestBody)\n * where requestBody = { event, payload, deliveredAt }\n *\n * Consumers should verify:\n * 1. Timestamp is within tolerance (e.g., 5 minutes)\n * 2. HMAC signature matches\n *\n * @example Verify signature (consumer side)\n * ```typescript\n * import crypto from 'crypto';\n *\n * const signature = req.headers['x-payroll-signature'];\n * const timestamp = req.headers['x-payroll-timestamp'];\n * const requestBody = req.body; // { event, payload, deliveredAt }\n *\n * // Check timestamp (replay protection)\n * const now = Math.floor(Date.now() / 1000);\n * if (Math.abs(now - parseInt(timestamp)) > 300) {\n * throw new Error('Signature expired');\n * }\n *\n * // Verify signature\n * const signedPayload = `${timestamp}.${JSON.stringify(requestBody)}`;\n * const expectedSignature = crypto\n * .createHmac('sha256', secret)\n * .update(signedPayload)\n * .digest('hex');\n *\n * const parts = signature.split(',');\n * const providedSignature = parts.find(p => p.startsWith('v1='))?.split('=')[1];\n *\n * if (providedSignature !== expectedSignature) {\n * throw new Error('Invalid signature');\n * }\n * ```\n */\n private generateSignature(requestBody: unknown, secret: string, timestamp: number): string {\n const data = JSON.stringify(requestBody);\n\n // Signed payload: timestamp.data\n const signedPayload = `${timestamp}.${data}`;\n\n // Generate HMAC-SHA256 signature\n const hmac = crypto.createHmac('sha256', secret);\n hmac.update(signedPayload);\n const signature = hmac.digest('hex');\n\n // Stripe-style format: t=timestamp,v1=signature\n return `t=${timestamp},v1=${signature}`;\n }\n\n /**\n * Prune delivery log to stay within maxLogSize.\n * Removes oldest entries first.\n */\n private pruneLog(): void {\n if (this.deliveryLog.length > this.maxLogSize) {\n this.deliveryLog = this.deliveryLog.slice(-this.maxLogSize);\n }\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 - 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 = 'USD'\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 - Transaction Factory\n *\n * Pure functions for building transaction objects aligned with @classytic/shared-types.\n * Ensures consistency with revenue package for unified cashflow.\n *\n * @packageDocumentation\n */\n\nimport type { ITransactionCreateInput } from '@classytic/shared-types';\nimport type { ObjectIdLike, PayrollBreakdown } from '../types.js';\nimport { toObjectId } from '../utils/query-builders.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Input for creating a payroll transaction\n */\nexport interface CreatePayrollTransactionInput {\n organizationId: ObjectIdLike;\n employee: {\n _id: ObjectIdLike;\n userId?: ObjectIdLike | { _id: ObjectIdLike; name?: string } | null;\n employeeId: string;\n email?: string;\n compensation: {\n currency?: string;\n };\n };\n payrollRecord: {\n _id: ObjectIdLike;\n };\n breakdown: PayrollBreakdown;\n period: {\n month: number;\n year: number;\n };\n paymentDate: Date;\n paymentMethod?: string; // Flexible: 'bank', 'cash', 'check', 'mobile_wallet', etc.\n processedBy?: ObjectIdLike;\n idempotencyKey?: string;\n jurisdiction?: string; // Optional: 'US', 'BD', 'UK', etc. (defaults based on org)\n defaultCurrency?: string; // Config default currency (fallback before USD)\n}\n\n/**\n * Input for creating a tax payment transaction\n */\nexport interface CreateTaxPaymentTransactionInput {\n organizationId: ObjectIdLike;\n totalAmount: number;\n currency: string;\n referenceNumber?: string;\n notes?: string;\n withholdingIds: ObjectIdLike[];\n}\n\n// ============================================================================\n// Pure Functions\n// ============================================================================\n\n/**\n * Create payroll transaction aligned with @classytic/shared-types\n *\n * This is the SINGLE SOURCE OF TRUTH for payroll transaction structure.\n * Aligns with revenue package for unified cashflow.\n *\n * @param input - Payroll transaction parameters\n * @returns Transaction data ready for DB creation (ITransactionCreateInput)\n *\n * @pure This function has no side effects\n */\nexport function createPayrollTransaction(input: CreatePayrollTransactionInput): ITransactionCreateInput {\n const { organizationId, employee, payrollRecord, breakdown, period, paymentDate, paymentMethod = 'bank', processedBy, idempotencyKey, jurisdiction, defaultCurrency } = input;\n\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: ObjectIdLike })._id\n : employee.userId)\n : undefined;\n\n // Extract user name for description (if available)\n const userName = employee.userId && typeof employee.userId === 'object' && 'name' in employee.userId\n ? (employee.userId as { name?: string })?.name\n : undefined;\n\n // Use employee's currency with proper fallback chain\n const currency = employee.compensation.currency || defaultCurrency || 'USD';\n\n // Align with @classytic/shared-types ITransactionCreateInput\n return {\n organizationId: toObjectId(organizationId),\n\n // Classification\n type: 'salary',\n flow: 'outflow',\n tags: ['recurring', 'payroll', 'monthly'],\n status: 'completed',\n\n // Amounts (aligned with shared-types)\n amount: breakdown.grossSalary, // Gross amount\n net: breakdown.netSalary, // Net after deductions\n currency, // From employee compensation (flexible!)\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: jurisdiction || undefined, // Optional, app-controlled\n } : undefined,\n\n // Payment (user can pass any method: 'bank_transfer', 'cash', 'check', 'mobile_wallet')\n method: paymentMethod,\n date: paymentDate,\n\n // Parties (shared-types)\n employeeId: toObjectId(employee._id),\n customerId: userIdValue ? toObjectId(userIdValue as ObjectIdLike) : null,\n processedBy: processedBy ? toObjectId(processedBy) : undefined,\n\n // Payroll breakdown (shared-types compatible)\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: period.month,\n year: period.year,\n start: new Date(period.year, period.month - 1, 1),\n end: new Date(period.year, period.month, 0),\n },\n workingDays: breakdown.workingDays\n ? {\n expected: breakdown.workingDays,\n actual: breakdown.actualDays || breakdown.workingDays,\n }\n : undefined,\n },\n\n // References\n sourceId: toObjectId(payrollRecord._id),\n sourceModel: 'PayrollRecord',\n\n // Idempotency (Stripe-style)\n idempotencyKey: idempotencyKey || null,\n\n // Timestamps\n processedAt: paymentDate,\n completedAt: paymentDate,\n\n // Metadata\n description: `Salary payment - ${userName || employee.employeeId} (${period.month}/${period.year})`,\n notes: breakdown.proRatedAmount ? `Pro-rated: ${breakdown.actualDays}/${breakdown.workingDays} days` : undefined,\n metadata: {\n employeeId: employee.employeeId,\n email: employee.email,\n payrollRecordId: payrollRecord._id.toString(),\n },\n };\n}\n\n/**\n * Create tax payment transaction aligned with @classytic/shared-types\n *\n * For government tax payments (withholding remittance).\n *\n * @param input - Tax payment parameters\n * @returns Transaction data ready for DB creation (ITransactionCreateInput)\n *\n * @pure This function has no side effects\n */\nexport function createTaxPaymentTransaction(input: CreateTaxPaymentTransactionInput): ITransactionCreateInput {\n const { organizationId, totalAmount, currency, referenceNumber, notes, withholdingIds } = input;\n\n // Align with shared-types ITransactionCreateInput\n return {\n organizationId: toObjectId(organizationId),\n\n // Classification\n type: 'tax_payment',\n flow: 'outflow',\n tags: ['tax', 'government', 'compliance'],\n status: 'completed',\n\n // Amounts (shared-types convention)\n amount: totalAmount,\n net: totalAmount, // No deductions for tax payments\n currency,\n fee: 0,\n\n // Payment\n method: 'bank',\n date: new Date(),\n\n // References\n sourceModel: 'TaxWithholding',\n\n // Timestamps\n completedAt: new Date(),\n\n // Metadata\n description: referenceNumber\n ? `Tax payment to government - ${referenceNumber}`\n : 'Tax payment to government',\n notes,\n metadata: {\n withholdingIds: withholdingIds.map((id) => id.toString()),\n referenceNumber,\n type: 'government_tax_remittance',\n },\n };\n}\n\n/**\n * Transaction Factory class (for builder pattern if needed)\n */\nexport class TransactionFactory {\n static createPayrollTransaction = createPayrollTransaction;\n static createTaxPaymentTransaction = createTaxPaymentTransaction;\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 * ## Idempotency & Duplicate Protection (v2.8.0+)\n *\n * The package implements multi-layer duplicate protection:\n *\n * ### 1. Database-Level Unique Index (PRIMARY)\n * - Unique compound index on `{ organizationId, employeeId, period.month, period.year, payrollRunType }`\n * - Prevents race conditions: concurrent requests get E11000 duplicate key error\n * - Partial filter excludes voided/reversed records (allows re-processing)\n * - Works across server restarts and multiple instances\n *\n * ### 2. Application-Level Duplicate Check (SECONDARY)\n * - Queries existing records before insert for better error messages\n * - Throws `DuplicatePayrollError` if a record exists\n * - Allows multiple payroll types per period (regular, supplemental, retroactive, off-cycle)\n *\n * ### 3. In-Memory Idempotency Cache (TERTIARY)\n * - Uses `IdempotencyManager` with LRU cache\n * - Stores results for 24 hours by default\n * - Auto-generated keys include run type: `payroll:{orgId}:{empId}:{year}-{month}:{runType}`\n * - Custom keys supported via `idempotencyKey` parameter\n *\n * ### Idempotency Key Format (v2.8.0+)\n *\n * ```\n * payroll:{organizationId}:{employeeId}:{year}-{month}:{payrollRunType}\n * ```\n *\n * Example: `payroll:org123:emp456:2024-3:regular`\n *\n * This allows processing multiple payroll types in the same period:\n * - `payroll:org123:emp456:2024-3:regular` (monthly salary)\n * - `payroll:org123:emp456:2024-3:supplemental` (bonus)\n * - `payroll:org123:emp456:2024-3:retroactive` (backpay adjustment)\n *\n * ### In-Memory Cache Limitations\n *\n * **Note:** The in-memory cache (layer 3) is process-local only:\n * - Does NOT persist across server restarts\n * - Does NOT work across multiple server instances (horizontal scaling)\n * - Only prevents duplicates within the same process lifetime\n *\n * However, the **database unique index (layer 1)** provides full protection\n * across restarts and multiple instances. Concurrent/duplicate requests\n * receive E11000 errors which are automatically handled.\n *\n * ### Implementing DB-Backed Idempotency (Recommended for Production)\n *\n * For production systems with multiple instances, implement database-backed idempotency:\n *\n * ```typescript\n * // 1. Create idempotency collection\n * const IdempotencyKey = mongoose.model('IdempotencyKey', new Schema({\n * key: { type: String, unique: true, required: true },\n * result: { type: Schema.Types.Mixed, required: true },\n * createdAt: { type: Date, default: Date.now, expires: 3600 }, // 1 hour TTL\n * }));\n *\n * // 2. Check before processing (include runType in key!)\n * const runType = params.payrollRunType || 'regular';\n * const key = `payroll:${orgId}:${empId}:${year}-${month}:${runType}`;\n * const existing = await IdempotencyKey.findOne({ key });\n * if (existing) return existing.result;\n *\n * // 3. Process and store result\n * const result = await payroll.processSalary(...);\n * await IdempotencyKey.create({ key, result });\n * return result;\n * ```\n *\n * ### Handling Duplicate Errors\n *\n * When a duplicate payroll is detected:\n * - The package throws `DuplicatePayrollError`\n * - Query the existing payroll record (include payrollRunType!)\n * - Return it to the caller\n *\n * ```typescript\n * try {\n * return await payroll.processSalary(params);\n * } catch (error) {\n * if (error instanceof DuplicatePayrollError) {\n * // Duplicate - fetch and return existing\n * const existing = await PayrollRecord.findOne({\n * employeeId: params.employeeId,\n * 'period.month': params.month,\n * 'period.year': params.year,\n * payrollRunType: params.payrollRunType || 'regular',\n * });\n * return existing;\n * }\n * throw error;\n * }\n * ```\n */\n\nimport mongoose, { Model, type ClientSession } from 'mongoose';\nimport pLimit from 'p-limit';\nimport type {\n PayrollInitConfig,\n HRMConfig,\n SingleTenantConfig,\n Logger,\n ObjectId,\n ObjectIdLike,\n PayrollInstance,\n EmployeeDocument,\n PayrollRecordDocument,\n LeaveRequestDocument,\n TaxWithholdingDocument,\n AnyDocument,\n HireEmployeeParams,\n UpdateEmploymentParams,\n TerminateEmployeeParams,\n ReHireEmployeeParams,\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 Compensation,\n Allowance,\n Deduction,\n GetPendingTaxParams,\n TaxSummaryParams,\n TaxSummaryResult,\n MarkTaxPaidParams,\n OperationContext,\n AnyModel,\n TaxWithholdingModel,\n // Void / Reversal types (v2.4.0+)\n VoidPayrollParams,\n ReversePayrollParams,\n RestorePayrollParams,\n VoidPayrollResult,\n ReversePayrollResult,\n RestorePayrollResult,\n} from './types.js';\nimport {\n PAYROLL_STATUS,\n isVoidablePayrollStatus,\n requiresReversalPayrollStatus,\n isVoidedOrReversedStatus,\n} from './enums.js';\nimport { Container, type ModelsContainer, resetDefaultContainer } from './core/container.js';\nimport { EventBus, createEventBus, type PayrollEventMap, type PayrollEventType } from './core/events.js';\nimport { PayrollStatusMachine } from './core/payroll-states.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 { payroll as payrollQuery, toObjectId, isValidObjectId } from './utils/query-builders.js';\nimport type { SecureEmployeeLookupOptions } from './utils/employee-lookup.js';\nimport { getPayPeriod, addMonths, addDays } from './utils/date.js';\nimport { calculateGross, calculateNet, sumAllowances, sumDeductions, applyTaxBrackets } from './utils/calculation.js';\nimport { roundMoney } from './utils/money.js';\nimport { getLogger, setLogger } from './utils/logger.js';\nimport { NotInitializedError, EmployeeNotFoundError, DuplicatePayrollError, NotEligibleError, EmployeeTerminatedError, ValidationError, SecurityError, PayrollError } 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';\nimport { Repository } from '@classytic/mongokit';\nimport { multiTenantPlugin } from './core/repository-plugins.js';\nimport type { PayrollRepositories } from './types.js';\nimport { RepositoryManager, createRepositoryManager, SalaryProcessingManager, createSalaryProcessingManager, BulkOperationsManager, createBulkOperationsManager, EmployeeOperationsManager, createEmployeeOperationsManager, CompensationManager, createCompensationManager, PayrollHistoryManager, createPayrollHistoryManager, PayrollStateManager, createPayrollStateManager } from './managers/index.js';\nimport { hasPluginMethod, assertPluginMethod } from './utils/validation.js';\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 private _container: Container<TEmployee, TPayrollRecord, TTransaction, TAttendance>;\n private _events: EventBus;\n private _plugins: PluginManager | null = null;\n private _initialized = false;\n\n // Repository and service layers are now created per-request with proper organizationId scoping\n // No caching to ensure multi-tenant security at query level\n private repositoryManager!: RepositoryManager<TEmployee, TPayrollRecord, TTransaction>;\n private salaryProcessingManager!: SalaryProcessingManager<TEmployee, TPayrollRecord, TTransaction, TAttendance>;\n private bulkOperationsManager!: BulkOperationsManager<TEmployee, TPayrollRecord, TTransaction, TAttendance>;\n private employeeOperationsManager!: EmployeeOperationsManager<TEmployee, TPayrollRecord, TTransaction>;\n private compensationManager!: CompensationManager<TEmployee, TPayrollRecord, TTransaction>;\n private payrollHistoryManager!: PayrollHistoryManager<TEmployee, TPayrollRecord, TTransaction>;\n private payrollStateManager!: PayrollStateManager<TPayrollRecord, TTransaction>;\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 LeaveRequestModel: config.LeaveRequestModel ?? null,\n TaxWithholdingModel: config.TaxWithholdingModel ?? null,\n },\n config: customConfig as Partial<HRMConfig>,\n singleTenant: singleTenant ?? null,\n logger: customLogger,\n });\n\n // Generic bridge: Container's attendance type param doesn't affect manager behavior\n const containerBase = this._container as unknown as Container<TEmployee, TPayrollRecord, TTransaction, AnyDocument>;\n\n // Initialize repository manager\n this.repositoryManager = createRepositoryManager<TEmployee, TPayrollRecord, TTransaction>(\n {\n EmployeeModel,\n PayrollRecordModel,\n TransactionModel,\n LeaveRequestModel: config.LeaveRequestModel ?? null,\n TaxWithholdingModel: config.TaxWithholdingModel ?? null,\n },\n containerBase\n ) as RepositoryManager<TEmployee, TPayrollRecord, TTransaction>;\n\n // Initialize salary processing manager\n this.salaryProcessingManager = createSalaryProcessingManager<TEmployee, TPayrollRecord, TTransaction, TAttendance>(\n {\n EmployeeModel,\n PayrollRecordModel,\n TransactionModel,\n AttendanceModel: AttendanceModel ?? null,\n LeaveRequestModel: (config.LeaveRequestModel as Model<LeaveRequestDocument> | null | undefined) ?? null,\n TaxWithholdingModel: (config.TaxWithholdingModel as unknown as TaxWithholdingModel | null) ?? null,\n },\n this._container,\n this._events,\n this._idempotency,\n this.repositoryManager as unknown as RepositoryManager<TEmployee, TPayrollRecord, TTransaction>,\n this.calculateSalaryBreakdown.bind(this),\n this.resolveOrganizationId.bind(this),\n this.resolveEmployeeId.bind(this),\n this.findEmployee.bind(this),\n this.updatePayrollStats.bind(this),\n this.config\n );\n\n // Initialize bulk operations manager\n this.bulkOperationsManager = createBulkOperationsManager<TEmployee, TPayrollRecord, TTransaction, TAttendance>(\n {\n EmployeeModel,\n PayrollRecordModel,\n TransactionModel,\n AttendanceModel: AttendanceModel ?? null,\n },\n this._events,\n this.processSalary.bind(this),\n this.resolveOrganizationId.bind(this)\n );\n\n // Initialize employee operations manager\n this.employeeOperationsManager = createEmployeeOperationsManager<TEmployee, TPayrollRecord, TTransaction>(\n this._events,\n this.config,\n this.resolveOrganizationId.bind(this),\n this.findEmployee.bind(this),\n (orgId) => this.repositoryManager.getReposForRequest(orgId) as PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>,\n (repos) => {\n return this.getServicesForRequest(repos);\n }\n );\n\n // Initialize compensation manager\n this.compensationManager = createCompensationManager<TEmployee, TPayrollRecord, TTransaction>(\n this._events,\n this.resolveOrganizationId.bind(this),\n this.resolveEmployeeId.bind(this),\n this.findEmployee.bind(this),\n (orgId) => this.repositoryManager.getReposForRequest(orgId) as PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>,\n (repos) => {\n return this.getServicesForRequest(repos);\n }\n );\n\n // Initialize payroll history manager\n this.payrollHistoryManager = createPayrollHistoryManager<TEmployee, TPayrollRecord, TTransaction>(\n {\n EmployeeModel,\n PayrollRecordModel,\n TransactionModel,\n },\n this._events,\n this.resolveOrganizationId.bind(this),\n this.findEmployee.bind(this)\n );\n\n // Initialize payroll state manager\n this.payrollStateManager = createPayrollStateManager<TPayrollRecord, TTransaction>(\n {\n PayrollRecordModel,\n TransactionModel,\n TaxWithholdingModel: config.TaxWithholdingModel ?? null,\n },\n this._events\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 this.findEmployee({\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 this.findEmployee({\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 * Create request-scoped services with proper organizationId filtering.\n *\n * SECURITY: Services are created from request-scoped repositories to ensure\n * multi-tenant isolation at the query level.\n *\n * @param repos - Request-scoped repositories\n */\n private getServicesForRequest(\n repos: PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>\n ): {\n employee: EmployeeService<TEmployee>;\n payroll: PayrollService<TPayrollRecord, TEmployee>;\n compensation: CompensationService<TEmployee>;\n } {\n const employeeService = createEmployeeService(repos.employee, this.config);\n const payrollService = createPayrollService(repos.payrollRecord, employeeService);\n const compensationService = createCompensationService(repos.employee);\n\n return {\n employee: employeeService,\n payroll: payrollService,\n compensation: compensationService,\n };\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 * Create request-scoped repositories with proper organizationId filtering.\n *\n * SECURITY: This ensures multi-tenant isolation at the query level by creating\n * repositories with the request-specific organizationId injected into plugins.\n *\n * @param organizationId - Required in multi-tenant mode, optional in single-tenant\n */\n private getReposForRequest(\n organizationId: ObjectId\n ): PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction> {\n return this.repositoryManager.getReposForRequest(organizationId) as PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>;\n }\n\n /**\n * Resolve organizationId for the current operation.\n *\n * SECURITY:\n * - Multi-tenant mode: organizationId MUST be provided in params\n * - Single-tenant with autoInject=true (default): Uses container organizationId\n * - Single-tenant with autoInject=false: organizationId MUST be provided in params\n *\n * @param providedOrgId - OrganizationId from operation parameters\n * @returns Resolved ObjectId\n * @throws SecurityError if organizationId is missing when required\n */\n private resolveOrganizationId(providedOrgId?: ObjectIdLike): ObjectId {\n const singleTenantConfig = this.container.getSingleTenantConfig();\n const containerOrgId = this.container.getOrganizationId();\n // FIX: Check if single-tenant MODE is enabled (config exists), not just if orgId exists\n const isSingleTenant = !!singleTenantConfig;\n\n // Single-tenant mode with auto-inject enabled (default: true)\n if (isSingleTenant && singleTenantConfig?.autoInject !== false) {\n // Prefer provided orgId if given\n if (providedOrgId) {\n return toObjectId(providedOrgId);\n }\n // Use container's organizationId if available\n if (containerOrgId) {\n return toObjectId(containerOrgId);\n }\n // Single-tenant with autoInject but no organizationId configured\n throw new SecurityError(\n 'Single-tenant mode with autoInject enabled requires organizationId in configuration. ' +\n 'Either provide organizationId in forSingleTenant({ organizationId: ... }) or pass it explicitly in each operation.'\n );\n }\n\n // Single-tenant with autoInject=false OR multi-tenant: require explicit orgId\n if (!providedOrgId) {\n if (isSingleTenant && singleTenantConfig?.autoInject === false) {\n throw new SecurityError(\n 'organizationId is required when autoInject is disabled in single-tenant mode'\n );\n } else {\n throw new SecurityError(\n 'organizationId is required in multi-tenant mode for security'\n );\n }\n }\n\n return toObjectId(providedOrgId);\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 * Find employee securely with organizational isolation at query level.\n *\n * SECURITY: Creates request-scoped repositories with organizationId injected into\n * query filters, ensuring multi-tenant isolation at the database level.\n *\n * In multi-tenant mode, organizationId MUST be provided in options.\n * In single-tenant mode, organizationId is retrieved from container.\n */\n private async findEmployee(options: SecureEmployeeLookupOptions): Promise<TEmployee> {\n const session = options.session;\n const populate = !!options.populate;\n\n // Resolve organizationId (throws SecurityError if missing in multi-tenant mode)\n const organizationId = this.resolveOrganizationId(options.organizationId);\n\n // Create request-scoped repositories and services with proper organizationId filtering\n const repos = this.getReposForRequest(organizationId);\n const services = this.getServicesForRequest(repos);\n\n // Find employee using priority order\n let employee: EmployeeDocument | null = null;\n\n // Priority 1: _id (MongoDB ObjectId)\n if (options._id) {\n employee = await services.employee.findById(options._id, { session, populate });\n if (!employee) {\n throw new EmployeeNotFoundError(`Employee not found: ${options._id}`);\n }\n }\n // Priority 2: employeeId (with mode handling for disambiguation)\n else if (options.employeeId !== undefined) {\n const mode = options.employeeIdMode || 'auto';\n const id = options.employeeId;\n\n // If mode is 'businessId', always use findByEmployeeId\n if (mode === 'businessId') {\n employee = await services.employee.findByEmployeeId(String(id), { session });\n if (!employee) {\n throw new EmployeeNotFoundError(`Employee not found: ${id}`);\n }\n }\n // If mode is 'objectId', use findById\n else if (mode === 'objectId') {\n employee = await services.employee.findById(id as ObjectIdLike, { session, populate });\n if (!employee) {\n throw new EmployeeNotFoundError(`Employee not found: ${id}`);\n }\n }\n // Auto mode: detect type by checking if valid ObjectId\n else if (isValidObjectId(id)) {\n employee = await services.employee.findById(id as ObjectIdLike, { session, populate });\n if (!employee) {\n throw new EmployeeNotFoundError(`Employee not found: ${id}`);\n }\n } else {\n employee = await services.employee.findByEmployeeId(String(id), { session });\n if (!employee) {\n throw new EmployeeNotFoundError(`Employee not found: ${id}`);\n }\n }\n }\n // Priority 3: userId\n else if (options.userId) {\n employee = await services.employee.findByUserId(options.userId, { session });\n if (!employee) {\n throw new EmployeeNotFoundError(`Employee not found for user: ${options.userId}`);\n }\n }\n // Priority 4: email\n else if (options.email) {\n employee = await services.employee.findByEmail(options.email, { session });\n if (!employee) {\n throw new EmployeeNotFoundError(`Employee not found: ${options.email}`);\n }\n }\n // No lookup criteria provided\n else {\n throw new ValidationError('Must provide _id, employeeId, userId, or email');\n }\n\n // No post-fetch validation needed - query-level filtering ensures organizational isolation\n return employee as TEmployee;\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 return this.employeeOperationsManager.hire(params);\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 return this.employeeOperationsManager.updateEmployment(params);\n }\n\n /**\n * Terminate employee\n */\n async terminate(params: TerminateEmployeeParams): Promise<TEmployee> {\n this.ensureInitialized();\n return this.employeeOperationsManager.terminate(params);\n }\n\n /**\n * Re-hire terminated employee\n */\n async reHire(params: ReHireEmployeeParams): Promise<TEmployee> {\n this.ensureInitialized();\n return this.employeeOperationsManager.reHire(params);\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 return this.employeeOperationsManager.getEmployee(params);\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 // Use consistent organization resolution (handles single-tenant with autoInject)\n const orgId = this.resolveOrganizationId(params.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 // Only swallow EmployeeNotFoundError - propagate operational errors (DB failures, timeouts)\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: params.organizationId, // Pass original param for re-resolution\n mode: tryMode,\n populateUser,\n session\n });\n } catch (modeError) {\n // Only suppress \"not found\" errors - propagate real operational failures\n if (modeError instanceof EmployeeNotFoundError) {\n continue; // Expected: employee not found with this mode, try next\n }\n throw modeError; // DB connection, timeout, or other operational error\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 // Compensation Management\n // ========================================\n\n /**\n * Update employee salary\n */\n async updateSalary(params: UpdateSalaryParams): Promise<TEmployee> {\n this.ensureInitialized();\n return this.compensationManager.updateSalary(params);\n }\n\n /**\n * Add allowance to employee\n */\n async addAllowance(params: AddAllowanceParams): Promise<TEmployee> {\n this.ensureInitialized();\n return this.compensationManager.addAllowance(params);\n }\n\n /**\n * Remove allowance from employee\n */\n async removeAllowance(params: RemoveAllowanceParams): Promise<TEmployee> {\n this.ensureInitialized();\n return this.compensationManager.removeAllowance(params);\n }\n\n /**\n * Add deduction to employee\n */\n async addDeduction(params: AddDeductionParams): Promise<TEmployee> {\n this.ensureInitialized();\n return this.compensationManager.addDeduction(params);\n }\n\n /**\n * Remove deduction from employee\n */\n async removeDeduction(params: RemoveDeductionParams): Promise<TEmployee> {\n this.ensureInitialized();\n return this.compensationManager.removeDeduction(params);\n }\n\n /**\n * Update bank details\n */\n async updateBankDetails(params: UpdateBankDetailsParams): Promise<TEmployee> {\n this.ensureInitialized();\n return this.compensationManager.updateBankDetails(params);\n }\n\n // ========================================\n // Payroll Processing\n // ========================================\n\n /**\n * Process salary for single employee\n *\n * ATOMICITY GUARANTEE:\n * This method ALWAYS ensures atomic operations. All database writes\n * (PayrollRecord, Transaction, Employee stats) either all succeed or all fail.\n *\n * Transaction Handling:\n * - No session provided: Creates session and starts transaction\n * - Session provided WITHOUT transaction: Starts transaction on that session\n * - Session provided WITH transaction: Uses existing transaction\n *\n * This means atomicity is enforced automatically - callers cannot\n * accidentally cause partial writes by providing session without transaction.\n *\n * @example\n * // Simple usage - transaction handled automatically\n * await payroll.processSalary({ employeeId, organizationId, month, year });\n *\n * @example\n * // Use existing session (transaction started automatically if needed)\n * const session = await mongoose.startSession();\n * await payroll.processSalary({\n * employeeId,\n * organizationId,\n * month,\n * year,\n * context: { session }\n * });\n *\n * @example\n * // Nested in caller's transaction (uses existing transaction)\n * await session.withTransaction(async () => {\n * await payroll.processSalary({\n * employeeId,\n * organizationId,\n * month,\n * year,\n * context: { session }\n * });\n * // Other operations...\n * });\n */\n async processSalary(\n params: ProcessSalaryParams\n ): Promise<ProcessSalaryResult<TEmployee, TPayrollRecord, TTransaction>> {\n this.ensureInitialized();\n return this.salaryProcessingManager.processSalary(params);\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 return this.bulkOperationsManager.processBulkPayroll(params);\n }\n\n /**\n * Get payroll history\n */\n async payrollHistory(params: PayrollHistoryParams): Promise<TPayrollRecord[]> {\n this.ensureInitialized();\n return this.payrollHistoryManager.payrollHistory(params);\n }\n\n /**\n * Get payroll summary\n */\n async payrollSummary(params: PayrollSummaryParams): Promise<PayrollSummaryResult> {\n this.ensureInitialized();\n return this.payrollHistoryManager.payrollSummary(params);\n }\n\n // ========================================\n // Void / Reversal Methods (v2.4.0+)\n // ========================================\n\n /**\n * Void a payroll record (before payment)\n *\n * Use for payrolls that haven't been paid yet (pending, processing, failed).\n * Creates audit trail but doesn't create a reversal transaction.\n *\n * @example\n * ```typescript\n * await payroll.voidPayroll({\n * organizationId: org._id,\n * payrollRecordId: record._id,\n * reason: 'Test payroll - not intended for production',\n * context: { userId: admin._id },\n * });\n * ```\n */\n async voidPayroll(params: VoidPayrollParams): Promise<VoidPayrollResult> {\n this.ensureInitialized();\n const result = await this.payrollStateManager.voidPayroll(params);\n\n // Clear idempotency cache to allow re-processing if needed\n // (voided payrolls block re-processing, but cache should be cleared for consistency)\n // IMPORTANT: Must include payrollRunType and period.startDate for non-monthly frequencies\n const { employeeId, period, organizationId, payrollRunType = 'regular', paymentFrequency = 'monthly' } = result.payrollRecord;\n\n // For non-monthly frequencies, include period.startDate in idempotency key\n // Use stored paymentFrequency (not date heuristics) for reliable detection\n const isNonMonthly = paymentFrequency !== 'monthly';\n const idempotencyKey = generatePayrollIdempotencyKey(\n organizationId,\n employeeId,\n period.month,\n period.year,\n payrollRunType as import('./core/idempotency.js').PayrollRunType,\n isNonMonthly ? period.startDate : undefined\n );\n this._idempotency.delete(idempotencyKey);\n\n return result;\n }\n\n /**\n * Reverse a paid payroll\n *\n * Creates a reversal (negative) transaction to offset the original payment.\n * Required for compliance as it maintains a full audit trail.\n *\n * @example\n * ```typescript\n * const result = await payroll.reversePayroll({\n * organizationId: org._id,\n * payrollRecordId: record._id,\n * reason: 'Duplicate payment - reversing',\n * createReversalTransaction: true,\n * });\n * ```\n */\n async reversePayroll(params: ReversePayrollParams): Promise<ReversePayrollResult> {\n this.ensureInitialized();\n const result = await this.payrollStateManager.reversePayroll(params);\n\n // Clear idempotency cache to allow re-processing after reversal\n // Reversed payrolls should allow creating a new record for the same period\n // IMPORTANT: Must include payrollRunType and period.startDate for non-monthly frequencies\n const { employeeId, period, organizationId, payrollRunType = 'regular', paymentFrequency = 'monthly' } = result.payrollRecord;\n\n // For non-monthly frequencies, include period.startDate in idempotency key\n // Use stored paymentFrequency (not date heuristics) for reliable detection\n const isNonMonthly = paymentFrequency !== 'monthly';\n const idempotencyKey = generatePayrollIdempotencyKey(\n organizationId,\n employeeId,\n period.month,\n period.year,\n payrollRunType as import('./core/idempotency.js').PayrollRunType,\n isNonMonthly ? period.startDate : undefined\n );\n this._idempotency.delete(idempotencyKey);\n\n return result;\n }\n\n /**\n * Restore a voided payroll\n *\n * Only works for voided payrolls (not reversed ones, as they have financial transactions).\n *\n * @example\n * ```typescript\n * await payroll.restorePayroll({\n * organizationId: org._id,\n * payrollRecordId: record._id,\n * reason: 'Voided in error, restoring',\n * });\n * ```\n */\n async restorePayroll(params: RestorePayrollParams): Promise<RestorePayrollResult> {\n this.ensureInitialized();\n return this.payrollStateManager.restorePayroll(params);\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 as unknown as 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 as unknown as 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?: AnyDocument;\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 as unknown as TaxWithholdingModel,\n this.models.TransactionModel as AnyModel,\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 // Priority: 1. Explicit attendance (passed in) → 2. Auto-fetch from DB → 3. Full attendance (no deduction)\n if (!options.skipAttendance && this.config.payroll.attendanceIntegration && !attendanceData && this.models.AttendanceModel) {\n try {\n // Auto-fetch attendance from database\n let query = this.models.AttendanceModel.findOne({\n organizationId: 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 // Don't set expectedDays - let calculator derive from workSchedule/proRating\n actualDays: workedDays,\n };\n getLogger().debug('Auto-fetched attendance from DB', {\n employeeId: employee._id.toString(),\n workedDays,\n month: period.month,\n year: period.year,\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 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 private async updatePayrollStats(\n employee: EmployeeDocument,\n amount: number,\n paymentDate: Date,\n repos: PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>,\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 = roundMoney(\n employee.payrollStats.totalPaid / employee.payrollStats.paymentsThisYear, 2\n );\n\n // Calculate next payment date based on payment frequency\n const frequency = employee.compensation?.frequency || 'monthly';\n switch (frequency) {\n case 'hourly':\n case 'daily':\n // Daily/hourly workers typically get paid daily\n employee.payrollStats.nextPaymentDate = addDays(paymentDate, 1);\n break;\n case 'weekly':\n employee.payrollStats.nextPaymentDate = addDays(paymentDate, 7);\n break;\n case 'bi_weekly':\n employee.payrollStats.nextPaymentDate = addDays(paymentDate, 14);\n break;\n case 'monthly':\n default:\n employee.payrollStats.nextPaymentDate = addMonths(paymentDate, 1);\n break;\n }\n\n // Use repository update instead of document.save()\n await repos.employee.update(\n employee._id,\n { payrollStats: employee.payrollStats },\n { session }\n );\n }\n\n // ========================================\n // Crash Recovery Methods (v2.8.0+)\n // ========================================\n\n /**\n * Recover stuck payroll records\n *\n * Finds payroll records stuck in 'processing' or 'pending' status for longer\n * than the threshold and handles them appropriately:\n * - Records WITHOUT transactionId: Marked as 'failed' (safe to retry)\n * - Records WITH transactionId: Flagged for manual review (orphaned transaction)\n *\n * This helps recover from server crashes or partial failures.\n *\n * @example\n * ```typescript\n * const recovered = await payroll.recoverStuckPayrolls({\n * organizationId: org._id,\n * staleThresholdMinutes: 30,\n * });\n * console.log(`Recovered ${recovered.markedFailed} records`);\n * if (recovered.requiresManualReview.length > 0) {\n * console.warn('Manual review needed:', recovered.requiresManualReview);\n * }\n * ```\n */\n async recoverStuckPayrolls(params: {\n organizationId: ObjectIdLike;\n staleThresholdMinutes?: number;\n dryRun?: boolean;\n }): Promise<{\n markedFailed: number;\n requiresManualReview: Array<{ _id: ObjectId; status: string; transactionId?: ObjectId }>;\n scanned: number;\n }> {\n this.ensureInitialized();\n\n const orgId = this.resolveOrganizationId(params.organizationId);\n const threshold = params.staleThresholdMinutes ?? 30;\n const cutoffTime = new Date(Date.now() - threshold * 60 * 1000);\n const dryRun = params.dryRun ?? false;\n\n // Find stuck records\n const stuckRecords = await this.models.PayrollRecordModel.find({\n organizationId: orgId,\n status: { $in: ['processing', 'pending'] },\n processedAt: { $lt: cutoffTime },\n });\n\n const result = {\n markedFailed: 0,\n requiresManualReview: [] as Array<{ _id: ObjectId; status: string; transactionId?: ObjectId }>,\n scanned: stuckRecords.length,\n };\n\n for (const record of stuckRecords) {\n if (record.transactionId) {\n // Has transaction - needs manual review (don't auto-mark to prevent orphaning)\n result.requiresManualReview.push({\n _id: record._id,\n status: record.status,\n transactionId: record.transactionId,\n });\n getLogger().warn('Stuck payroll record with transaction needs manual review', {\n payrollRecordId: record._id.toString(),\n status: record.status,\n transactionId: record.transactionId.toString(),\n processedAt: record.processedAt,\n });\n } else {\n // No transaction - safe to mark as failed\n if (!dryRun) {\n await this.models.PayrollRecordModel.updateOne(\n { _id: record._id },\n { $set: { status: 'failed' } }\n );\n }\n result.markedFailed++;\n getLogger().info('Marked stuck payroll record as failed', {\n payrollRecordId: record._id.toString(),\n status: record.status,\n processedAt: record.processedAt,\n dryRun,\n });\n }\n }\n\n getLogger().info('Crash recovery completed', {\n organizationId: orgId.toString(),\n scanned: result.scanned,\n markedFailed: result.markedFailed,\n requiresManualReview: result.requiresManualReview.length,\n dryRun,\n });\n\n return result;\n }\n\n // ========================================\n // Two-Phase Export Methods (v2.8.0+)\n // ========================================\n\n /**\n * Prepare payroll data for export (Phase 1)\n *\n * Retrieves records but does NOT mark them as exported yet.\n * Returns an exportId that must be used to confirm or cancel the export.\n *\n * @example\n * ```typescript\n * // Phase 1: Prepare\n * const { records, exportId } = await payroll.prepareExport({\n * organizationId: org._id,\n * startDate: new Date('2024-01-01'),\n * endDate: new Date('2024-01-31'),\n * });\n *\n * // Send records to external system...\n *\n * // Phase 2: Confirm (if successful) or Cancel (if failed)\n * await payroll.confirmExport({ organizationId: org._id, exportId });\n * ```\n */\n async prepareExport(params: ExportPayrollParams): Promise<{\n records: TPayrollRecord[];\n exportId: string;\n total: number;\n }> {\n this.ensureInitialized();\n\n const orgId = this.resolveOrganizationId(params.organizationId);\n const { startDate, endDate } = params;\n\n const query = {\n organizationId: toObjectId(orgId),\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 // Generate export ID for tracking\n const exportId = `export-${orgId}-${Date.now()}-${Math.random().toString(36).substring(7)}`;\n\n // Store pending export info in idempotency cache (temporary storage)\n this._idempotency.set(`pending-export:${exportId}`, {\n organizationId: orgId.toString(),\n recordIds: records.map(r => r._id.toString()),\n createdAt: new Date(),\n startDate,\n endDate,\n });\n\n getLogger().info('Prepared payroll export', {\n organizationId: orgId.toString(),\n exportId,\n recordCount: records.length,\n dateRange: { start: startDate, end: endDate },\n });\n\n return {\n records: records as unknown as TPayrollRecord[],\n exportId,\n total: records.length,\n };\n }\n\n /**\n * Confirm export success (Phase 2a)\n *\n * Marks records as exported after downstream system confirms receipt.\n */\n async confirmExport(params: {\n organizationId: ObjectIdLike;\n exportId: string;\n }): Promise<{ confirmed: number }> {\n this.ensureInitialized();\n\n const orgId = this.resolveOrganizationId(params.organizationId);\n const { exportId } = params;\n\n // Retrieve pending export info\n const pendingExport = this._idempotency.get<{\n organizationId: string;\n recordIds: string[];\n createdAt: Date;\n }>(`pending-export:${exportId}`);\n\n if (!pendingExport) {\n throw new PayrollError(\n `Export ${exportId} not found or already processed`,\n 'EXPORT_NOT_FOUND',\n 404,\n { exportId }\n );\n }\n\n // Verify organization match\n if (pendingExport.value.organizationId !== orgId.toString()) {\n throw new PayrollError(\n 'Organization mismatch for export confirmation',\n 'EXPORT_ORG_MISMATCH',\n 403,\n { exportId, expectedOrg: pendingExport.value.organizationId }\n );\n }\n\n const recordIds = pendingExport.value.recordIds.map(id => toObjectId(id));\n\n // Mark records as exported\n const result = await this.models.PayrollRecordModel.updateMany(\n { _id: { $in: recordIds }, organizationId: orgId },\n { $set: { exported: true, exportedAt: new Date() } }\n );\n\n // Clear pending export\n this._idempotency.delete(`pending-export:${exportId}`);\n\n // Emit event\n this._events.emitSync('payroll:exported', {\n organizationId: orgId,\n exportId,\n recordCount: result.modifiedCount,\n format: 'json',\n });\n\n getLogger().info('Confirmed payroll export', {\n organizationId: orgId.toString(),\n exportId,\n confirmed: result.modifiedCount,\n });\n\n return { confirmed: result.modifiedCount ?? 0 };\n }\n\n /**\n * Cancel export (Phase 2b)\n *\n * Called when downstream system fails to process the export.\n * Records remain unmarked and can be exported again.\n */\n async cancelExport(params: {\n organizationId: ObjectIdLike;\n exportId: string;\n reason?: string;\n }): Promise<{ cancelled: boolean }> {\n this.ensureInitialized();\n\n const orgId = this.resolveOrganizationId(params.organizationId);\n const { exportId, reason } = params;\n\n // Just clear the pending export - records were never marked\n const pendingExport = this._idempotency.get(`pending-export:${exportId}`);\n\n if (!pendingExport) {\n getLogger().warn('Export cancellation for unknown export', { exportId });\n return { cancelled: false };\n }\n\n this._idempotency.delete(`pending-export:${exportId}`);\n\n getLogger().info('Cancelled payroll export', {\n organizationId: orgId.toString(),\n exportId,\n reason,\n });\n\n return { cancelled: true };\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 LeaveRequestModel: this._models.LeaveRequestModel,\n TaxWithholdingModel: this._models.TaxWithholdingModel,\n config: this._config,\n singleTenant: this._singleTenant,\n logger: this._logger,\n } as PayrollInitConfig<TEmployee, TPayrollRecord, TTransaction, TAttendance>);\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 Service (Refactored with Mongokit)\n *\n * High-level employee operations using Repository pattern\n *\n * ⚠️ **INTERNAL USE ONLY**\n *\n * This service is for internal use by the Payroll class only.\n * All methods use repository pattern with automatic multi-tenant isolation.\n *\n * **Key Changes from v1:**\n * - Uses Repository instead of direct Model access\n * - Multi-tenant isolation handled by plugin (organizationId auto-injected)\n * - Cleaner transaction handling via repo.withTransaction()\n * - No need to pass organizationId to most methods (plugin handles it)\n *\n * @internal\n */\n\nimport type { Repository } from '@classytic/mongokit';\nimport type { 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 (Mongokit Refactored)\n// ============================================================================\n\nexport class EmployeeService<T extends EmployeeDocument = EmployeeDocument> {\n private readonly config: HRMConfig;\n\n constructor(\n private readonly employeeRepo: Repository<T>,\n config?: HRMConfig\n ) {\n this.config = config || HRM_CONFIG;\n }\n\n /**\n * Find employee by ID\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n *\n * @throws {Error} If employee not found\n */\n async findById(\n employeeId: ObjectIdLike,\n options: { session?: ClientSession; populate?: boolean } = {}\n ): Promise<EmployeeDocument | null> {\n // Use getAll to ensure organizationId filtering works at query level\n // (getById after hooks don't properly override return values in mongokit)\n const result = await this.employeeRepo.getAll(\n {\n filters: { _id: toObjectId(employeeId) },\n limit: 1,\n },\n {\n session: options.session,\n populate: options.populate ? (['userId'] as any) : undefined,\n }\n );\n\n return result.docs[0] || null;\n }\n\n /**\n * Find employee by user ID\n */\n async findByUserId(\n userId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument | null> {\n // organizationId automatically added by multiTenantPlugin\n return this.employeeRepo.getByQuery(\n { userId: toObjectId(userId) },\n { session: options.session }\n );\n }\n\n /**\n * Find employee by employeeId (human-readable ID)\n */\n async findByEmployeeId(\n employeeId: string,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument | null> {\n // organizationId automatically added by multiTenantPlugin\n return this.employeeRepo.getByQuery(\n { employeeId },\n { session: options.session, throwOnNotFound: false }\n );\n }\n\n /**\n * Find employee by email (guest employees)\n */\n async findByEmail(\n email: string,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument | null> {\n // organizationId automatically added by multiTenantPlugin\n // Normalize email (lowercase + trim) to match schema storage format\n return this.employeeRepo.getByQuery(\n { email: email.toLowerCase().trim() },\n { session: options.session }\n );\n }\n\n /**\n * Find all guest employees (no userId or userId: null)\n * Note: MongoDB's {field: null} query matches BOTH documents where field is null\n * AND documents where field doesn't exist, providing consistent behavior with query builder.\n */\n async findGuestEmployees(\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument[]> {\n // organizationId automatically added by multiTenantPlugin\n const result = await this.employeeRepo.getAll(\n { filters: { userId: null } },\n { session: options.session }\n );\n\n return result.docs;\n }\n\n /**\n * Find active employees with pagination support\n *\n * @param options - Query options including pagination\n * @returns Paginated result with employees and metadata\n *\n * @example\n * ```typescript\n * // Get first page (100 employees)\n * const result = await employeeService.findActive({ page: 1, limit: 100 });\n * console.log(result.docs); // Array of employees\n * console.log(result.total); // Total count\n *\n * // Get all (use with caution for large datasets)\n * const all = await employeeService.findActive({ limit: 0 }); // limit: 0 = no limit\n * ```\n */\n async findActive(\n options: {\n page?: number;\n limit?: number;\n session?: ClientSession;\n select?: string;\n sort?: string;\n } = {}\n ): Promise<import('../types.js').OffsetPaginationResult<EmployeeDocument> | import('../types.js').KeysetPaginationResult<EmployeeDocument>> {\n // organizationId automatically added by multiTenantPlugin\n const { page = 1, limit = 100, session, select, sort = '-createdAt' } = options;\n\n return this.employeeRepo.getAll(\n {\n filters: { status: 'active' },\n page,\n limit,\n sort\n },\n { session, select }\n );\n }\n\n /**\n * Find employed employees (not terminated) with pagination support\n *\n * @param options - Query options including pagination\n * @returns Paginated result with employees and metadata\n *\n * @example\n * ```typescript\n * // Get first 50 employed employees\n * const result = await employeeService.findEmployed({ limit: 50 });\n * ```\n */\n async findEmployed(\n options: {\n page?: number;\n limit?: number;\n session?: ClientSession;\n select?: string;\n sort?: string;\n } = {}\n ): Promise<import('../types.js').OffsetPaginationResult<EmployeeDocument> | import('../types.js').KeysetPaginationResult<EmployeeDocument>> {\n // organizationId automatically added by multiTenantPlugin\n const { page = 1, limit = 100, session, select, sort = '-createdAt' } = options;\n\n return this.employeeRepo.getAll(\n {\n filters: { status: { $ne: 'terminated' } },\n page,\n limit,\n sort\n },\n { session, select }\n );\n }\n\n /**\n * Find employees by department with pagination support\n *\n * @param department - Department to filter by\n * @param options - Query options including pagination\n * @returns Paginated result with employees and metadata\n *\n * @example\n * ```typescript\n * // Get first page of engineering employees\n * const result = await employeeService.findByDepartment('engineering', { page: 1, limit: 50 });\n * ```\n */\n async findByDepartment(\n department: Department,\n options: {\n page?: number;\n limit?: number;\n session?: ClientSession;\n select?: string;\n sort?: string;\n } = {}\n ): Promise<import('../types.js').OffsetPaginationResult<EmployeeDocument> | import('../types.js').KeysetPaginationResult<EmployeeDocument>> {\n // organizationId automatically added by multiTenantPlugin\n const { page = 1, limit = 100, session, select, sort = '-createdAt' } = options;\n\n return this.employeeRepo.getAll(\n {\n filters: { department, status: 'active' },\n page,\n limit,\n sort\n },\n { session, select }\n );\n }\n\n /**\n * Find employees eligible for payroll with pagination support\n *\n * ⚠️ Note: This method applies in-memory filtering after database query.\n * The pagination counts may not match perfectly due to post-filtering.\n * Consider using higher limits to account for filtered-out records.\n *\n * @param options - Query options including pagination\n * @returns Paginated result with eligible employees\n *\n * @example\n * ```typescript\n * // Get eligible employees (paginated)\n * const result = await employeeService.findEligibleForPayroll({ page: 1, limit: 100 });\n * ```\n */\n async findEligibleForPayroll(\n options: {\n page?: number;\n limit?: number;\n session?: ClientSession;\n select?: string;\n sort?: string;\n } = {}\n ): Promise<import('../types.js').OffsetPaginationResult<EmployeeDocument> | import('../types.js').KeysetPaginationResult<EmployeeDocument>> {\n // organizationId automatically added by multiTenantPlugin\n const { page = 1, limit = 100, session, select, sort = '-createdAt' } = options;\n\n const result = await this.employeeRepo.getAll(\n {\n filters: { status: { $ne: 'terminated' } },\n page,\n limit,\n sort\n },\n { session, select }\n );\n\n // Apply eligibility filter in-memory on docs\n const eligibleDocs = result.docs.filter((emp: EmployeeDocument) => canReceiveSalary(emp));\n\n // Return mongokit's standard structure with filtered docs\n return {\n ...result,\n docs: eligibleDocs,\n total: eligibleDocs.length, // Filtered count\n } as typeof result;\n }\n\n /**\n * Create new employee\n *\n * organizationId auto-injected by multiTenantPlugin\n */\n async create(\n params: CreateEmployeeParams,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument> {\n const employeeData = EmployeeFactory.create(params, this.config);\n\n // For guest employees, need special handling to preserve partial index\n if (!params.userId) {\n // Guest employee - prepare data for insertion\n const dataToInsert: Record<string, unknown> = {};\n\n // Copy all fields except userId/email\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\n if (employeeData.email && employeeData.email !== '') {\n dataToInsert.email = employeeData.email;\n }\n\n // Note: organizationId will be auto-injected by multiTenantPlugin\n return this.employeeRepo.create(dataToInsert, { session: options.session });\n }\n\n // Regular employee with userId\n return this.employeeRepo.create(employeeData as Partial<EmployeeDocument>, {\n session: options.session,\n });\n }\n\n /**\n * Update employee status\n */\n async updateStatus(\n employeeId: ObjectIdLike,\n status: EmployeeStatus,\n options: { session?: ClientSession; context?: OperationContext } = {}\n ): Promise<EmployeeDocument> {\n // Fetch first to ensure cross-org updates are blocked\n const existing = await this.findById(employeeId, options);\n if (!existing) {\n throw new Error(`Employee not found: ${employeeId}`);\n }\n\n const employee = await this.employeeRepo.update(\n employeeId,\n { status },\n { session: options.session }\n );\n\n logger.info('Employee status updated', {\n employeeId: employee.employeeId,\n organizationId: employee.organizationId?.toString(),\n newStatus: status,\n });\n\n return employee;\n }\n\n /**\n * Update employee compensation\n */\n async updateCompensation(\n employeeId: ObjectIdLike,\n compensation: Compensation,\n options: { session?: ClientSession; context?: OperationContext } = {}\n ): Promise<EmployeeDocument> {\n // Fetch first to ensure cross-org updates are blocked\n const existing = await this.findById(employeeId, options);\n if (!existing) {\n throw new Error(`Employee not found: ${employeeId}`);\n }\n\n const employee = await this.employeeRepo.update(\n employeeId,\n { compensation },\n { session: options.session }\n );\n\n logger.info('Employee compensation updated', {\n employeeId: employee.employeeId,\n organizationId: employee.organizationId?.toString(),\n });\n\n return employee;\n }\n\n /**\n * Terminate employee\n */\n async terminate(\n employeeId: ObjectIdLike,\n terminationDate: Date,\n options: { session?: ClientSession; reason?: string; context?: OperationContext } = {}\n ): Promise<EmployeeDocument> {\n // Fetch first to ensure cross-org updates are blocked\n const existing = await this.findById(employeeId, options);\n if (!existing) {\n throw new Error(`Employee not found: ${employeeId}`);\n }\n\n const updateData: Record<string, unknown> = {\n status: 'terminated',\n terminatedAt: terminationDate,\n };\n\n if (options.reason) {\n updateData.terminationReason = options.reason;\n }\n\n const employee = await this.employeeRepo.update(employeeId, updateData, {\n session: options.session,\n });\n\n logger.info('Employee terminated', {\n employeeId: employee.employeeId,\n terminationDate: terminationDate.toISOString(),\n });\n\n return employee;\n }\n\n /**\n * Re-hire employee\n */\n async reHire(\n employeeId: ObjectIdLike,\n options: { session?: ClientSession; context?: OperationContext } = {}\n ): Promise<EmployeeDocument> {\n // Fetch first to ensure cross-org updates are blocked\n const existing = await this.findById(employeeId, options);\n if (!existing) {\n throw new Error(`Employee not found: ${employeeId}`);\n }\n\n const employee = await this.employeeRepo.update(\n employeeId,\n {\n status: 'active',\n terminatedAt: null,\n terminationReason: null,\n },\n { session: options.session }\n );\n\n logger.info('Employee re-hired', {\n employeeId: employee.employeeId,\n });\n\n return employee;\n }\n\n /**\n * Check if employee exists\n */\n async exists(employeeId: ObjectIdLike): Promise<boolean> {\n const result = await this.employeeRepo.exists({ _id: toObjectId(employeeId) });\n return result !== null;\n }\n\n /**\n * Count employees\n */\n async count(filters: Record<string, unknown> = {}): Promise<number> {\n // organizationId automatically added by multiTenantPlugin\n return this.employeeRepo.count(filters);\n }\n\n /**\n * Validate employee can receive salary\n */\n validateEligibility(employee: EmployeeDocument): void {\n if (!employee) {\n throw new Error('Employee not found');\n }\n\n if (!isEmployed(employee)) {\n throw new Error(`Employee is terminated and cannot receive salary`);\n }\n\n if (!canReceiveSalary(employee)) {\n throw new Error('Employee is not eligible to receive salary');\n }\n }\n}\n\n/**\n * Factory function to create EmployeeService\n */\nexport function createEmployeeService<T extends EmployeeDocument = EmployeeDocument>(\n employeeRepo: Repository<T>,\n config?: HRMConfig\n): EmployeeService<T> {\n return new EmployeeService<T>(employeeRepo, config);\n}\n\nexport default EmployeeService;\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 { roundMoney } from '../utils/money.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 ? roundMoney((baseAmount * allowance.value) / 100, 2)\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 ? roundMoney((baseAmount * deduction.value) / 100, 2)\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 (Refactored with Mongokit)\n *\n * High-level payroll operations using Repository pattern\n *\n * **Key Changes from v1:**\n * - Uses Repository instead of direct Model access\n * - Multi-tenant isolation handled by plugin (organizationId auto-injected)\n * - Cleaner API (no need to pass organizationId to most methods)\n */\n\nimport type { Repository } from '@classytic/mongokit';\nimport type { 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 (Mongokit Refactored)\n// ============================================================================\n\nexport class PayrollService<\n T extends PayrollRecordDocument = PayrollRecordDocument,\n TEmployee extends EmployeeDocument = EmployeeDocument\n> {\n constructor(\n private readonly payrollRepo: Repository<T>,\n private readonly employeeService: EmployeeService<TEmployee>\n ) {}\n\n /**\n * Find payroll by ID\n *\n * organizationId auto-scoped by multiTenantPlugin\n */\n async findById(\n payrollId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument | null> {\n // Use getAll to ensure organizationId filtering works at query level\n // (getById after hooks don't properly override return values in mongokit)\n const result = await this.payrollRepo.getAll(\n {\n filters: { _id: toObjectId(payrollId) },\n limit: 1,\n },\n { session: options.session }\n );\n\n return result.docs[0] || null;\n }\n\n /**\n * Find payrolls by employee\n */\n async findByEmployee(\n employeeId: ObjectIdLike,\n options: { session?: ClientSession; limit?: number } = {}\n ): Promise<PayrollRecordDocument[]> {\n // organizationId automatically added by multiTenantPlugin\n const result = await this.payrollRepo.getAll(\n {\n filters: { employeeId: toObjectId(employeeId) },\n sort: { 'period.year': -1, 'period.month': -1 },\n limit: options.limit || 12,\n },\n { session: options.session }\n );\n\n return result.docs;\n }\n\n /**\n * Find payrolls for a period\n */\n async findForPeriod(\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument[]> {\n // organizationId automatically added by multiTenantPlugin\n const result = await this.payrollRepo.getAll(\n {\n filters: {\n 'period.month': month,\n 'period.year': year,\n },\n },\n { session: options.session }\n );\n\n return result.docs;\n }\n\n /**\n * Find pending payrolls\n */\n async findPending(\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument[]> {\n // organizationId automatically added by multiTenantPlugin\n const result = await this.payrollRepo.getAll(\n {\n filters: {\n 'period.month': month,\n 'period.year': year,\n status: 'pending',\n },\n },\n { session: options.session }\n );\n\n return result.docs;\n }\n\n /**\n * Find payroll by employee and period\n */\n async findByEmployeeAndPeriod(\n employeeId: ObjectIdLike,\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument | null> {\n // organizationId automatically added by multiTenantPlugin\n return this.payrollRepo.getByQuery(\n {\n employeeId: toObjectId(employeeId),\n 'period.month': month,\n 'period.year': year,\n },\n { session: options.session }\n );\n }\n\n /**\n * Create payroll record\n *\n * organizationId auto-injected by multiTenantPlugin\n */\n async create(\n data: PayrollData,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument> {\n const payroll = await this.payrollRepo.create(data as unknown as Partial<T>, {\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\n *\n * organizationId auto-scoped by multiTenantPlugin\n */\n async generateForEmployee(\n employeeId: ObjectIdLike,\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument> {\n // Employee lookup auto-scoped by multiTenantPlugin\n const employee = await this.employeeService.findById(employeeId, options);\n\n if (!employee) {\n throw new Error(`Employee not found: ${employeeId}`);\n }\n\n if (!canReceiveSalary(employee)) {\n throw new Error('Employee is not eligible to receive salary');\n }\n\n const payrollData = PayrollFactory.create({\n employeeId: employee._id,\n organizationId: employee.organizationId,\n baseAmount: employee.compensation.baseAmount,\n allowances: employee.compensation.allowances,\n deductions: employee.compensation.deductions,\n period: { month, year },\n });\n return this.create(payrollData, options);\n }\n\n /**\n * Generate bulk payroll\n *\n * organizationId auto-scoped by multiTenantPlugin\n */\n async generateBulk(\n employeeIds: ObjectIdLike[],\n month: number,\n year: number,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument[]> {\n const payrolls: PayrollRecordDocument[] = [];\n\n for (const employeeId of employeeIds) {\n try {\n const payroll = await this.generateForEmployee(employeeId, month, year, options);\n payrolls.push(payroll);\n } catch (error) {\n logger.error('Failed to generate payroll for employee', {\n employeeId: employeeId.toString(),\n error: (error as Error).message,\n });\n // Continue with other employees\n }\n }\n\n return payrolls;\n }\n\n /**\n * Mark payroll as paid\n */\n async markAsPaid(\n payrollId: ObjectIdLike,\n transactionIdOrOptions?: ObjectIdLike | { session?: ClientSession; paidAt?: Date },\n options?: { session?: ClientSession; paidAt?: Date }\n ): Promise<PayrollRecordDocument> {\n // Handle both old and new signatures\n let transactionId: ObjectIdLike | undefined;\n let resolvedOptions: { session?: ClientSession; paidAt?: Date } = {};\n\n if (transactionIdOrOptions) {\n // Check if it's an ObjectId or options object\n if (typeof transactionIdOrOptions === 'object' && ('session' in transactionIdOrOptions || 'paidAt' in transactionIdOrOptions)) {\n // Old signature: markAsPaid(payrollId, { session, paidAt })\n resolvedOptions = transactionIdOrOptions;\n transactionId = undefined;\n } else {\n // New signature: markAsPaid(payrollId, transactionId, { session, paidAt })\n transactionId = transactionIdOrOptions as ObjectIdLike;\n resolvedOptions = options || {};\n }\n } else {\n resolvedOptions = options || {};\n }\n\n // Fetch first to ensure cross-org updates are blocked\n const existing = await this.findById(payrollId, resolvedOptions);\n if (!existing) {\n throw new Error(`Payroll not found: ${payrollId}`);\n }\n\n // Validate state transition\n const { PayrollStatusMachine } = await import('../core/payroll-states.js');\n if (!PayrollStatusMachine.canTransition(existing.status, 'paid')) {\n const validNext = PayrollStatusMachine.getNextStates(existing.status);\n throw new Error(\n `Invalid status transition: Cannot transition from ${existing.status} to paid. Valid transitions: ${validNext.join(', ')}`\n );\n }\n\n const updateData: Record<string, unknown> = {\n status: 'paid',\n paidAt: resolvedOptions.paidAt || new Date(),\n };\n\n if (transactionId) {\n updateData.transactionId = toObjectId(transactionId);\n }\n\n const payroll = await this.payrollRepo.update(\n payrollId,\n updateData,\n { session: resolvedOptions.session }\n );\n\n logger.info('Payroll marked as paid', {\n payrollId: payroll._id.toString(),\n });\n\n return payroll;\n }\n\n /**\n * Update payroll status\n */\n async updateStatus(\n payrollId: ObjectIdLike,\n status: PayrollStatus,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument> {\n // Fetch first to ensure cross-org updates are blocked\n const existing = await this.findById(payrollId, options);\n if (!existing) {\n throw new Error(`Payroll not found: ${payrollId}`);\n }\n\n // Validate state transition (allow idempotent same-status updates)\n if (existing.status !== status) {\n const { PayrollStatusMachine } = await import('../core/payroll-states.js');\n if (!PayrollStatusMachine.canTransition(existing.status, status)) {\n const validNext = PayrollStatusMachine.getNextStates(existing.status);\n throw new Error(\n `Invalid status transition: Cannot transition from ${existing.status} to ${status}. Valid transitions: ${validNext.join(', ')}`\n );\n }\n }\n\n return this.payrollRepo.update(\n payrollId,\n { status },\n { session: options.session }\n );\n }\n\n /**\n * Add correction to payroll\n */\n async addCorrection(\n payrollId: ObjectIdLike,\n previousAmount: number,\n newAmount: number,\n reason: string,\n correctedBy: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument> {\n const payroll = await this.findById(payrollId, options);\n\n if (!payroll) {\n throw new Error(`Payroll not found: ${payrollId}`);\n }\n\n // Add correction using document method\n payroll.addCorrection(previousAmount, newAmount, reason, toObjectId(correctedBy));\n\n await payroll.save({ session: options.session });\n\n return payroll;\n }\n\n /**\n * Get summary for organization\n *\n * organizationId auto-scoped by multiTenantPlugin\n */\n async getSummary(\n month?: number,\n year?: number,\n options: { session?: ClientSession } = {}\n ): Promise<{\n totalGross: number;\n totalNet: number;\n count: number;\n paidCount: number;\n }> {\n // organizationId automatically added by multiTenantPlugin in aggregation\n const filters: Record<string, unknown> = {};\n\n if (month) filters['period.month'] = month;\n if (year) filters['period.year'] = year;\n\n const pipeline = [\n { $match: filters },\n {\n $group: {\n _id: null,\n totalGross: { $sum: '$breakdown.grossSalary' },\n totalNet: { $sum: '$breakdown.netSalary' },\n count: { $sum: 1 },\n paidCount: {\n $sum: { $cond: [{ $eq: ['$status', 'paid'] }, 1, 0] },\n },\n },\n },\n ];\n\n const results = await this.payrollRepo.aggregate<{ totalGross: number; totalNet: number; count: number; paidCount: number }>(\n pipeline,\n { session: options.session }\n );\n\n return results[0] || { totalGross: 0, totalNet: 0, count: 0, paidCount: 0 };\n }\n\n /**\n * Check if payroll exists\n */\n async exists(\n employeeId: ObjectIdLike,\n month: number,\n year: number\n ): Promise<boolean> {\n // organizationId automatically added by multiTenantPlugin\n const result = await this.payrollRepo.exists({\n employeeId: toObjectId(employeeId),\n 'period.month': month,\n 'period.year': year,\n });\n\n return result !== null;\n }\n\n /**\n * Count payrolls\n */\n async count(filters: Record<string, unknown> = {}): Promise<number> {\n // organizationId automatically added by multiTenantPlugin\n return this.payrollRepo.count(filters);\n }\n\n /**\n * Export payrolls for date range\n */\n async exportForDateRange(\n startDate: Date,\n endDate: Date,\n options: { session?: ClientSession } = {}\n ): Promise<PayrollRecordDocument[]> {\n // organizationId automatically added by multiTenantPlugin\n const result = await this.payrollRepo.getAll(\n {\n filters: {\n 'period.startDate': { $gte: startDate },\n 'period.endDate': { $lte: endDate },\n },\n sort: { 'period.year': -1, 'period.month': -1 },\n },\n { session: options.session }\n );\n\n return result.docs;\n }\n}\n\n/**\n * Factory function to create PayrollService\n */\nexport function createPayrollService<\n T extends PayrollRecordDocument = PayrollRecordDocument,\n TEmployee extends EmployeeDocument = EmployeeDocument\n>(\n payrollRepo: Repository<T>,\n employeeService: EmployeeService<TEmployee>\n): PayrollService<T, TEmployee> {\n return new PayrollService<T, TEmployee>(payrollRepo, employeeService);\n}\n\nexport default PayrollService;\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 { roundMoney } from '../utils/money.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 roundMoney(newBaseAmount, 2),\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 (Refactored with Mongokit)\n *\n * High-level compensation operations using Repository pattern\n *\n * ⚠️ **INTERNAL USE ONLY**\n *\n * This service is for internal use by the Payroll class only.\n * All methods use repository pattern with automatic multi-tenant isolation.\n *\n * **Key Changes from v1:**\n * - Uses Repository instead of direct Model access\n * - Multi-tenant isolation handled by plugin (organizationId auto-injected)\n * - No need to pass organizationId to methods (plugin handles it)\n *\n * @internal\n */\n\nimport type { Repository } from '@classytic/mongokit';\nimport type { 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';\nimport { roundMoney } from '../utils/money.js';\n\n// ============================================================================\n// Compensation Service (Mongokit Refactored)\n// ============================================================================\n\nexport class CompensationService<T extends EmployeeDocument = EmployeeDocument> {\n constructor(private readonly employeeRepo: Repository<T>) {}\n\n /**\n * Get employee compensation\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n */\n async getEmployeeCompensation(\n employeeId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<Compensation> {\n const employee = await this.findEmployee(employeeId, options);\n return employee.compensation;\n }\n\n /**\n * Calculate compensation breakdown\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n */\n async calculateBreakdown(\n employeeId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const compensation = await this.getEmployeeCompensation(employeeId, options);\n return CompensationFactory.calculateBreakdown(compensation);\n }\n\n /**\n * Update base amount\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n */\n async updateBaseAmount(\n employeeId: ObjectIdLike,\n newAmount: number,\n effectiveFrom = new Date(),\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, options);\n\n const updatedCompensation = CompensationFactory.updateBaseAmount(\n employee.compensation,\n newAmount,\n effectiveFrom\n );\n\n await this.employeeRepo.update(\n employeeId,\n { compensation: updatedCompensation },\n { session: options.session }\n );\n\n logger.info('Compensation base amount updated', {\n employeeId: employee.employeeId,\n organizationId: employee.organizationId.toString(),\n newAmount,\n });\n\n return CompensationFactory.calculateBreakdown(updatedCompensation);\n }\n\n /**\n * Apply salary increment\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n */\n async applyIncrement(\n employeeId: ObjectIdLike,\n params: { percentage?: number; amount?: number; effectiveFrom?: Date },\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, options);\n const previousAmount = employee.compensation.baseAmount;\n\n const updatedCompensation = CompensationFactory.applyIncrement(\n employee.compensation,\n params\n );\n\n await this.employeeRepo.update(\n employeeId,\n { compensation: updatedCompensation },\n { session: options.session }\n );\n\n logger.info('Salary increment applied', {\n employeeId: employee.employeeId,\n organizationId: employee.organizationId.toString(),\n previousAmount,\n newAmount: updatedCompensation.baseAmount,\n percentage: params.percentage,\n });\n\n return CompensationFactory.calculateBreakdown(updatedCompensation);\n }\n\n /**\n * Add allowance\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n */\n async addAllowance(\n employeeId: ObjectIdLike,\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, options);\n\n const updatedCompensation = CompensationFactory.addAllowance(\n employee.compensation,\n allowance\n );\n\n await this.employeeRepo.update(\n employeeId,\n { compensation: updatedCompensation },\n { session: options.session }\n );\n\n logger.info('Allowance added', {\n employeeId: employee.employeeId,\n organizationId: employee.organizationId.toString(),\n type: allowance.type,\n value: allowance.value,\n });\n\n return CompensationFactory.calculateBreakdown(updatedCompensation);\n }\n\n /**\n * Remove allowance\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n */\n async removeAllowance(\n employeeId: ObjectIdLike,\n allowanceType: Allowance['type'],\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, options);\n\n const updatedCompensation = CompensationFactory.removeAllowance(\n employee.compensation,\n allowanceType\n );\n\n await this.employeeRepo.update(\n employeeId,\n { compensation: updatedCompensation },\n { session: options.session }\n );\n\n logger.info('Allowance removed', {\n employeeId: employee.employeeId,\n organizationId: employee.organizationId.toString(),\n type: allowanceType,\n });\n\n return CompensationFactory.calculateBreakdown(updatedCompensation);\n }\n\n /**\n * Add deduction\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n */\n async addDeduction(\n employeeId: ObjectIdLike,\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, options);\n\n const updatedCompensation = CompensationFactory.addDeduction(\n employee.compensation,\n deduction\n );\n\n await this.employeeRepo.update(\n employeeId,\n { compensation: updatedCompensation },\n { session: options.session }\n );\n\n logger.info('Deduction added', {\n employeeId: employee.employeeId,\n organizationId: employee.organizationId.toString(),\n type: deduction.type,\n value: deduction.value,\n });\n\n return CompensationFactory.calculateBreakdown(updatedCompensation);\n }\n\n /**\n * Remove deduction\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n */\n async removeDeduction(\n employeeId: ObjectIdLike,\n deductionType: Deduction['type'],\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, options);\n\n const updatedCompensation = CompensationFactory.removeDeduction(\n employee.compensation,\n deductionType\n );\n\n await this.employeeRepo.update(\n employeeId,\n { compensation: updatedCompensation },\n { session: options.session }\n );\n\n logger.info('Deduction removed', {\n employeeId: employee.employeeId,\n organizationId: employee.organizationId.toString(),\n type: deductionType,\n });\n\n return CompensationFactory.calculateBreakdown(updatedCompensation);\n }\n\n /**\n * Set standard compensation\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n */\n async setStandardCompensation(\n employeeId: ObjectIdLike,\n baseAmount: number,\n options: { session?: ClientSession } = {}\n ): Promise<CompensationBreakdownResult> {\n const employee = await this.findEmployee(employeeId, options);\n\n const standardCompensation = CompensationPresets.standard(baseAmount);\n\n await this.employeeRepo.update(\n employeeId,\n { compensation: standardCompensation },\n { session: options.session }\n );\n\n logger.info('Standard compensation set', {\n employeeId: employee.employeeId,\n organizationId: employee.organizationId.toString(),\n baseAmount,\n });\n\n return CompensationFactory.calculateBreakdown(standardCompensation);\n }\n\n /**\n * Compare compensation between two employees\n *\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n */\n async compareCompensation(\n employeeId1: ObjectIdLike,\n employeeId2: ObjectIdLike,\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, options);\n const breakdown2 = await this.calculateBreakdown(employeeId2, 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 using MongoDB aggregation\n *\n * ✨ Optimized: Uses aggregation pipeline instead of loading all employees\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n *\n * @example\n * ```typescript\n * const stats = await compensationService.getDepartmentCompensationStats('engineering');\n * console.log(stats.employeeCount); // e.g., 250\n * console.log(stats.averageBase); // e.g., 85000\n * ```\n */\n async getDepartmentCompensationStats(\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 // Use MongoDB aggregation pipeline for efficient stats calculation\n // organizationId filter automatically added by plugin\n const pipeline = [\n {\n $match: {\n department,\n status: { $in: ['active', 'on_leave'] },\n },\n },\n {\n $group: {\n _id: null,\n employeeCount: { $sum: 1 },\n totalBase: { $sum: '$compensation.baseAmount' },\n totalGross: { $sum: '$compensation.grossSalary' },\n totalNet: { $sum: '$compensation.netSalary' },\n avgBase: { $avg: '$compensation.baseAmount' },\n avgGross: { $avg: '$compensation.grossSalary' },\n avgNet: { $avg: '$compensation.netSalary' },\n },\n },\n ];\n\n const results = await this.employeeRepo.aggregate<{\n _id: null;\n employeeCount: number;\n totalBase: number;\n totalGross: number;\n totalNet: number;\n avgBase: number;\n avgGross: number;\n avgNet: number;\n }>(pipeline, { session: options.session });\n\n const stats = results[0] || {\n employeeCount: 0,\n totalBase: 0,\n totalGross: 0,\n totalNet: 0,\n avgBase: 0,\n avgGross: 0,\n avgNet: 0,\n };\n\n return {\n department,\n employeeCount: stats.employeeCount,\n totalBase: roundMoney(stats.totalBase || 0, 2),\n totalGross: roundMoney(stats.totalGross || 0, 2),\n totalNet: roundMoney(stats.totalNet || 0, 2),\n averageBase: roundMoney(stats.avgBase || 0, 2),\n averageGross: roundMoney(stats.avgGross || 0, 2),\n averageNet: roundMoney(stats.avgNet || 0, 2),\n };\n }\n\n /**\n * Get organization compensation stats using MongoDB aggregation\n *\n * ✨ Optimized: Uses aggregation pipeline instead of loading all employees\n * ⚠️ organizationId auto-scoped by multi-tenant plugin\n *\n * @example\n * ```typescript\n * const stats = await compensationService.getOrganizationCompensationStats();\n * console.log(stats.employeeCount); // Total active employees\n * console.log(stats.byDepartment); // Breakdown by department\n * ```\n */\n async getOrganizationCompensationStats(\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 // Use MongoDB aggregation with facet for both overall and by-department stats\n // organizationId filter automatically added by plugin\n const pipeline = [\n {\n $match: {\n status: { $in: ['active', 'on_leave'] },\n },\n },\n {\n $facet: {\n overall: [\n {\n $group: {\n _id: null,\n employeeCount: { $sum: 1 },\n totalBase: { $sum: '$compensation.baseAmount' },\n totalGross: { $sum: '$compensation.grossSalary' },\n totalNet: { $sum: '$compensation.netSalary' },\n avgBase: { $avg: '$compensation.baseAmount' },\n avgGross: { $avg: '$compensation.grossSalary' },\n avgNet: { $avg: '$compensation.netSalary' },\n },\n },\n ],\n byDepartment: [\n {\n $group: {\n _id: { $ifNull: ['$department', 'unassigned'] },\n count: { $sum: 1 },\n totalNet: { $sum: '$compensation.netSalary' },\n },\n },\n ],\n },\n },\n ];\n\n const results = await this.employeeRepo.aggregate<{\n overall: Array<{\n _id: null;\n employeeCount: number;\n totalBase: number;\n totalGross: number;\n totalNet: number;\n avgBase: number;\n avgGross: number;\n avgNet: number;\n }>;\n byDepartment: Array<{\n _id: string;\n count: number;\n totalNet: number;\n }>;\n }>(pipeline, { session: options.session });\n\n const overallStats = results[0]?.overall[0] || {\n employeeCount: 0,\n totalBase: 0,\n totalGross: 0,\n totalNet: 0,\n avgBase: 0,\n avgGross: 0,\n avgNet: 0,\n };\n\n const byDepartment: Record<string, { count: number; totalNet: number }> = {};\n (results[0]?.byDepartment || []).forEach((dept) => {\n byDepartment[dept._id] = {\n count: dept.count,\n totalNet: roundMoney(dept.totalNet || 0, 2),\n };\n });\n\n return {\n employeeCount: overallStats.employeeCount,\n totalBase: roundMoney(overallStats.totalBase || 0, 2),\n totalGross: roundMoney(overallStats.totalGross || 0, 2),\n totalNet: roundMoney(overallStats.totalNet || 0, 2),\n averageBase: roundMoney(overallStats.avgBase || 0, 2),\n averageGross: roundMoney(overallStats.avgGross || 0, 2),\n averageNet: roundMoney(overallStats.avgNet || 0, 2),\n byDepartment,\n };\n }\n\n /**\n * Find employee helper\n *\n * ⚠️ organizationId automatically validated by multiTenantPlugin\n */\n private async findEmployee(\n employeeId: ObjectIdLike,\n options: { session?: ClientSession } = {}\n ): Promise<EmployeeDocument> {\n // Use getAll to ensure organizationId filtering works at query level\n const result = await this.employeeRepo.getAll(\n {\n filters: { _id: toObjectId(employeeId) },\n limit: 1,\n },\n { session: options.session }\n );\n\n const employee = result.docs[0];\n if (!employee) {\n throw new Error(`Employee not found: ${employeeId}`);\n }\n\n return employee;\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create compensation service instance\n */\nexport function createCompensationService<T extends EmployeeDocument = EmployeeDocument>(\n employeeRepo: Repository<T>\n): CompensationService<T> {\n return new CompensationService<T>(employeeRepo);\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 TaxCalculationOptions,\n PaymentFrequency,\n} from '../types.js';\nimport { calculateGross, calculateNet, sumAllowances, sumDeductions, applyTaxBrackets } from '../utils/calculation.js';\nimport { roundMoney, percentageOf, prorateAmount } from '../utils/money.js';\nimport { isEffectiveForPeriod } from '../utils/date.js';\nimport { countWorkingDays } from '../core/config.js';\nimport { getPayPeriodsPerYear } from '../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 * Enhanced tax calculation options (optional)\n *\n * When provided, enables jurisdiction-aware tax calculation with:\n * - Standard deduction / tax-free threshold\n * - Demographic-based thresholds (senior, disabled, etc.)\n * - Pre-tax deductions handling\n * - Tax credits/rebates\n *\n * @example\n * ```typescript\n * taxOptions: {\n * applyStandardDeduction: true,\n * taxpayerCategory: 'senior',\n * preTaxDeductions: [{ type: 'provident_fund', amount: 5000 }],\n * taxCredits: [{ type: 'investment', amount: 2000 }],\n * }\n * ```\n */\n taxOptions?: TaxCalculationOptions;\n\n /**\n * Jurisdiction tax configuration (optional)\n *\n * When provided alongside taxOptions, enables lookup of:\n * - standardDeduction from jurisdiction\n * - thresholdsByCategory for taxpayer category\n * - preTaxDeductionTypes for automatic pre-tax detection\n */\n jurisdictionTaxConfig?: {\n /** Standard deduction amount (annual) */\n standardDeduction?: number;\n /** Tax-free thresholds by taxpayer category (annual) */\n thresholdsByCategory?: Record<string, number>;\n /** Recognized pre-tax deduction types */\n preTaxDeductionTypes?: string[];\n };\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, taxOptions, jurisdictionTaxConfig } = 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 = prorateAmount(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, options.skipProration);\n\n // 6. Calculate deductions (handle percentages and pro-rating)\n const deductions = processDeductions(effectiveDeductions, originalBaseAmount, proRating, config, options.skipProration);\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 with enhanced tax options\n const taxableAllowances = allowances.filter((a) => a.taxable);\n let taxableAmount = baseAmount + sumAllowances(taxableAllowances);\n\n // 9a. Apply pre-tax deductions (reduce taxable income)\n const preTaxDeductionAmount = calculatePreTaxDeductions(\n effectiveDeductions,\n deductions,\n taxOptions,\n jurisdictionTaxConfig\n );\n taxableAmount = Math.max(0, taxableAmount - preTaxDeductionAmount);\n\n // 10. Calculate tax with enhanced options (frequency-aware)\n const frequency = employee.compensation?.frequency || 'monthly';\n let taxAmount = 0;\n if (!options.skipTax && taxBrackets.length > 0 && config.autoDeductions) {\n taxAmount = calculateEnhancedTax(\n taxableAmount,\n taxBrackets,\n taxOptions,\n jurisdictionTaxConfig,\n frequency\n );\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 * 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 skipProration?: boolean\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 ? percentageOf(originalBaseAmount, a.value)\n : a.amount;\n\n const originalAmount = amount;\n\n // Apply pro-rating ONCE if needed (respect skipProration flag)\n if (proRating.isProRated && config.allowProRating && !skipProration) {\n amount = prorateAmount(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 skipProration?: boolean\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 ? percentageOf(originalBaseAmount, d.value)\n : d.amount;\n\n const originalAmount = amount;\n\n // Apply pro-rating ONCE if needed (respect skipProration flag)\n if (proRating.isProRated && config.allowProRating && !skipProration) {\n amount = prorateAmount(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 * Calculate total pre-tax deductions (monthly)\n *\n * Pre-tax deductions reduce taxable income before tax brackets are applied.\n * Sources:\n * 1. Employee deductions with reducesTaxableIncome=true\n * 2. Deductions matching jurisdictionTaxConfig.preTaxDeductionTypes\n * 3. Explicit taxOptions.preTaxDeductions\n */\nfunction calculatePreTaxDeductions(\n effectiveDeductions: Deduction[],\n processedDeductions: ProcessedDeduction[],\n taxOptions?: TaxCalculationOptions,\n jurisdictionTaxConfig?: SalaryCalculationInput['jurisdictionTaxConfig']\n): number {\n let totalPreTax = 0;\n\n // NOTE: effectiveDeductions[i] and processedDeductions[i] are 1:1 aligned.\n // processDeductions() builds processedDeductions from effectiveDeductions in order.\n // Attendance deductions are appended to processedDeductions AFTER this array is built,\n // so they won't be iterated here (effectiveDeductions.length < processedDeductions.length\n // when attendance deductions exist, but we only iterate up to effectiveDeductions.length).\n\n // 1. Sum deductions marked as reducesTaxableIncome\n for (let i = 0; i < effectiveDeductions.length; i++) {\n const original = effectiveDeductions[i];\n const processed = processedDeductions[i];\n\n if (original.reducesTaxableIncome) {\n totalPreTax += processed?.amount || 0;\n }\n }\n\n // 2. Sum deductions matching jurisdiction's preTaxDeductionTypes\n if (jurisdictionTaxConfig?.preTaxDeductionTypes?.length) {\n const preTaxTypes = new Set(jurisdictionTaxConfig.preTaxDeductionTypes);\n\n for (let i = 0; i < effectiveDeductions.length; i++) {\n const original = effectiveDeductions[i];\n const processed = processedDeductions[i];\n\n // Skip if already counted via reducesTaxableIncome\n if (original.reducesTaxableIncome) continue;\n\n // Check if deduction type is in pre-tax list\n if (preTaxTypes.has(original.type)) {\n totalPreTax += processed?.amount || 0;\n }\n }\n }\n\n // 3. Add explicit pre-tax deductions from taxOptions\n if (taxOptions?.preTaxDeductions?.length) {\n for (const deduction of taxOptions.preTaxDeductions) {\n totalPreTax += deduction.amount;\n }\n }\n\n return roundMoney(totalPreTax);\n}\n\n/**\n * Calculate tax with enhanced options\n *\n * Supports:\n * - Standard deduction / tax-free threshold\n * - Demographic-based thresholds (taxpayerCategory)\n * - Tax credits/rebates\n * - Multiple payment frequencies (weekly, bi_weekly, monthly, etc.)\n *\n * @param periodTaxable - Taxable amount for the pay period (after pre-tax deductions)\n * @param taxBrackets - Tax brackets (for annual income)\n * @param taxOptions - Enhanced tax calculation options\n * @param jurisdictionTaxConfig - Jurisdiction tax configuration\n * @param frequency - Payment frequency (determines periods per year)\n * @returns Tax amount for the pay period (after credits)\n */\nfunction calculateEnhancedTax(\n periodTaxable: number,\n taxBrackets: TaxBracket[],\n taxOptions?: TaxCalculationOptions,\n jurisdictionTaxConfig?: SalaryCalculationInput['jurisdictionTaxConfig'],\n frequency: PaymentFrequency = 'monthly'\n): number {\n // Get pay periods per year based on frequency\n const periodsPerYear = getPayPeriodsPerYear(frequency);\n\n // Annualize the taxable amount\n let annualTaxable = periodTaxable * periodsPerYear;\n\n // Apply standard deduction or threshold\n const threshold = getApplicableThreshold(taxOptions, jurisdictionTaxConfig);\n if (threshold > 0) {\n annualTaxable = Math.max(0, annualTaxable - threshold);\n }\n\n // Calculate tax using brackets\n let annualTax = applyTaxBrackets(annualTaxable, taxBrackets);\n\n // Apply tax credits (reduce tax liability)\n if (taxOptions?.taxCredits?.length && annualTax > 0) {\n annualTax = applyTaxCredits(annualTax, taxOptions.taxCredits);\n }\n\n // Return period tax (banker's rounding)\n return roundMoney(annualTax / periodsPerYear);\n}\n\n/**\n * Get applicable tax-free threshold based on options\n *\n * Priority:\n * 1. taxOptions.standardDeductionOverride (explicit override)\n * 2. taxOptions.thresholdOverrides[taxpayerCategory]\n * 3. jurisdictionTaxConfig.thresholdsByCategory[taxpayerCategory]\n * 4. jurisdictionTaxConfig.standardDeduction (if applyStandardDeduction)\n */\nfunction getApplicableThreshold(\n taxOptions?: TaxCalculationOptions,\n jurisdictionTaxConfig?: SalaryCalculationInput['jurisdictionTaxConfig']\n): number {\n // 1. Explicit override takes highest priority\n if (taxOptions?.standardDeductionOverride !== undefined) {\n return taxOptions.standardDeductionOverride;\n }\n\n // 2. Check taxpayer category thresholds\n if (taxOptions?.taxpayerCategory) {\n const category = taxOptions.taxpayerCategory;\n\n // Check override thresholds first\n if (taxOptions.thresholdOverrides?.[category] !== undefined) {\n return taxOptions.thresholdOverrides[category];\n }\n\n // Check jurisdiction thresholds\n if (jurisdictionTaxConfig?.thresholdsByCategory?.[category] !== undefined) {\n return jurisdictionTaxConfig.thresholdsByCategory[category];\n }\n }\n\n // 3. Fall back to standard deduction if enabled\n if (taxOptions?.applyStandardDeduction && jurisdictionTaxConfig?.standardDeduction) {\n return jurisdictionTaxConfig.standardDeduction;\n }\n\n return 0;\n}\n\n/**\n * Apply tax credits to reduce tax liability\n *\n * Credits with maxPercent are capped at that percentage of the original tax.\n * Credits cannot reduce tax below zero.\n */\nfunction applyTaxCredits(\n annualTax: number,\n taxCredits: NonNullable<TaxCalculationOptions['taxCredits']>\n): number {\n let remainingTax = annualTax;\n\n for (const credit of taxCredits) {\n if (remainingTax <= 0) break;\n\n let creditAmount = credit.amount;\n\n // Apply maxPercent cap if specified\n if (credit.maxPercent !== undefined && credit.maxPercent > 0) {\n const maxCredit = annualTax * credit.maxPercent;\n creditAmount = Math.min(creditAmount, maxCredit);\n }\n\n // Credit cannot exceed remaining tax\n creditAmount = Math.min(creditAmount, remainingTax);\n remainingTax -= creditAmount;\n }\n\n return Math.max(0, remainingTax);\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 * All monetary calculations use banker's rounding for financial accuracy.\n *\n * @packageDocumentation\n */\n\nimport { roundMoney } from '../utils/money.js';\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 (banker's rounding to cents)\n const deductionAmount = roundMoney(absentDays * rate, 2);\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 roundMoney(monthlySalary / workingDays, 2);\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 roundMoney(dailyRate / hoursPerDay, 2);\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 roundMoney(dailyRate * fraction, 2);\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 (banker's rounding to whole units)\n const fullDayDeduction = roundMoney(dailyRate * Math.max(0, fullDayAbsences), 2);\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","/**\n * Repository plugins for mongokit integration\n */\n\nimport type { Plugin } from '@classytic/mongokit';\nimport type { ObjectId } from '../types.js';\nimport { toObjectId } from '../utils/query-builders.js';\n\n/** Hook context for create operations */\ninterface CreateHookContext {\n data?: Record<string, unknown> | Record<string, unknown>[];\n}\n\n/** Hook context for filter-based operations (getAll, getById, update, delete) */\ninterface FilterHookContext {\n filters?: Record<string, unknown>;\n}\n\n/** Hook context for query-based operations (getByQuery) */\ninterface QueryHookContext {\n query?: Record<string, unknown>;\n}\n\n/**\n * Multi-tenant plugin - automatically injects organizationId into all repository operations.\n *\n * Hooks into create, getAll, getById, getByQuery, update, and delete operations\n * to enforce organizational isolation. The organizationId is force-set on creates\n * (cannot be overridden by caller) and added as a filter on all read/write operations.\n *\n * @param organizationId - Organization ID to scope all operations to. If undefined, plugin is a no-op.\n * @returns Mongokit Plugin instance\n *\n * @example\n * ```typescript\n * import { multiTenantPlugin } from '@classytic/payroll';\n * import { Repository } from '@classytic/mongokit';\n *\n * const repo = new Repository(EmployeeModel, [\n * multiTenantPlugin(organizationId),\n * ]);\n *\n * // All operations auto-scoped to organizationId\n * await repo.getAll({ filters: { status: 'active' } });\n * // Executes: { organizationId, status: 'active' }\n * ```\n */\nexport function multiTenantPlugin(organizationId?: ObjectId): Plugin {\n return {\n name: 'multi-tenant',\n apply(repo) {\n if (!organizationId) return;\n\n const orgId = toObjectId(organizationId);\n\n // Inject organizationId into create operations (ALWAYS enforce, never allow override)\n repo.on('before:create', async (context: CreateHookContext) => {\n if (context.data) {\n if (Array.isArray(context.data)) {\n context.data = context.data.map((item: Record<string, unknown>) => ({\n ...item,\n organizationId: orgId, // CRITICAL: Force override - never allow caller to set different orgId\n }));\n } else {\n context.data = {\n ...context.data,\n organizationId: orgId, // CRITICAL: Force override - never allow caller to set different orgId\n };\n }\n }\n });\n\n // Add organizationId filter to getAll operations\n repo.on('before:getAll', async (context: FilterHookContext) => {\n // Always inject organizationId, even if filters is empty\n context.filters = {\n ...(context.filters || {}),\n organizationId: orgId,\n };\n });\n\n // Add organizationId filter to getById operations\n repo.on('before:getById', async (context: FilterHookContext) => {\n // Always inject organizationId, even if filters is empty\n context.filters = {\n ...(context.filters || {}),\n organizationId: orgId,\n };\n });\n\n // Add organizationId filter to getByQuery operations\n repo.on('before:getByQuery', async (context: QueryHookContext) => {\n // Directly modify query object to ensure organizationId is set\n if (!context.query) {\n context.query = {};\n }\n context.query.organizationId = orgId;\n });\n\n // Add organizationId filter to update operations\n repo.on('before:update', async (context: FilterHookContext) => {\n // Always inject organizationId, even if filters is empty\n context.filters = {\n ...(context.filters || {}),\n organizationId: orgId,\n };\n });\n\n // Add organizationId filter to delete operations\n repo.on('before:delete', async (context: FilterHookContext) => {\n // Always inject organizationId, even if filters is empty\n context.filters = {\n ...(context.filters || {}),\n organizationId: orgId,\n };\n });\n },\n };\n}\n\n","/**\n * @classytic/payroll - Repository Manager\n *\n * Handles per-request repository creation with proper multi-tenant isolation.\n * Repositories are created fresh for each request with organizationId-scoped plugins.\n */\n\nimport { Repository } from '@classytic/mongokit';\nimport type { Model, ClientSession } from 'mongoose';\nimport type { Container } from '../core/container.js';\nimport type {\n EmployeeDocument,\n PayrollRecordDocument,\n LeaveRequestDocument,\n TaxWithholdingDocument,\n AnyDocument\n} from '../types.js';\nimport { multiTenantPlugin } from '../core/repository-plugins.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 type { ObjectId } from '../types.js';\n\n/**\n * Repository collection for a single request\n */\nexport interface RequestScopedRepositories<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument,\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument\n> {\n employee: Repository<TEmployee>;\n payrollRecord: Repository<TPayrollRecord>;\n transaction: Repository<TTransaction>;\n leaveRequest?: Repository<TLeaveRequest>;\n taxWithholding?: Repository<TTaxWithholding>;\n}\n\n/**\n * Service collection for a single request\n */\nexport interface RequestScopedServices<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument\n> {\n employee: EmployeeService<TEmployee>;\n payroll: PayrollService<TPayrollRecord, TEmployee>;\n compensation: CompensationService<TEmployee>;\n}\n\n/**\n * Models configuration\n */\nexport interface ModelsConfig<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction 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<AnyDocument> | null;\n LeaveRequestModel?: Model<TLeaveRequest> | null;\n TaxWithholdingModel?: Model<TTaxWithholding> | null;\n}\n\n/**\n * RepositoryManager\n *\n * Creates per-request repositories with organizationId-scoped plugins.\n * This ensures proper multi-tenant isolation at the database query level.\n *\n * Key Features:\n * - Per-request scope (no cached state)\n * - Multi-tenant security via plugins\n * - Audit trail support\n * - Service layer creation\n *\n * @example\n * ```typescript\n * const manager = new RepositoryManager(models, container);\n *\n * // Create repositories for a specific request/organizationId\n * const repos = manager.getReposForRequest(organizationId);\n *\n * // Use the scoped repository\n * const employee = await repos.employee.getById(employeeId);\n * // ^ This query automatically includes: { organizationId }\n * ```\n */\nexport class RepositoryManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument,\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument\n> {\n constructor(\n private readonly models: ModelsConfig<TEmployee, TPayrollRecord, TTransaction, TLeaveRequest, TTaxWithholding>,\n // TODO(@classytic/payroll): Container reserved for future audit/plugin integration\n private readonly _container: Container<TEmployee, TPayrollRecord, TTransaction, AnyDocument>\n ) {}\n\n /**\n * Create request-scoped repositories with organizationId filtering\n *\n * SECURITY: Each repository is created with multiTenantPlugin that injects\n * organizationId into ALL queries, ensuring database-level multi-tenant isolation.\n *\n * @param organizationId - Organization ID for this request\n * @returns Fresh repository instances scoped to this organizationId\n */\n getReposForRequest(organizationId: ObjectId): RequestScopedRepositories<TEmployee, TPayrollRecord, TTransaction, TLeaveRequest, TTaxWithholding> {\n // Create plugins for this request\n // SECURITY: multiTenantPlugin enforces organizationId on ALL queries\n const plugins = [\n multiTenantPlugin(organizationId),\n ];\n\n // Create fresh repository instances (no caching)\n // SECURITY: All repositories get multi-tenant plugin to enforce org isolation\n const repos: RequestScopedRepositories<TEmployee, TPayrollRecord, TTransaction, TLeaveRequest, TTaxWithholding> = {\n employee: new Repository(this.models.EmployeeModel, plugins),\n payrollRecord: new Repository(this.models.PayrollRecordModel, plugins),\n transaction: new Repository(this.models.TransactionModel, plugins), // SECURITY: Transactions are org-scoped\n };\n\n // Optional models\n if (this.models.LeaveRequestModel) {\n repos.leaveRequest = new Repository(this.models.LeaveRequestModel, plugins);\n }\n\n if (this.models.TaxWithholdingModel) {\n repos.taxWithholding = new Repository(this.models.TaxWithholdingModel, plugins);\n }\n\n return repos;\n }\n\n /**\n * Create request-scoped services\n *\n * Services wrap repositories with business logic and are also request-scoped.\n *\n * @param organizationId - Organization ID for this request\n * @param session - Optional transaction session\n * @returns Fresh service instances\n */\n getServicesForRequest(\n organizationId: ObjectId,\n _session?: ClientSession // TODO(@classytic/payroll): Session support for service-level transactions\n ): RequestScopedServices<TEmployee, TPayrollRecord, TLeaveRequest> {\n const repos = this.getReposForRequest(organizationId);\n const employeeService = createEmployeeService(repos.employee);\n\n return {\n employee: employeeService,\n payroll: createPayrollService(repos.payrollRecord, employeeService),\n compensation: createCompensationService(repos.employee),\n };\n }\n\n /**\n * Get models (for direct access when needed)\n */\n getModels(): ModelsConfig<TEmployee, TPayrollRecord, TTransaction, TLeaveRequest, TTaxWithholding> {\n return this.models;\n }\n}\n\n/**\n * Factory function for creating RepositoryManager\n *\n * @param models - Model configuration\n * @param container - Container instance\n * @returns RepositoryManager instance\n */\nexport function createRepositoryManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument,\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument\n>(\n models: ModelsConfig<TEmployee, TPayrollRecord, TTransaction, TLeaveRequest, TTaxWithholding>,\n container: Container<TEmployee, TPayrollRecord, TTransaction, AnyDocument>\n): RepositoryManager<TEmployee, TPayrollRecord, TTransaction, TLeaveRequest, TTaxWithholding> {\n return new RepositoryManager(models, container);\n}\n","/**\n * @classytic/payroll - Salary Processing Manager\n *\n * Handles individual salary processing with transaction management,\n * retry logic, and multi-tenant security.\n */\n\nimport mongoose, { Model, type ClientSession } from 'mongoose';\nimport type {\n EmployeeDocument,\n PayrollRecordDocument,\n AnyDocument,\n LeaveRequestDocument,\n ProcessSalaryParams,\n ProcessSalaryResult,\n ObjectId,\n ObjectIdLike,\n TaxWithholdingModel,\n PayrollRunType,\n} from '../types.js';\nimport { getLogger } from '../utils/logger.js';\nimport { NotEligibleError, DuplicatePayrollError, PayrollError } from '../errors/index.js';\nimport { payroll as payrollQuery, toObjectId } from '../utils/query-builders.js';\nimport { getPayPeriod, getPayPeriodForFrequency } from '../utils/date.js';\nimport { generatePayrollIdempotencyKey, type IdempotencyManager } from '../core/idempotency.js';\nimport type { EventBus } from '../core/events.js';\nimport type { Container } from '../core/container.js';\nimport type { RepositoryManager } from './repository.manager.js';\nimport type { PayrollRepositories } from '../types.js';\nimport { hasPluginMethod } from '../utils/validation.js';\nimport { getEmployeeEmail, getEmployeeName } from '../utils/employee-type-guards.js';\nimport { isDuplicateKeyError, parseDuplicateKeyError } from '../utils/type-guards.js';\n\n/**\n * SalaryProcessingManager\n *\n * Extracts salary processing logic from the main Payroll class.\n * Handles individual salary processing with proper transaction management,\n * idempotency, retry logic, and multi-tenant security.\n *\n * Key responsibilities:\n * - Process individual employee salary\n * - Calculate salary breakdowns\n * - Manage retry behavior (only safe retries)\n * - Cascade delete related records\n * - Create transactions and tax withholdings\n *\n * @example\n * ```typescript\n * const manager = new SalaryProcessingManager(models, container, events, idempotency, repositoryManager);\n * const result = await manager.processSalary({\n * employeeId: 'EMP-001',\n * organizationId: orgId,\n * month: 1,\n * year: 2024,\n * });\n * ```\n */\nexport class SalaryProcessingManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument\n> {\n constructor(\n private readonly models: {\n EmployeeModel: Model<TEmployee>;\n PayrollRecordModel: Model<TPayrollRecord>;\n TransactionModel: Model<TTransaction>;\n AttendanceModel?: Model<TAttendance> | null;\n LeaveRequestModel?: Model<LeaveRequestDocument> | null;\n TaxWithholdingModel?: TaxWithholdingModel | null;\n },\n // TODO(@classytic/payroll): Container reserved for future plugin/extension support\n private readonly _container: Container<TEmployee, TPayrollRecord, TTransaction, TAttendance>,\n private readonly events: EventBus,\n private readonly idempotency: IdempotencyManager,\n private readonly repositoryManager: RepositoryManager<TEmployee, TPayrollRecord, TTransaction>,\n private readonly calculateSalaryBreakdownFn: (\n employee: EmployeeDocument,\n period: { month: number; year: number; startDate: Date; endDate: Date; payDate: Date },\n input?: { attendance?: import('../core/config.js').AttendanceInput | null; options?: import('../core/config.js').PayrollProcessingOptions },\n session?: ClientSession\n ) => Promise<import('../types.js').PayrollBreakdown>,\n private readonly resolveOrganizationIdFn: (providedOrgId?: ObjectIdLike) => ObjectId,\n private readonly resolveEmployeeIdFn: (\n employeeId: ObjectIdLike | string,\n employeeIdMode: 'auto' | 'objectId' | 'businessId' | undefined,\n organizationId: ObjectIdLike,\n session?: ClientSession\n ) => Promise<mongoose.Types.ObjectId>,\n private readonly findEmployeeFn: import('./context.js').FindEmployeeFn<TEmployee>,\n private readonly updatePayrollStatsFn: import('./context.js').UpdatePayrollStatsFn<TEmployee, TPayrollRecord, TTransaction>,\n private readonly config: import('../types.js').HRMConfig\n ) {}\n\n /**\n * Cascade delete payroll record and related documents\n * Deletes the payroll record and any related tax withholdings\n *\n * @param payrollRecordId - ID of payroll record to delete\n * @param session - Optional transaction session\n * @private\n */\n private async cascadeDeletePayrollRecord(\n payrollRecordId: mongoose.Types.ObjectId,\n session?: mongoose.ClientSession\n ): Promise<void> {\n const sessionOpt = session ? { session } : {};\n\n // Delete the payroll record itself\n await this.models.PayrollRecordModel.deleteOne({ _id: payrollRecordId }, sessionOpt);\n\n // Cascade delete related tax withholdings (if model provided)\n if (this.models.TaxWithholdingModel) {\n const deleted = await this.models.TaxWithholdingModel.deleteMany(\n { payrollRecordId },\n sessionOpt\n );\n\n if (deleted.deletedCount && deleted.deletedCount > 0) {\n getLogger().info('Cascade deleted tax withholdings', {\n payrollRecordId: payrollRecordId.toString(),\n count: deleted.deletedCount,\n });\n }\n }\n\n // Note: We do NOT delete transactions because:\n // 1. If transactionId exists, we should never reach this code (caught earlier)\n // 2. Transactions are financial records that should be preserved even if orphaned\n // 3. Transaction model is app-provided and we can't assume its structure\n }\n\n /**\n * Process salary for a single employee\n */\n async processSalary(\n params: ProcessSalaryParams\n ): Promise<ProcessSalaryResult<TEmployee, TPayrollRecord, TTransaction>> {\n const {\n employeeId,\n employeeIdMode,\n organizationId: explicitOrgId,\n month,\n year,\n paymentDate = new Date(),\n paymentMethod = 'bank',\n attendance,\n options,\n context,\n idempotencyKey,\n payrollRunType = 'regular',\n retroactiveAdjustment,\n employerContributions,\n } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n // Create request-scoped repositories for proper multi-tenant isolation\n const repos = this.repositoryManager.getReposForRequest(orgId) as PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>;\n\n // Resolve employee ID and fetch employee to get frequency for proper idempotency key\n const resolvedEmployeeId = await this.resolveEmployeeIdFn(employeeId, employeeIdMode, orgId, context?.session);\n\n // Fetch employee early to determine frequency for idempotency key generation\n // This is necessary for non-monthly frequencies where the same month can have multiple pay periods\n const employee = await this.findEmployeeFn({\n employeeId,\n employeeIdMode,\n organizationId: orgId,\n session: context?.session ?? undefined,\n populate: 'userId'\n });\n\n // Calculate period based on employee's payment frequency\n // This is needed for proper idempotency key generation\n const employeeFrequency = employee.compensation?.frequency || 'monthly';\n const frequencyPeriod = getPayPeriodForFrequency(employeeFrequency, paymentDate, month, year);\n const period = { ...frequencyPeriod, payDate: paymentDate };\n\n // Idempotency: Generate or use provided key\n // For non-monthly frequencies, include period.startDate to differentiate runs within the same month\n const idempotentKey = idempotencyKey || generatePayrollIdempotencyKey(\n orgId,\n resolvedEmployeeId,\n month,\n year,\n payrollRunType,\n employeeFrequency !== 'monthly' ? period.startDate : undefined\n );\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 frequency: employeeFrequency,\n });\n return cached.value;\n }\n\n // CRITICAL: Transaction management - enforce atomicity\n const providedSession = context?.session;\n\n // If session provided, use it directly (caller manages transaction lifecycle)\n // Otherwise, use mongokit's withTransaction() for proper retry handling\n if (providedSession) {\n return this._processSalaryWithSession(providedSession, repos, params, resolvedEmployeeId, orgId, idempotentKey, employee, period);\n }\n\n // Use mongokit's withTransaction() to prevent transaction number mismatch\n // This properly handles MongoDB retries and transaction lifecycle\n try {\n return await repos.employee.withTransaction(\n async (session) => this._processSalaryWithSession(session, repos, params, resolvedEmployeeId, orgId, idempotentKey, employee, period),\n { allowFallback: true } // Fallback to non-transactional for standalone MongoDB\n );\n } catch (error) {\n // Handle duplicate key error OUTSIDE transaction to avoid session corruption\n // E11000 inside a transaction auto-aborts it; catching inside withTransaction()\n // and returning success causes commit to fail on already-aborted transaction\n if (isDuplicateKeyError(error)) {\n return this._handleDuplicateKeyError(error, resolvedEmployeeId, orgId, params.month, params.year, payrollRunType, idempotentKey, period.startDate, employeeFrequency);\n }\n throw error;\n }\n }\n\n /**\n * Handle duplicate key error by fetching existing payroll record\n * MUST be called OUTSIDE transaction to avoid session state corruption\n */\n private async _handleDuplicateKeyError(\n error: unknown,\n resolvedEmployeeId: ObjectId,\n orgId: ObjectId,\n month: number,\n year: number,\n payrollRunType: PayrollRunType,\n idempotentKey: string,\n periodStartDate: Date,\n employeeFrequency: string\n ): Promise<ProcessSalaryResult<TEmployee, TPayrollRecord, TTransaction>> {\n // Safe cast: only called after isDuplicateKeyError() returns true\n const duplicateField = parseDuplicateKeyError(error as import('mongodb').MongoServerError);\n getLogger().warn('Duplicate payroll record detected (E11000), fetching existing', {\n employeeId: resolvedEmployeeId.toString(),\n month,\n year,\n payrollRunType,\n idempotencyKey: idempotentKey,\n duplicateField,\n periodStartDate: periodStartDate.toISOString(),\n frequency: employeeFrequency,\n });\n\n // Build query to fetch existing payroll record\n // For non-monthly frequencies, include period.startDate to find the correct record\n const query: Record<string, unknown> = {\n organizationId: orgId,\n employeeId: resolvedEmployeeId,\n 'period.month': month,\n 'period.year': year,\n payrollRunType,\n };\n\n // For non-monthly frequencies, include period.startDate to fetch the correct record\n if (employeeFrequency !== 'monthly') {\n query['period.startDate'] = periodStartDate;\n }\n\n // Fetch existing payroll record with populated transaction (NO session - clean query)\n const existingPayroll = await (this.models.PayrollRecordModel as Model<PayrollRecordDocument>)\n .findOne(query)\n .populate('transactionId');\n\n if (existingPayroll && existingPayroll.transactionId) {\n // Fetch employee for the result\n const existingEmployee = await this.models.EmployeeModel.findOne({\n _id: resolvedEmployeeId,\n organizationId: orgId,\n });\n\n if (!existingEmployee) {\n throw new PayrollError(\n `Data inconsistency: Payroll record exists but employee not found for ${resolvedEmployeeId.toString()} in organization ${orgId.toString()}. ` +\n `The employee may have been deleted after payroll was processed.`,\n 'PAYROLL_ERROR',\n 500,\n {\n reason: 'data_inconsistency',\n employeeId: resolvedEmployeeId.toString(),\n organizationId: orgId.toString(),\n payrollRecordId: existingPayroll._id.toString(),\n month,\n year,\n }\n );\n }\n\n const result = {\n payrollRecord: existingPayroll as unknown as TPayrollRecord,\n transaction: existingPayroll.transactionId as unknown as TTransaction,\n employee: existingEmployee as unknown as TEmployee,\n };\n\n // Cache for future idempotent requests\n this.idempotency.set(idempotentKey, result);\n\n return result;\n }\n\n // Existing record found but missing transactionId - orphaned/partial record\n // This can happen when a previous non-transactional attempt failed after creating\n // the payroll record but before creating the transaction.\n if (existingPayroll && !existingPayroll.transactionId) {\n const status = existingPayroll.status;\n\n // If the record is 'failed', the retry logic in _processSalaryWithSession\n // will cascade-delete it on the next attempt. Throw a retryable error.\n if (status === 'failed') {\n throw new PayrollError(\n `Previous payroll attempt failed for employee in ${month}/${year}. Retry to automatically clean up and reprocess.`,\n 'DUPLICATE_PAYROLL',\n 409,\n {\n existingRecordId: existingPayroll._id.toString(),\n status,\n reason: 'orphaned_failed_record',\n retryable: true,\n }\n );\n }\n\n // For processing/pending without transaction, mark as failed for future retry\n if (status === 'processing' || status === 'pending') {\n try {\n await (this.models.PayrollRecordModel as Model<PayrollRecordDocument>).updateOne(\n { _id: existingPayroll._id },\n { $set: { status: 'failed' } }\n );\n getLogger().warn('Marked orphaned payroll record as failed', {\n payrollRecordId: existingPayroll._id.toString(),\n previousStatus: status,\n });\n } catch {\n // Best-effort cleanup\n }\n\n throw new PayrollError(\n `Previous payroll attempt was incomplete for employee in ${month}/${year}. The record has been marked as failed - retry to reprocess.`,\n 'DUPLICATE_PAYROLL',\n 409,\n {\n existingRecordId: existingPayroll._id.toString(),\n status: 'failed',\n reason: 'orphaned_record_cleaned',\n retryable: true,\n }\n );\n }\n }\n\n // No valid existing record found - rethrow original error\n throw error;\n }\n\n /**\n * Internal: Process salary with a specific session\n * Extracted to support both external sessions and withTransaction() pattern\n *\n * @param session - Database session (for transactions)\n * @param repos - Request-scoped repositories\n * @param params - Salary processing parameters\n * @param resolvedEmployeeId - Pre-resolved employee ObjectId\n * @param orgId - Organization ID\n * @param idempotentKey - Pre-calculated idempotency key\n * @param prefetchedEmployee - Pre-fetched employee (to avoid duplicate DB call)\n * @param prefetchedPeriod - Pre-calculated period (to avoid duplicate calculation)\n */\n private async _processSalaryWithSession(\n session: ClientSession | null,\n repos: PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>,\n params: ProcessSalaryParams,\n resolvedEmployeeId: ObjectId,\n orgId: ObjectId,\n idempotentKey: string,\n prefetchedEmployee: TEmployee,\n prefetchedPeriod: { month: number; year: number; startDate: Date; endDate: Date; workingDays: number; payDate: Date }\n ): Promise<ProcessSalaryResult<TEmployee, TPayrollRecord, TTransaction>> {\n const {\n month,\n year,\n paymentDate = new Date(),\n paymentMethod = 'bank',\n attendance,\n options,\n context,\n payrollRunType = 'regular',\n retroactiveAdjustment,\n employerContributions,\n } = params;\n\n // Convert null to undefined for Mongoose API compatibility\n const mongooseSession = session ?? undefined;\n\n // Track created records for non-transactional cleanup on failure\n let createdPayrollRecordId: mongoose.Types.ObjectId | null = null;\n let createdTransactionId: mongoose.Types.ObjectId | null = null;\n\n try {\n // Use pre-fetched employee (already fetched in processSalary for idempotency key generation)\n const employee = prefetchedEmployee;\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.status === 'on_leave') && (employee.compensation?.baseAmount || 0) > 0);\n\n if (!canReceive) {\n throw new NotEligibleError('Employee is not eligible to receive salary');\n }\n\n // Use pre-calculated period (already calculated in processSalary for idempotency key)\n const period = prefetchedPeriod;\n const employeeFrequency = employee.compensation?.frequency || 'monthly';\n\n // Check for existing payroll of the SAME run type AND period\n // ✅ Use employee._id (not employeeId param) since we've resolved the employee\n // ✅ DEFENSE-IN-DEPTH: Include organizationId even though employee is already org-scoped\n // ✅ Include payrollRunType to allow multiple run types per period (regular + supplemental)\n // ✅ Include period.startDate for non-monthly frequencies to allow multiple runs/month\n const existingQuery: Record<string, unknown> = {\n ...payrollQuery()\n .forOrganization(orgId)\n .forEmployee(employee._id)\n .forPeriod(month, year)\n .build(),\n payrollRunType, // Only check for same run type\n };\n\n // For non-monthly frequencies, include period.startDate in duplicate check\n // This allows multiple runs per month (e.g., 4 weekly runs in March)\n // Monthly frequency uses only month/year for the entire calendar month\n if (employeeFrequency !== 'monthly') {\n existingQuery['period.startDate'] = period.startDate;\n }\n\n let existingRecordQuery = this.models.PayrollRecordModel.findOne(existingQuery);\n if (mongooseSession) existingRecordQuery = existingRecordQuery.session(mongooseSession);\n const existingRecord = await existingRecordQuery;\n\n // Handle existing records based on status\n if (existingRecord) {\n // ✅ RETRY SAFETY: Only allow retry for truly failed operations\n // - 'paid'/'processing': Cannot retry (already completed/in-progress)\n // - 'voided': Cannot retry (intentionally cancelled, keep for audit)\n // - 'reversed': CAN re-process (was wrong, create new record, keep reversed for audit)\n // - 'pending' with transactionId: Cannot retry (has financial record)\n // - 'failed' with transactionId: Cannot retry (has orphaned transaction)\n // - 'failed' without transactionId: CAN retry (safe to delete and retry)\n\n if (existingRecord.status === 'paid' || existingRecord.status === 'processing') {\n throw new DuplicatePayrollError(employee.employeeId, month, year, payrollRunType);\n }\n\n if (existingRecord.status === 'voided') {\n throw new PayrollError(\n `Cannot re-process voided payroll for employee ${employee.employeeId} in ${month}/${year}. ` +\n `To re-process, first call restorePayroll() to restore the voided record to 'pending' status.`,\n 'VOIDED_PAYROLL_REPROCESS',\n 409,\n {\n status: existingRecord.status,\n reason: 'voided_requires_restore',\n suggestedAction: 'Call restorePayroll({ payrollRecordId }) first',\n existingRecordId: existingRecord._id.toString(),\n }\n );\n }\n\n // Reversed: Allow re-processing (create new record, keep reversed for audit trail)\n if (existingRecord.status === 'reversed') {\n getLogger().info('Creating new payroll after reversal', {\n reversedRecordId: existingRecord._id.toString(),\n employeeId: employee.employeeId,\n month,\n year,\n });\n // Continue to create new record - don't delete reversed, don't throw\n } else {\n // For pending or failed with transaction: cannot retry (would orphan transaction)\n if (existingRecord.transactionId) {\n throw new PayrollError(\n `Cannot retry ${existingRecord.status} payroll for employee ${employee.employeeId} in ${month}/${year} with existing transaction - would orphan financial records`,\n 'DUPLICATE_PAYROLL',\n 409,\n {\n status: existingRecord.status,\n transactionId: existingRecord.transactionId.toString(),\n reason: 'financial_record_orphan_prevention'\n }\n );\n }\n\n // Retry failed OR pending records without transactions (safe to delete)\n // These represent incomplete operations that can be safely retried\n if (existingRecord.status === 'failed' || existingRecord.status === 'pending') {\n getLogger().info('Removing incomplete record without transaction for retry', {\n recordId: existingRecord._id.toString(),\n status: existingRecord.status,\n employeeId: employee.employeeId,\n month,\n year,\n payrollRunType,\n });\n\n // Cascade delete related records (tax withholdings, etc.)\n await this.cascadeDeletePayrollRecord(existingRecord._id, mongooseSession);\n } else {\n // Unknown status without transaction - should not happen, but block for safety\n throw new PayrollError(\n `Cannot retry ${existingRecord.status} payroll for employee ${employee.employeeId} in ${month}/${year} - unexpected status`,\n 'DUPLICATE_PAYROLL',\n 409,\n { status: existingRecord.status, reason: 'unexpected_status' }\n );\n }\n }\n }\n\n // Period was calculated above (before duplicate check)\n const breakdown = await this.calculateSalaryBreakdownFn(employee, period, { attendance, options }, mongooseSession);\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 // SECURITY: Use resolved orgId, not employee.organizationId (could be stale/missing)\n // Routes through repository for multi-tenant plugin enforcement\n const payrollRecord = await repos.payrollRecord.create({\n organizationId: orgId,\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 // Payroll run type and related fields (v2.8.0+)\n payrollRunType,\n // Payment frequency at time of processing (v2.9.0+)\n // Stored for proper idempotency key reconstruction in void/reverse\n paymentFrequency: employeeFrequency,\n retroactiveAdjustment,\n employerContributions,\n }, mongooseSession ? { session: mongooseSession } : {}) as TPayrollRecord & PayrollRecordDocument;\n\n // Track for non-transactional cleanup\n createdPayrollRecordId = payrollRecord._id;\n\n // Aligned with @classytic/shared-types ITransactionCreateInput\n // Use employee's payment frequency for accurate transaction tags\n const frequency = employee.compensation.frequency || 'monthly';\n // SECURITY: Use resolved orgId, not employee.organizationId (could be stale/missing)\n // SECURITY: Use normalized userIdValue, not employee.userId (could be populated object)\n // Routes through repository for multi-tenant plugin enforcement\n const transaction = await repos.transaction!.create({\n organizationId: orgId,\n\n // Classification (shared-types)\n type: 'salary',\n flow: 'outflow',\n tags: ['recurring', 'payroll', frequency],\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 || this.config.payroll?.defaultCurrency || 'USD',\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: userIdValue, // Use normalized value (handles populated docs)\n processedBy: context?.userId ? toObjectId(context.userId) : undefined,\n\n // 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 // Include payrollRecordId to allow new transaction on re-processing after reversal\n idempotencyKey: `${idempotentKey}:${payrollRecord._id}`,\n\n // Timestamps (shared-types)\n processedAt: paymentDate,\n completedAt: paymentDate,\n\n // Description & metadata\n description: `Salary payment - ${getEmployeeName(employee)} (${month}/${year})`,\n notes: breakdown.proRatedAmount ? `Pro-rated: ${breakdown.actualDays}/${breakdown.workingDays} days` : undefined,\n metadata: {\n employeeId: employee.employeeId,\n email: getEmployeeEmail(employee),\n payrollRecordId: payrollRecord._id.toString(),\n },\n }, mongooseSession ? { session: mongooseSession } : {}) as TTransaction & { _id: mongoose.Types.ObjectId };\n\n // Track for non-transactional cleanup (preserve transaction reference on failure)\n createdTransactionId = transaction._id;\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(mongooseSession ? { session: mongooseSession } : {});\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 import('../types.js').AnyModel,\n this.events\n );\n\n // SECURITY: Use resolved orgId and normalized userIdValue (consistent with payroll/transaction)\n await taxService.createFromBreakdown({\n organizationId: orgId,\n employeeId: employee._id,\n employeeBusinessId: employee.employeeId,\n userId: userIdValue,\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: employee.compensation.currency || this.config.payroll?.defaultCurrency || 'USD',\n session: mongooseSession,\n context,\n });\n }\n\n // Update employee payroll stats\n await this.updatePayrollStatsFn(employee, breakdown.netSalary, paymentDate, repos, mongooseSession);\n\n // Emit event (transaction will be committed by withTransaction() or caller)\n // SECURITY: Use resolved orgId for consistent tenant scoping\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: orgId,\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 /**\n * NON-TRANSACTIONAL FALLBACK CLEANUP\n *\n * When running without transactions (standalone MongoDB), failures after\n * payroll record creation require cleanup. We mark as 'failed' rather than\n * delete to preserve the transactionId reference and prevent orphaning.\n *\n * Why mark as 'failed' instead of deleting:\n * 1. If transactionId exists, we preserve it on the payroll record\n * 2. The retry logic sees `existingRecord.transactionId` and blocks cascade-deletion\n * 3. This prevents orphaning financial transactions in the database\n * 4. Users can investigate failed records with transaction references\n *\n * Recovery guidance for operators:\n * - Records with 'failed' status AND transactionId need manual investigation\n * - Records with 'failed' status WITHOUT transactionId can be safely retried\n *\n * @see recoverStuckPayrolls() for automated recovery of stuck records\n */\n if (!session && createdPayrollRecordId) {\n try {\n // CRITICAL: Check current status before overwriting\n // If record is already 'paid' with a transaction, don't corrupt it\n const existingRecord = await this.models.PayrollRecordModel.findById(createdPayrollRecordId);\n\n if (existingRecord?.status === 'paid' && existingRecord?.transactionId) {\n // Record is already paid with transaction - do NOT mark as failed\n // This preserves ledger integrity when failure occurs after commit\n getLogger().warn('Payroll record already paid with transaction - not marking as failed', {\n payrollRecordId: createdPayrollRecordId.toString(),\n transactionId: existingRecord.transactionId.toString(),\n status: existingRecord.status,\n error: (error as Error).message,\n });\n } else {\n // Safe to mark as failed - record wasn't successfully paid\n const updateFields: Record<string, unknown> = { status: 'failed' };\n if (createdTransactionId) {\n updateFields.transactionId = createdTransactionId;\n }\n await repos.payrollRecord.update(\n createdPayrollRecordId,\n updateFields,\n { throwOnNotFound: false }\n );\n getLogger().warn('Marked payroll record as failed after non-transactional error', {\n payrollRecordId: createdPayrollRecordId.toString(),\n transactionId: createdTransactionId?.toString(),\n error: (error as Error).message,\n });\n }\n } catch (cleanupError) {\n // Log but don't mask the original error\n getLogger().error('Failed to mark payroll record as failed during cleanup', {\n payrollRecordId: createdPayrollRecordId.toString(),\n transactionId: createdTransactionId?.toString(),\n cleanupError: (cleanupError as Error).message,\n originalError: (error as Error).message,\n });\n }\n }\n\n // Let all errors propagate - transaction abort handled by withTransaction()\n // Duplicate key errors are handled OUTSIDE the transaction in processSalary()\n throw error;\n }\n }\n}\n\n/**\n * Factory function for creating SalaryProcessingManager\n *\n * Creates a salary processing manager with injected dependencies using\n * the dependency injection pattern to avoid tight coupling.\n *\n * @template TEmployee - Employee document type\n * @template TPayrollRecord - Payroll record document type\n * @template TTransaction - Transaction document type\n * @template TAttendance - Attendance document type\n *\n * @param models - Model instances for database access\n * @param container - Dependency container instance\n * @param events - Event bus for emitting payroll events\n * @param idempotency - Idempotency manager for duplicate prevention\n * @param repositoryManager - Repository manager for data access\n * @param calculateSalaryBreakdownFn - Function to calculate salary breakdown\n * @param resolveOrganizationIdFn - Function to resolve organization ID\n * @param resolveEmployeeIdFn - Function to resolve employee ID\n * @param findEmployeeFn - Function to find employee with security\n * @param updatePayrollStatsFn - Function to update employee payroll stats\n * @param config - HRM configuration\n *\n * @returns Configured salary processing manager instance\n *\n * @example\n * ```typescript\n * const manager = createSalaryProcessingManager(\n * { EmployeeModel, PayrollRecordModel, TransactionModel },\n * container,\n * eventBus,\n * idempotencyManager,\n * repositoryManager,\n * payroll.calculateSalaryBreakdown.bind(payroll),\n * payroll.resolveOrganizationId.bind(payroll),\n * payroll.resolveEmployeeId.bind(payroll),\n * payroll.findEmployee.bind(payroll),\n * payroll.updatePayrollStats.bind(payroll),\n * config\n * );\n * ```\n *\n * @see SalaryProcessingContext in managers/context.ts for context-based alternative\n */\nexport function createSalaryProcessingManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument\n>(\n models: {\n EmployeeModel: Model<TEmployee>;\n PayrollRecordModel: Model<TPayrollRecord>;\n TransactionModel: Model<TTransaction>;\n AttendanceModel?: Model<TAttendance> | null;\n LeaveRequestModel?: Model<LeaveRequestDocument> | null;\n TaxWithholdingModel?: TaxWithholdingModel | null;\n },\n container: Container<TEmployee, TPayrollRecord, TTransaction, TAttendance>,\n events: EventBus,\n idempotency: IdempotencyManager,\n repositoryManager: RepositoryManager<TEmployee, TPayrollRecord, TTransaction>,\n calculateSalaryBreakdownFn: (\n employee: EmployeeDocument,\n period: { month: number; year: number; startDate: Date; endDate: Date; payDate: Date },\n input?: { attendance?: import('../core/config.js').AttendanceInput | null; options?: import('../core/config.js').PayrollProcessingOptions },\n session?: ClientSession\n ) => Promise<import('../types.js').PayrollBreakdown>,\n resolveOrganizationIdFn: import('./context.js').ResolveOrganizationIdFn,\n resolveEmployeeIdFn: import('./context.js').ResolveEmployeeIdFn,\n findEmployeeFn: import('./context.js').FindEmployeeFn<TEmployee>,\n updatePayrollStatsFn: import('./context.js').UpdatePayrollStatsFn<TEmployee, TPayrollRecord, TTransaction>,\n config: import('../types.js').HRMConfig\n): SalaryProcessingManager<TEmployee, TPayrollRecord, TTransaction, TAttendance> {\n return new SalaryProcessingManager<TEmployee, TPayrollRecord, TTransaction, TAttendance>(\n models,\n container,\n events,\n idempotency,\n repositoryManager,\n calculateSalaryBreakdownFn,\n resolveOrganizationIdFn,\n resolveEmployeeIdFn,\n findEmployeeFn,\n updatePayrollStatsFn,\n config\n );\n}\n","/**\r\n * @classytic/payroll - Employee Type Guards\r\n *\r\n * Type-safe utilities for accessing employee properties,\r\n * especially for guest vs. regular employees.\r\n *\r\n * @module @classytic/payroll/utils/employee-type-guards\r\n */\r\n\r\nimport type { EmployeeDocument } from '../types.js';\r\n\r\n/**\r\n * Safely get email from employee (guest or regular)\r\n *\r\n * @param employee - Employee document\r\n * @returns Email address or undefined\r\n *\r\n * @example\r\n * ```typescript\r\n * const email = getEmployeeEmail(employee);\r\n * if (email) {\r\n * sendNotification(email, 'Payroll processed');\r\n * }\r\n * ```\r\n */\r\nexport function getEmployeeEmail(employee: EmployeeDocument): string | undefined {\r\n // Guest employee with direct email field\r\n if ('email' in employee && typeof employee.email === 'string') {\r\n return employee.email;\r\n }\r\n\r\n // Regular employee with userId populated\r\n if (employee.userId && typeof employee.userId === 'object' && 'email' in employee.userId) {\r\n return (employee.userId as { email?: string }).email;\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Get employee name (from userId if populated, fallback to employeeId)\r\n *\r\n * @param employee - Employee document\r\n * @returns Employee name or employee ID\r\n *\r\n * @example\r\n * ```typescript\r\n * const name = getEmployeeName(employee);\r\n * console.log(`Processing payroll for ${name}`);\r\n * ```\r\n */\r\nexport function getEmployeeName(employee: EmployeeDocument): string {\r\n if (employee.userId && typeof employee.userId === 'object' && 'name' in employee.userId) {\r\n const userName = (employee.userId as { name?: string }).name;\r\n if (userName) return userName;\r\n }\r\n\r\n return employee.employeeId;\r\n}\r\n\r\n/**\r\n * Check if employee is a guest employee (no userId)\r\n *\r\n * @param employee - Employee document\r\n * @returns True if guest employee\r\n *\r\n * @example\r\n * ```typescript\r\n * if (isGuestEmployee(employee)) {\r\n * // Handle guest-specific logic\r\n * }\r\n * ```\r\n */\r\nexport function isGuestEmployee(employee: EmployeeDocument): boolean {\r\n return !employee.userId;\r\n}\r\n\r\n/**\r\n * Get phone number from employee (userId or direct field)\r\n *\r\n * @param employee - Employee document\r\n * @returns Phone number or undefined\r\n */\r\nexport function getEmployeePhone(employee: EmployeeDocument): string | undefined {\r\n if (employee.userId && typeof employee.userId === 'object' && 'phone' in employee.userId) {\r\n return (employee.userId as { phone?: string }).phone;\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Type guard: Check if employee has a user ID\r\n *\r\n * @param employee - Employee document\r\n * @returns True if employee has userId (not guest)\r\n */\r\nexport function hasUserId(employee: EmployeeDocument): employee is EmployeeDocument & { userId: NonNullable<EmployeeDocument['userId']> } {\r\n return !!employee.userId;\r\n}\r\n\r\n/**\r\n * Safely get user ID (ObjectId) from employee\r\n *\r\n * @param employee - Employee document\r\n * @returns User ObjectId or undefined\r\n */\r\nexport function getEmployeeUserId(employee: EmployeeDocument): import('mongoose').Types.ObjectId | undefined {\r\n if (!employee.userId) return undefined;\r\n\r\n // userId can be ObjectId or populated user object\r\n if (typeof employee.userId === 'object' && '_id' in employee.userId) {\r\n return (employee.userId as { _id: import('mongoose').Types.ObjectId })._id;\r\n }\r\n\r\n return employee.userId as import('mongoose').Types.ObjectId;\r\n}\r\n","/**\n * @classytic/payroll - Bulk Operations Manager\n *\n * Handles bulk payroll processing with advanced features:\n * - Progress tracking\n * - Cancellation support\n * - Batch processing\n * - Concurrency control\n * - Streaming for large datasets (10k+ employees)\n */\n\nimport { Model } from 'mongoose';\nimport pLimit from 'p-limit';\nimport type {\n EmployeeDocument,\n PayrollRecordDocument,\n AnyDocument,\n ObjectId,\n ObjectIdLike,\n ProcessBulkPayrollParams,\n ProcessSalaryParams,\n ProcessSalaryResult,\n BulkPayrollResult,\n BulkPayrollProgress,\n PaymentMethod,\n OperationContext,\n} from '../types.js';\nimport type { ResolveOrganizationIdFn } from './context.js';\nimport type { PayrollProcessingOptions } from '../core/config.js';\nimport { getLogger } from '../utils/logger.js';\nimport { toObjectId } from '../utils/query-builders.js';\nimport type { EventBus } from '../core/events.js';\n\n/**\n * BulkOperationsManager\n *\n * Master of parallel processing - handles bulk payroll with enterprise features.\n * Automatically switches to streaming mode for large datasets (>10k employees).\n *\n * Key features:\n * - **Progress tracking**: Real-time progress callbacks\n * - **Cancellation**: AbortSignal support\n * - **Batch processing**: Configurable batch size\n * - **Concurrency control**: Limit parallel operations\n * - **Streaming**: Memory-efficient for millions of employees\n *\n * @example Basic usage\n * ```typescript\n * const manager = new BulkOperationsManager(...);\n * const result = await manager.processBulkPayroll({\n * organizationId,\n * month: 1,\n * year: 2024,\n * });\n * ```\n *\n * @example With progress tracking\n * ```typescript\n * await manager.processBulkPayroll({\n * organizationId,\n * month: 1,\n * year: 2024,\n * onProgress: (p) => console.log(`${p.percentage}% done`),\n * });\n * ```\n *\n * @example With concurrency control\n * ```typescript\n * await manager.processBulkPayroll({\n * organizationId,\n * month: 1,\n * year: 2024,\n * concurrency: 5, // Process 5 employees at a time\n * batchSize: 20, // 20 employees per batch\n * });\n * ```\n */\nexport class BulkOperationsManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument\n> {\n constructor(\n private readonly models: {\n EmployeeModel: Model<TEmployee>;\n PayrollRecordModel: Model<TPayrollRecord>;\n TransactionModel: Model<TTransaction>;\n AttendanceModel?: Model<TAttendance> | null;\n },\n private readonly events: EventBus,\n private readonly processSalaryFn: (params: ProcessSalaryParams) => Promise<ProcessSalaryResult<TEmployee, TPayrollRecord, TTransaction>>,\n private readonly resolveOrganizationIdFn: ResolveOrganizationIdFn\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 * @param params - Bulk payroll parameters\n * @returns Results with successful and failed employees\n */\n async processBulkPayroll(params: ProcessBulkPayrollParams): Promise<BulkPayrollResult> {\n const {\n organizationId: explicitOrgId,\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 maxResultDetails = Infinity,\n } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n // Also check context.organizationId for parity with processSalary\n const organizationId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n // Include both active and on_leave employees (matching single-employee eligibility)\n const query: Record<string, unknown> = { organizationId, status: { $in: ['active', 'on_leave'] } };\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 maxResultDetails,\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 successCount: 0,\n failCount: 0,\n totalAmount: 0,\n };\n\n // Helper to report progress\n const reportProgress = async (currentEmployee?: string) => {\n if (onProgress) {\n const processed = results.successCount + results.failCount;\n await onProgress({\n processed,\n total,\n successful: results.successCount,\n failed: results.failCount,\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.successCount + results.failCount,\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.processSalaryFn({\n employeeId: employee._id,\n organizationId,\n month,\n year,\n paymentDate,\n paymentMethod,\n options,\n context: { ...context, session: undefined },\n });\n\n const amount = result.payrollRecord.breakdown.netSalary;\n results.successCount++;\n results.totalAmount += amount;\n if (results.successful.length < maxResultDetails) {\n results.successful.push({\n employeeId: employee.employeeId,\n amount,\n transactionId: result.transaction._id,\n });\n }\n } catch (error) {\n results.failCount++;\n if (results.failed.length < maxResultDetails) {\n results.failed.push({\n employeeId: employee.employeeId,\n error: (error as Error).message,\n });\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) - respects concurrency limit\n const limit = pLimit(concurrency);\n const batchResults = await Promise.allSettled(\n batch.map((employee) =>\n limit(() =>\n this.processSalaryFn({\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\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 const amount = batchResult.value.result.payrollRecord.breakdown.netSalary;\n results.successCount++;\n results.totalAmount += amount;\n if (results.successful.length < maxResultDetails) {\n results.successful.push({\n employeeId: batchResult.value.employee.employeeId,\n amount,\n transactionId: batchResult.value.result.transaction._id,\n });\n }\n } else {\n results.failCount++;\n if (results.failed.length < maxResultDetails) {\n results.failed.push({\n employeeId: employee.employeeId,\n error: (batchResult.reason as Error).message || 'Unknown error',\n });\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.successCount,\n failed: results.failCount,\n totalAmount: results.totalAmount,\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.successCount,\n failed: results.failCount,\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 * This is the **enterprise-grade** solution for massive datasets.\n * Automatically used when >10k employees.\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?: PayrollProcessingOptions;\n context?: OperationContext;\n signal?: AbortSignal;\n batchSize: number;\n batchDelay: number;\n concurrency: number;\n onProgress?: (progress: BulkPayrollProgress) => void | Promise<void>;\n total: number;\n maxResultDetails: 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 maxResultDetails,\n } = params;\n\n const startTime = Date.now();\n const results: BulkPayrollResult = {\n successful: [],\n failed: [],\n total,\n successCount: 0,\n failCount: 0,\n totalAmount: 0,\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 // Concurrency control\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.successCount,\n failed: results.failCount,\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.processSalaryFn({\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 const amount = result.payrollRecord.breakdown.netSalary;\n results.successCount++;\n results.totalAmount += amount;\n if (results.successful.length < maxResultDetails) {\n results.successful.push({\n employeeId: employee.employeeId,\n amount,\n transactionId: result.transaction._id,\n });\n }\n } catch (error) {\n results.failCount++;\n if (results.failed.length < maxResultDetails) {\n results.failed.push({\n employeeId: employee.employeeId,\n error: (error as Error).message,\n });\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.successCount,\n failed: results.failCount,\n totalAmount: results.totalAmount,\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.successCount,\n failed: results.failCount,\n duration,\n concurrency,\n batchSize,\n });\n\n return results;\n }\n}\n\n/**\n * Factory function for creating BulkOperationsManager\n */\nexport function createBulkOperationsManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument,\n TAttendance extends AnyDocument = AnyDocument\n>(\n models: {\n EmployeeModel: Model<TEmployee>;\n PayrollRecordModel: Model<TPayrollRecord>;\n TransactionModel: Model<TTransaction>;\n AttendanceModel?: Model<TAttendance> | null;\n },\n events: EventBus,\n processSalaryFn: (params: ProcessSalaryParams) => Promise<ProcessSalaryResult<TEmployee, TPayrollRecord, TTransaction>>,\n resolveOrganizationIdFn: ResolveOrganizationIdFn\n): BulkOperationsManager<TEmployee, TPayrollRecord, TTransaction, TAttendance> {\n return new BulkOperationsManager<TEmployee, TPayrollRecord, TTransaction, TAttendance>(models, events, processSalaryFn, resolveOrganizationIdFn);\n}\n","/**\n * @classytic/payroll - Employee Operations Manager\n *\n * Handles the complete employee lifecycle:\n * - Hiring new employees\n * - Updating employment details\n * - Terminating employees\n * - Re-hiring terminated employees\n * - Employee retrieval and lookups\n */\n\nimport type { ClientSession } from 'mongoose';\nimport type {\n EmployeeDocument,\n PayrollRecordDocument,\n AnyDocument,\n LeaveRequestDocument,\n ObjectId,\n ObjectIdLike,\n HireEmployeeParams,\n UpdateEmploymentParams,\n TerminateEmployeeParams,\n ReHireEmployeeParams,\n OperationContext,\n} from '../types.js';\nimport { getLogger } from '../utils/logger.js';\nimport { ValidationError, EmployeeTerminatedError } from '../errors/index.js';\nimport type { EventBus } from '../core/events.js';\nimport type { HRMConfig } from '../types.js';\nimport type { PayrollRepositories } from '../types.js';\nimport type { FindEmployeeFn } from './context.js';\nimport type { RequestScopedServices } from './repository.manager.js';\n\n/**\n * EmployeeOperationsManager\n *\n * The master of employee lifecycle management. Handles all operations\n * from hiring to termination with proper validation and event emission.\n *\n * Key responsibilities:\n * - Employee onboarding (hire)\n * - Employment updates\n * - Employee termination\n * - Re-hiring terminated employees\n * - Employee retrieval\n *\n * @example Hiring an employee\n * ```typescript\n * const employee = await manager.hire({\n * organizationId,\n * userId: user._id,\n * employment: {\n * employeeId: 'EMP-001',\n * position: 'Software Engineer',\n * department: 'Engineering',\n * hireDate: new Date(),\n * },\n * compensation: {\n * baseAmount: 120000,\n * currency: 'USD',\n * type: 'salary',\n * payFrequency: 'monthly',\n * },\n * });\n * ```\n *\n * @example Terminating an employee\n * ```typescript\n * const terminated = await manager.terminate({\n * employeeId: 'EMP-001',\n * organizationId,\n * terminationDate: new Date(),\n * reason: 'resignation',\n * notes: 'Accepted position elsewhere',\n * });\n * ```\n */\nexport class EmployeeOperationsManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument\n> {\n constructor(\n private readonly events: EventBus,\n private readonly config: HRMConfig,\n private readonly resolveOrganizationIdFn: (providedOrgId?: ObjectIdLike) => ObjectId,\n private readonly findEmployeeFn: FindEmployeeFn<TEmployee>,\n private readonly getReposForRequestFn: (orgId: ObjectId) => PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>,\n private readonly getServicesForRequestFn: (repos: PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>) => RequestScopedServices<TEmployee, TPayrollRecord>\n ) {}\n\n /**\n * Hire a new employee\n */\n async hire(params: HireEmployeeParams): Promise<TEmployee> {\n const { userId, employment, compensation, bankDetails, context } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(params.organizationId);\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 // Create request-scoped repositories and services\n const repos = this.getReposForRequestFn(orgId);\n const services = this.getServicesForRequestFn(repos);\n\n const employee = await services.employee.create({\n userId,\n organizationId: orgId,\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 const { employeeId, employeeIdMode, organizationId: explicitOrgId, updates, context } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n const session = context?.session;\n\n // SECURE: Use secure lookup with organizationId isolation\n const employee = await this.findEmployeeFn({\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId: orgId,\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 const { employeeId, employeeIdMode, organizationId: explicitOrgId, terminationDate = new Date(), reason = 'resignation', notes, context } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n const session = context?.session;\n\n // SECURE: Use secure lookup with organizationId isolation\n const employee = await this.findEmployeeFn({\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId: orgId,\n session\n });\n\n // Create request-scoped repositories and services\n const repos = this.getReposForRequestFn(orgId);\n const services = this.getServicesForRequestFn(repos);\n\n // Use EmployeeService.terminate instead of document methods\n const terminated = await services.employee.terminate(\n employee._id,\n terminationDate,\n {\n session,\n reason,\n context\n }\n );\n\n // Add notes if provided\n if (notes) {\n const updatedNotes = (terminated.notes || '') + `\\nTermination: ${notes}`;\n await repos.employee.update(\n terminated._id,\n { notes: updatedNotes },\n { session }\n );\n }\n\n // Emit event\n this.events.emitSync('employee:terminated', {\n employee: {\n id: terminated._id,\n employeeId: terminated.employeeId,\n },\n terminationDate,\n reason,\n organizationId: terminated.organizationId,\n context,\n });\n\n getLogger().info('Employee terminated', {\n employeeId: terminated.employeeId,\n reason,\n });\n\n return terminated as TEmployee;\n }\n\n /**\n * Re-hire terminated employee\n */\n async reHire(params: ReHireEmployeeParams): Promise<TEmployee> {\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 // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n const session = context?.session;\n\n // SECURE: Use secure lookup with organizationId isolation\n const employee = await this.findEmployeeFn({\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId: orgId,\n session\n });\n\n // Create request-scoped repositories and services\n const repos = this.getReposForRequestFn(orgId);\n const services = this.getServicesForRequestFn(repos);\n\n // Use EmployeeService.reHire instead of document methods\n const rehired = await services.employee.reHire(\n employee._id,\n {\n session,\n context\n }\n );\n\n // Update position, department, and compensation if provided\n const updates: Record<string, unknown> = {};\n if (position) updates.position = position;\n if (department) updates.department = department;\n if (compensation) {\n updates.compensation = { ...rehired.compensation, ...compensation };\n }\n if (hireDate) updates.hireDate = hireDate;\n\n let updated = rehired;\n if (Object.keys(updates).length > 0) {\n updated = await repos.employee.update(\n rehired._id,\n updates,\n { session }\n );\n }\n\n // Emit event\n this.events.emitSync('employee:rehired', {\n employee: {\n id: updated._id,\n employeeId: updated.employeeId,\n position: updated.position,\n },\n organizationId: updated.organizationId,\n context,\n });\n\n getLogger().info('Employee re-hired', {\n employeeId: updated.employeeId,\n });\n\n return updated 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 const { employeeId, employeeIdMode, organizationId: explicitOrgId, populateUser = true, session, context } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n const employee = await this.findEmployeeFn({\n employeeId,\n employeeIdMode, // Explicit disambiguation if needed\n organizationId: orgId,\n session,\n populate: populateUser ? 'userId' : undefined\n });\n\n // No post-fetch validation needed - query-level filtering ensures organizational isolation\n return employee as TEmployee;\n }\n}\n\n/**\n * Factory function for creating EmployeeOperationsManager\n */\nexport function createEmployeeOperationsManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument\n>(\n events: EventBus,\n config: HRMConfig,\n resolveOrganizationIdFn: (providedOrgId?: ObjectIdLike) => ObjectId,\n findEmployeeFn: FindEmployeeFn<TEmployee>,\n getReposForRequestFn: (orgId: ObjectId) => PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>,\n getServicesForRequestFn: (repos: PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>) => RequestScopedServices<TEmployee, TPayrollRecord>\n): EmployeeOperationsManager<TEmployee, TPayrollRecord, TTransaction> {\n return new EmployeeOperationsManager(\n events,\n config,\n resolveOrganizationIdFn,\n findEmployeeFn,\n getReposForRequestFn,\n getServicesForRequestFn\n );\n}\n","/**\n * @classytic/payroll - Compensation Manager\n *\n * Handles all compensation-related operations:\n * - Salary updates\n * - Allowances (housing, transport, etc.)\n * - Deductions (loans, advances, etc.)\n * - Bank account details\n */\n\nimport type { ClientSession } from 'mongoose';\nimport type {\n EmployeeDocument,\n PayrollRecordDocument,\n AnyDocument,\n LeaveRequestDocument,\n ObjectId,\n ObjectIdLike,\n UpdateSalaryParams,\n AddAllowanceParams,\n RemoveAllowanceParams,\n AddDeductionParams,\n RemoveDeductionParams,\n UpdateBankDetailsParams,\n Compensation,\n Allowance,\n Deduction,\n} from '../types.js';\nimport { getLogger } from '../utils/logger.js';\nimport { EmployeeTerminatedError, ValidationError } from '../errors/index.js';\nimport type { EventBus } from '../core/events.js';\nimport type { PayrollRepositories } from '../types.js';\nimport { hasPluginMethod } from '../utils/validation.js';\nimport type { FindEmployeeFn, ResolveEmployeeIdFn } from './context.js';\nimport type { RequestScopedServices } from './repository.manager.js';\n\n/**\n * CompensationManager\n *\n * The master of compensation and benefits management. Handles salary\n * updates, allowances, deductions, and banking information.\n *\n * Key responsibilities:\n * - Base salary management\n * - Allowances (recurring/one-time, taxable/non-taxable)\n * - Deductions (manual/automatic)\n * - Bank account updates\n * - Event emission for audit trails\n *\n * @example Updating salary\n * ```typescript\n * const employee = await manager.updateSalary({\n * employeeId: 'EMP-001',\n * organizationId,\n * compensation: {\n * baseAmount: 150000,\n * currency: 'USD',\n * },\n * effectiveFrom: new Date('2024-01-01'),\n * });\n * ```\n *\n * @example Adding allowance\n * ```typescript\n * const employee = await manager.addAllowance({\n * employeeId: 'EMP-001',\n * organizationId,\n * type: 'housing',\n * amount: 2000,\n * recurring: true,\n * taxable: true,\n * });\n * ```\n */\nexport class CompensationManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument\n> {\n constructor(\n private readonly events: EventBus,\n private readonly resolveOrganizationIdFn: (providedOrgId?: ObjectIdLike) => ObjectId,\n private readonly resolveEmployeeIdFn: ResolveEmployeeIdFn,\n private readonly findEmployeeFn: FindEmployeeFn<TEmployee>,\n private readonly getReposForRequestFn: (orgId: ObjectId) => PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>,\n private readonly getServicesForRequestFn: (repos: PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>) => RequestScopedServices<TEmployee, TPayrollRecord>\n ) {}\n\n /**\n * Update employee salary/compensation\n */\n async updateSalary(params: UpdateSalaryParams): Promise<TEmployee> {\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, compensation, effectiveFrom = new Date(), context } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n // Resolve employeeId to ObjectId if it's a string business ID\n const resolvedEmployeeId = await this.resolveEmployeeIdFn(employeeId, employeeIdMode, orgId, context?.session);\n\n // Get old salary for event (before update)\n const oldEmployee = await this.findEmployeeFn({\n employeeId: resolvedEmployeeId,\n employeeIdMode: 'objectId', // We resolved it to ObjectId\n organizationId: orgId,\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 // Merge partial compensation update with existing compensation\n const updatedCompensation: Compensation = {\n ...oldEmployee.compensation,\n ...compensation,\n effectiveFrom,\n };\n\n // Create request-scoped repositories and services\n const repos = this.getReposForRequestFn(orgId);\n const services = this.getServicesForRequestFn(repos);\n\n const employee = await services.employee.updateCompensation(\n resolvedEmployeeId,\n updatedCompensation,\n { session: context?.session, context }\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 const { employeeId, employeeIdMode, organizationId: explicitOrgId, type, amount, isPercentage, value, taxable = true, recurring = true, effectiveFrom = new Date(), effectiveTo, context } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await this.findEmployeeFn({\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId: orgId,\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 const { employeeId, employeeIdMode, organizationId: explicitOrgId, type, context } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await this.findEmployeeFn({\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId: orgId,\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 ValidationError(`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 const { employeeId, employeeIdMode, organizationId: explicitOrgId, type, amount, isPercentage, value, auto = false, recurring = true, description, effectiveFrom = new Date(), effectiveTo, context } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await this.findEmployeeFn({\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId: orgId,\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 const { employeeId, employeeIdMode, organizationId: explicitOrgId, type, context } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await this.findEmployeeFn({\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId: orgId,\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 ValidationError(`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 const { employeeId, employeeIdMode, organizationId: explicitOrgId, bankDetails, context } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId || context?.organizationId);\n\n const session = context?.session;\n\n // ✅ SECURE: Use secure lookup with organizationId isolation\n const employee = await this.findEmployeeFn({\n employeeId, // Supports both ObjectId and string\n employeeIdMode, // Explicit disambiguation if needed\n organizationId: orgId,\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/**\n * Factory function for creating CompensationManager\n */\nexport function createCompensationManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument\n>(\n events: EventBus,\n resolveOrganizationIdFn: (providedOrgId?: ObjectIdLike) => ObjectId,\n resolveEmployeeIdFn: ResolveEmployeeIdFn,\n findEmployeeFn: FindEmployeeFn<TEmployee>,\n getReposForRequestFn: (orgId: ObjectId) => PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>,\n getServicesForRequestFn: (repos: PayrollRepositories<TEmployee, TPayrollRecord, LeaveRequestDocument, TTransaction>) => RequestScopedServices<TEmployee, TPayrollRecord>\n): CompensationManager<TEmployee, TPayrollRecord, TTransaction> {\n return new CompensationManager(\n events,\n resolveOrganizationIdFn,\n resolveEmployeeIdFn,\n findEmployeeFn,\n getReposForRequestFn,\n getServicesForRequestFn\n );\n}\n","/**\n * @classytic/payroll - Payroll History Manager\n *\n * Handles all payroll history and reporting operations:\n * - History queries with filters and pagination\n * - Summary statistics and aggregations\n * - Data export with audit tracking\n */\n\nimport mongoose, { Model, isValidObjectId } from 'mongoose';\nimport type {\n PayrollRecordDocument,\n EmployeeDocument,\n AnyDocument,\n ObjectId,\n ObjectIdLike,\n PayrollHistoryParams,\n PayrollSummaryParams,\n PayrollSummaryResult,\n} from '../types.js';\nimport { getLogger } from '../utils/logger.js';\nimport { payroll as payrollQuery, toObjectId } from '../utils/query-builders.js';\nimport type { EventBus } from '../core/events.js';\n\n/**\n * PayrollHistoryManager\n *\n * Master of payroll data queries and reporting. Handles history retrieval,\n * summary statistics, and data exports with proper security and audit trails.\n *\n * Key responsibilities:\n * - Payroll history queries (with filters and pagination)\n * - Summary statistics (gross, net, deductions, tax)\n * - Data export (with audit tracking)\n * - Multi-tenant security enforcement\n *\n * @example History query\n * ```typescript\n * const history = await manager.payrollHistory({\n * organizationId,\n * employeeId: 'EMP-001',\n * year: 2024,\n * status: 'paid',\n * pagination: { page: 1, limit: 20 }\n * });\n * ```\n *\n * @example Summary statistics\n * ```typescript\n * const summary = await manager.payrollSummary({\n * organizationId,\n * month: 1,\n * year: 2024\n * });\n * console.log(`Total paid: ${summary.totalNet}`);\n * ```\n *\n * @example Data export\n * ```typescript\n * const records = await manager.exportPayroll({\n * organizationId,\n * startDate: new Date('2024-01-01'),\n * endDate: new Date('2024-12-31')\n * });\n * ```\n */\nexport class PayrollHistoryManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument\n> {\n constructor(\n private readonly models: {\n EmployeeModel: Model<TEmployee>;\n PayrollRecordModel: Model<TPayrollRecord>;\n TransactionModel: Model<TTransaction>;\n },\n private readonly events: EventBus,\n private readonly resolveOrganizationIdFn: (providedOrgId?: ObjectIdLike) => ObjectId,\n private readonly findEmployeeFn: import('./context.js').FindEmployeeFn<TEmployee>\n ) {}\n\n /**\n * Get payroll history with filters and pagination\n *\n * Supports filtering by:\n * - Employee (by ID or business ID)\n * - Period (month, year)\n * - Status (paid, pending, etc.)\n * - Pagination (page, limit, sort)\n *\n * SECURITY: Always includes organizationId filter for multi-tenant isolation\n *\n * @param params - History query parameters\n * @returns Paginated payroll records with populated relations\n */\n async payrollHistory(params: PayrollHistoryParams): Promise<TPayrollRecord[]> {\n const { employeeId, employeeIdMode, organizationId: explicitOrgId, month, year, status, pagination = {} } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId);\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 const employee = await this.findEmployeeFn({\n employeeId,\n employeeIdMode,\n organizationId: orgId\n });\n resolvedEmployeeId = employee._id;\n }\n }\n\n // Build query with organizationId always included for security\n let queryBuilder = payrollQuery().forOrganization(orgId);\n if (resolvedEmployeeId) queryBuilder = queryBuilder.forEmployee(resolvedEmployeeId);\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 statistics\n *\n * Aggregates payroll data to provide:\n * - Total gross salary\n * - Total net salary\n * - Total deductions\n * - Total tax\n * - Employee count\n * - Status breakdown (paid, pending)\n *\n * @param params - Summary parameters (organization, period)\n * @returns Aggregated summary statistics\n */\n async payrollSummary(params: PayrollSummaryParams): Promise<PayrollSummaryResult> {\n const { organizationId: explicitOrgId, month, year } = params;\n\n // Resolve organizationId (required in multi-tenant, auto-inject in single-tenant)\n const orgId = this.resolveOrganizationIdFn(explicitOrgId);\n\n const query: Record<string, unknown> = { organizationId: orgId };\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\n/**\n * Factory function for creating PayrollHistoryManager\n */\nexport function createPayrollHistoryManager<\n TEmployee extends EmployeeDocument = EmployeeDocument,\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\n TTransaction extends AnyDocument = AnyDocument\n>(\n models: {\n EmployeeModel: Model<TEmployee>;\n PayrollRecordModel: Model<TPayrollRecord>;\n TransactionModel: Model<TTransaction>;\n },\n events: EventBus,\n resolveOrganizationIdFn: (providedOrgId?: ObjectIdLike) => ObjectId,\n findEmployeeFn: import('./context.js').FindEmployeeFn<TEmployee>\n): PayrollHistoryManager<TEmployee, TPayrollRecord, TTransaction> {\n return new PayrollHistoryManager<TEmployee, TPayrollRecord, TTransaction>(models, events, resolveOrganizationIdFn, findEmployeeFn);\n}\n","/**\r\n * @classytic/payroll - Payroll State Manager\r\n *\r\n * Handles all payroll state transitions and corrections:\r\n * - Void operations (for unpaid payrolls)\r\n * - Reverse operations (for paid payrolls with reversal transactions)\r\n * - Restore operations (undo void)\r\n */\r\n\r\nimport { Model } from 'mongoose';\r\nimport type {\r\n PayrollRecordDocument,\r\n AnyDocument,\r\n AnyModel,\r\n ObjectIdLike,\r\n VoidPayrollParams,\r\n VoidPayrollResult,\r\n ReversePayrollParams,\r\n ReversePayrollResult,\r\n RestorePayrollParams,\r\n RestorePayrollResult,\r\n TaxWithholdingDocument,\r\n TaxWithholdingModel,\r\n} from '../types.js';\r\nimport { getLogger } from '../utils/logger.js';\r\nimport { toObjectId } from '../utils/query-builders.js';\r\nimport { ValidationError, EmployeeNotFoundError } from '../errors/index.js';\r\nimport { PayrollStatusMachine } from '../core/payroll-states.js';\r\nimport { PAYROLL_STATUS, isVoidablePayrollStatus } from '../enums.js';\r\nimport type { EventBus } from '../core/events.js';\r\n\r\n/**\r\n * PayrollStateManager\r\n *\r\n * Master of payroll state transitions, corrections, and reversal operations.\r\n * Handles complex audit trail and compliance requirements for payroll modifications.\r\n *\r\n * Key responsibilities:\r\n * - Void unpaid payrolls (pending, processing, failed)\r\n * - Reverse paid payrolls (with offsetting transactions)\r\n * - Restore voided payrolls (undo void)\r\n * - State machine validation\r\n * - Audit trail maintenance\r\n * - Tax withholding coordination\r\n *\r\n * SECURITY: All operations enforce multi-tenant isolation via organizationId\r\n *\r\n * @example Void unpaid payroll\r\n * ```typescript\r\n * await manager.voidPayroll({\r\n * organizationId,\r\n * payrollRecordId,\r\n * reason: 'Test payroll - not intended for production',\r\n * voidTransaction: true\r\n * });\r\n * ```\r\n *\r\n * @example Reverse paid payroll\r\n * ```typescript\r\n * const result = await manager.reversePayroll({\r\n * organizationId,\r\n * payrollRecordId,\r\n * reason: 'Duplicate payment detected',\r\n * createReversalTransaction: true\r\n * });\r\n * console.log(`Created reversal: ${result.reversalTransaction._id}`);\r\n * ```\r\n *\r\n * @example Restore voided payroll\r\n * ```typescript\r\n * await manager.restorePayroll({\r\n * organizationId,\r\n * payrollRecordId,\r\n * reason: 'Voided in error, restoring'\r\n * });\r\n * ```\r\n */\r\nexport class PayrollStateManager<\r\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\r\n TTransaction extends AnyDocument = AnyDocument,\r\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument\r\n> {\r\n constructor(\r\n private readonly models: {\r\n PayrollRecordModel: Model<TPayrollRecord>;\r\n TransactionModel: Model<TTransaction> | null;\r\n TaxWithholdingModel?: Model<TTaxWithholding> | null;\r\n },\r\n private readonly events: EventBus\r\n ) {}\r\n\r\n /**\r\n * Void a payroll record (before payment)\r\n *\r\n * Use for payrolls that haven't been paid yet (pending, processing, failed).\r\n * Creates audit trail but doesn't create a reversal transaction.\r\n *\r\n * Features:\r\n * - State machine validation (only voidable statuses)\r\n * - Transaction cancellation (optional)\r\n * - Tax withholding cancellation\r\n * - Full audit trail\r\n *\r\n * @param params - Void parameters\r\n * @returns Void result with status flags\r\n * @throws ValidationError if payroll is already paid (use reversePayroll instead)\r\n */\r\n async voidPayroll(params: VoidPayrollParams): Promise<VoidPayrollResult> {\r\n const { organizationId, payrollRecordId, reason, context, voidTransaction = true } = params;\r\n const session = context?.session;\r\n\r\n if (!reason || reason.trim().length < 5) {\r\n throw new ValidationError('Void reason must be at least 5 characters');\r\n }\r\n\r\n // Find the payroll record with org isolation\r\n const payrollRecord = await this.models.PayrollRecordModel.findOne({\r\n _id: toObjectId(payrollRecordId),\r\n organizationId: toObjectId(organizationId),\r\n }).session(session || null);\r\n\r\n if (!payrollRecord) {\r\n throw new EmployeeNotFoundError(`Payroll record not found: ${payrollRecordId}`);\r\n }\r\n\r\n // Validate state transition using state machine\r\n const transition = PayrollStatusMachine.validateTransition(\r\n payrollRecord.status,\r\n PAYROLL_STATUS.VOIDED\r\n );\r\n if (!transition.success) {\r\n if (payrollRecord.status === PAYROLL_STATUS.PAID) {\r\n throw new ValidationError(\r\n `Cannot void a paid payroll. Use reversePayroll() instead.`\r\n );\r\n }\r\n throw new ValidationError(transition.error);\r\n }\r\n\r\n // Update payroll record\r\n payrollRecord.status = PAYROLL_STATUS.VOIDED;\r\n payrollRecord.isVoided = true;\r\n payrollRecord.voidedAt = new Date();\r\n payrollRecord.voidedBy = context?.userId ? toObjectId(context.userId) : undefined;\r\n payrollRecord.voidReason = reason;\r\n payrollRecord.notes = `${payrollRecord.notes || ''}\\n[VOIDED] ${reason}`.trim();\r\n\r\n await payrollRecord.save({ session });\r\n\r\n // Void associated transaction if requested\r\n let transactionVoided = false;\r\n if (voidTransaction && payrollRecord.transactionId && this.models.TransactionModel) {\r\n await this.models.TransactionModel.updateOne(\r\n { _id: payrollRecord.transactionId },\r\n {\r\n $set: {\r\n status: 'cancelled',\r\n notes: `Voided: ${reason}`,\r\n 'metadata.voidedAt': new Date(),\r\n 'metadata.voidedBy': context?.userId,\r\n },\r\n },\r\n { session }\r\n );\r\n transactionVoided = true;\r\n }\r\n\r\n // Void associated tax withholdings if TaxWithholdingModel is provided\r\n let taxWithholdingsVoided = 0;\r\n if (this.models.TaxWithholdingModel) {\r\n const { TaxWithholdingService } = await import('../services/tax-withholding.service.js');\r\n const taxService = new TaxWithholdingService(\r\n this.models.TaxWithholdingModel as unknown as TaxWithholdingModel,\r\n this.models.TransactionModel as AnyModel | undefined,\r\n this.events\r\n );\r\n\r\n const taxResult = await taxService.voidByPayrollRecord({\r\n payrollRecordId,\r\n organizationId,\r\n reason,\r\n voidedBy: context?.userId,\r\n session,\r\n });\r\n taxWithholdingsVoided = taxResult.voidedCount;\r\n }\r\n\r\n getLogger().info('Payroll voided', {\r\n payrollRecordId: payrollRecordId.toString(),\r\n organizationId: organizationId.toString(),\r\n reason,\r\n transactionVoided,\r\n taxWithholdingsVoided,\r\n });\r\n\r\n return {\r\n payrollRecord: payrollRecord as unknown as PayrollRecordDocument,\r\n transactionVoided,\r\n taxWithholdingsVoided,\r\n };\r\n }\r\n\r\n /**\r\n * Reverse a paid payroll\r\n *\r\n * Creates a reversal (negative) transaction to offset the original payment.\r\n * Required for compliance as it maintains a full audit trail.\r\n *\r\n * Features:\r\n * - State machine validation (only paid payrolls)\r\n * - Reversal transaction creation (negative amount)\r\n * - Original transaction metadata update\r\n * - Tax withholding cancellation\r\n * - Full audit trail\r\n *\r\n * @param params - Reversal parameters\r\n * @returns Reversal result with transaction details\r\n * @throws ValidationError if payroll is not paid (use voidPayroll instead)\r\n */\r\n async reversePayroll(params: ReversePayrollParams): Promise<ReversePayrollResult> {\r\n const { organizationId, payrollRecordId, reason, createReversalTransaction = true, paymentMethod = 'manual', context } = params;\r\n const session = context?.session;\r\n\r\n if (!reason || reason.trim().length < 5) {\r\n throw new ValidationError('Reversal reason must be at least 5 characters');\r\n }\r\n\r\n // Find the payroll record with org isolation\r\n const payrollRecord = await this.models.PayrollRecordModel.findOne({\r\n _id: toObjectId(payrollRecordId),\r\n organizationId: toObjectId(organizationId),\r\n }).session(session || null);\r\n\r\n if (!payrollRecord) {\r\n throw new EmployeeNotFoundError(`Payroll record not found: ${payrollRecordId}`);\r\n }\r\n\r\n // Validate state transition using state machine\r\n const transition = PayrollStatusMachine.validateTransition(\r\n payrollRecord.status,\r\n PAYROLL_STATUS.REVERSED\r\n );\r\n if (!transition.success) {\r\n if (isVoidablePayrollStatus(payrollRecord.status)) {\r\n throw new ValidationError(\r\n `Cannot reverse an unpaid payroll. Use voidPayroll() instead.`\r\n );\r\n }\r\n throw new ValidationError(transition.error);\r\n }\r\n\r\n // Validate breakdown exists before reversal (HRM compliance: must know exact amounts)\r\n if (!payrollRecord.breakdown) {\r\n throw new ValidationError(\r\n 'Cannot reverse payroll without breakdown data. Breakdown is required for audit trail.'\r\n );\r\n }\r\n\r\n const originalAmount = payrollRecord.breakdown.netSalary;\r\n const grossAmount = payrollRecord.breakdown.grossSalary;\r\n const taxAmount = payrollRecord.breakdown.taxAmount || 0;\r\n\r\n // Validate amounts are valid (prevent reversing $0 or negative amounts)\r\n if (grossAmount <= 0 || originalAmount <= 0) {\r\n throw new ValidationError(\r\n `Cannot reverse payroll with invalid amounts. Gross: ${grossAmount}, Net: ${originalAmount}`\r\n );\r\n }\r\n\r\n // Create reversal transaction (positive amount with inflow)\r\n let reversalTransaction: AnyDocument | undefined;\r\n let originalTx: AnyDocument | null = null;\r\n\r\n if (createReversalTransaction && this.models.TransactionModel) {\r\n // Get original transaction for reconciliation\r\n let currency = 'USD'; // Default fallback\r\n if (payrollRecord.transactionId) {\r\n originalTx = await this.models.TransactionModel.findById(payrollRecord.transactionId).session(session || null);\r\n if (originalTx) {\r\n if (originalTx.currency) {\r\n currency = originalTx.currency as string;\r\n }\r\n\r\n // Reconciliation check: warn if amounts don't match (allows 1 cent rounding difference)\r\n const amountDiff = Math.abs((originalTx.amount as number) - grossAmount);\r\n if (amountDiff > 0.01) {\r\n getLogger().warn('Reversal amount mismatch with original transaction', {\r\n payrollRecordId: payrollRecordId.toString(),\r\n originalTransactionAmount: originalTx.amount,\r\n breakdownGrossAmount: grossAmount,\r\n difference: amountDiff,\r\n });\r\n }\r\n }\r\n }\r\n\r\n const [created] = await (this.models.TransactionModel as Model<AnyDocument>).create([{\r\n organizationId: toObjectId(organizationId),\r\n\r\n // Classification (aligned with @classytic/shared-types)\r\n type: 'salary_reversal',\r\n flow: 'inflow', // Reversal is an inflow (money back)\r\n tags: ['reversal', 'payroll', 'correction'],\r\n status: 'completed',\r\n\r\n // Amounts (positive values - ITransaction requires amount >= 0)\r\n amount: Math.abs(grossAmount), // ✅ Ensure positive\r\n net: Math.abs(originalAmount), // ✅ Ensure positive\r\n currency,\r\n fee: 0,\r\n tax: Math.abs(payrollRecord.breakdown?.taxAmount || 0),\r\n\r\n // Payment (default: manual for reversals, configurable for different scenarios)\r\n method: paymentMethod,\r\n date: new Date(),\r\n\r\n // Parties\r\n employeeId: payrollRecord.employeeId,\r\n customerId: payrollRecord.userId,\r\n\r\n // References (correct field names per ITransaction)\r\n sourceId: payrollRecord._id,\r\n sourceModel: 'PayrollRecord',\r\n relatedTransactionId: payrollRecord.transactionId,\r\n\r\n // Metadata\r\n description: `Payroll Reversal: ${reason}`,\r\n metadata: {\r\n originalPayrollId: payrollRecord._id,\r\n originalTransactionId: payrollRecord.transactionId,\r\n reversalReason: reason,\r\n reversedBy: context?.userId,\r\n reversedAt: new Date(),\r\n employeeId: payrollRecord.employeeId,\r\n period: payrollRecord.period,\r\n },\r\n }], session ? { session } : {});\r\n\r\n reversalTransaction = created;\r\n\r\n // Link reversal transaction to original payroll\r\n payrollRecord.reversalTransactionId = reversalTransaction._id;\r\n }\r\n\r\n // Update payroll record\r\n payrollRecord.status = PAYROLL_STATUS.REVERSED;\r\n payrollRecord.isVoided = true;\r\n payrollRecord.voidedAt = new Date();\r\n payrollRecord.voidedBy = context?.userId ? toObjectId(context.userId) : undefined;\r\n payrollRecord.voidReason = reason;\r\n payrollRecord.reversedAt = new Date();\r\n payrollRecord.reversedBy = context?.userId ? toObjectId(context.userId) : undefined;\r\n payrollRecord.reversalReason = reason;\r\n payrollRecord.notes = `${payrollRecord.notes || ''}\\n[REVERSED] ${reason}`.trim();\r\n\r\n await payrollRecord.save({ session });\r\n\r\n // Update original transaction if it exists\r\n if (payrollRecord.transactionId && this.models.TransactionModel) {\r\n await this.models.TransactionModel.updateOne(\r\n { _id: payrollRecord.transactionId },\r\n {\r\n $set: {\r\n 'metadata.reversed': true,\r\n 'metadata.reversedAt': new Date(),\r\n 'metadata.reversedBy': context?.userId,\r\n 'metadata.reversalTransactionId': reversalTransaction?._id,\r\n 'metadata.reversalReason': reason,\r\n },\r\n },\r\n { session }\r\n );\r\n }\r\n\r\n // Cancel associated tax withholdings if TaxWithholdingModel is provided\r\n let taxWithholdingsCancelled = 0;\r\n if (this.models.TaxWithholdingModel) {\r\n const { TaxWithholdingService } = await import('../services/tax-withholding.service.js');\r\n const taxService = new TaxWithholdingService(\r\n this.models.TaxWithholdingModel as unknown as TaxWithholdingModel,\r\n this.models.TransactionModel as AnyModel | undefined,\r\n this.events\r\n );\r\n\r\n const taxResult = await taxService.voidByPayrollRecord({\r\n payrollRecordId,\r\n organizationId,\r\n reason: `Payroll reversed: ${reason}`,\r\n voidedBy: context?.userId,\r\n session,\r\n });\r\n taxWithholdingsCancelled = taxResult.voidedCount;\r\n }\r\n\r\n getLogger().info('Payroll reversed', {\r\n payrollRecordId: payrollRecordId.toString(),\r\n organizationId: organizationId.toString(),\r\n reason,\r\n reversalTransactionId: reversalTransaction?._id?.toString(),\r\n taxWithholdingsCancelled,\r\n });\r\n\r\n return {\r\n payrollRecord: payrollRecord as unknown as PayrollRecordDocument,\r\n reversalTransaction,\r\n taxWithholdingsCancelled,\r\n };\r\n }\r\n\r\n /**\r\n * Restore a voided payroll\r\n *\r\n * Only works for voided payrolls (not reversed ones, as they have financial transactions).\r\n *\r\n * Features:\r\n * - State machine validation (only voided payrolls)\r\n * - Prevents restoring reversed payrolls (would orphan reversal transaction)\r\n * - Transaction restoration\r\n * - Audit trail preservation (keeps void metadata)\r\n *\r\n * @param params - Restore parameters\r\n * @returns Restored payroll record\r\n * @throws ValidationError if payroll is reversed or has reversal transaction\r\n */\r\n async restorePayroll(params: RestorePayrollParams): Promise<RestorePayrollResult> {\r\n const { organizationId, payrollRecordId, reason, context } = params;\r\n const session = context?.session;\r\n\r\n if (!reason || reason.trim().length < 5) {\r\n throw new ValidationError('Restore reason must be at least 5 characters');\r\n }\r\n\r\n // Find the payroll record with org isolation\r\n const payrollRecord = await this.models.PayrollRecordModel.findOne({\r\n _id: toObjectId(payrollRecordId),\r\n organizationId: toObjectId(organizationId),\r\n }).session(session || null);\r\n\r\n if (!payrollRecord) {\r\n throw new EmployeeNotFoundError(`Payroll record not found: ${payrollRecordId}`);\r\n }\r\n\r\n // Validate state transition using state machine\r\n const transition = PayrollStatusMachine.validateTransition(\r\n payrollRecord.status,\r\n PAYROLL_STATUS.PENDING\r\n );\r\n if (!transition.success) {\r\n if (payrollRecord.status === PAYROLL_STATUS.REVERSED) {\r\n throw new ValidationError(\r\n 'Cannot restore a reversed payroll. The reversal transaction would become orphaned.'\r\n );\r\n }\r\n throw new ValidationError(transition.error);\r\n }\r\n\r\n // Cannot restore if there's a reversal transaction\r\n if (payrollRecord.reversalTransactionId) {\r\n throw new ValidationError(\r\n 'Cannot restore a payroll with reversal transaction. The transaction would become orphaned.'\r\n );\r\n }\r\n\r\n // Check if an active (non-voided) record already exists for this period\r\n // This can happen if a replacement payroll was created after voiding the original\r\n const existingActive = await this.models.PayrollRecordModel.findOne({\r\n organizationId: toObjectId(organizationId),\r\n employeeId: payrollRecord.employeeId,\r\n 'period.month': payrollRecord.period.month,\r\n 'period.year': payrollRecord.period.year,\r\n payrollRunType: payrollRecord.payrollRunType,\r\n isVoided: { $ne: true },\r\n _id: { $ne: payrollRecord._id },\r\n }).session(session || null);\r\n\r\n if (existingActive) {\r\n throw new ValidationError(\r\n `Cannot restore: An active payroll record already exists for employee ${payrollRecord.employeeId} ` +\r\n `in ${payrollRecord.period.month}/${payrollRecord.period.year} with run type '${payrollRecord.payrollRunType}'. ` +\r\n `Void or reverse the existing record first.`\r\n );\r\n }\r\n\r\n // Restore to pending status\r\n payrollRecord.status = PAYROLL_STATUS.PENDING;\r\n payrollRecord.isVoided = false;\r\n payrollRecord.notes = `${payrollRecord.notes || ''}\\n[RESTORED] ${reason || 'Restored by user'}`.trim();\r\n\r\n // Keep voidedAt/voidedBy/voidReason for audit trail\r\n\r\n await payrollRecord.save({ session });\r\n\r\n // Restore associated transaction if exists\r\n if (payrollRecord.transactionId && this.models.TransactionModel) {\r\n await this.models.TransactionModel.updateOne(\r\n { _id: payrollRecord.transactionId },\r\n {\r\n $set: {\r\n status: 'pending',\r\n 'metadata.restoredAt': new Date(),\r\n 'metadata.restoredBy': context?.userId,\r\n },\r\n $unset: {\r\n 'metadata.voidedAt': '',\r\n 'metadata.voidedBy': '',\r\n },\r\n },\r\n { session }\r\n );\r\n }\r\n\r\n getLogger().info('Payroll restored', {\r\n payrollRecordId: payrollRecordId.toString(),\r\n organizationId: organizationId.toString(),\r\n reason,\r\n });\r\n\r\n return {\r\n payrollRecord: payrollRecord as unknown as PayrollRecordDocument,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Factory function for creating PayrollStateManager\r\n */\r\nexport function createPayrollStateManager<\r\n TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument,\r\n TTransaction extends AnyDocument = AnyDocument,\r\n TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument\r\n>(\r\n models: {\r\n PayrollRecordModel: Model<TPayrollRecord>;\r\n TransactionModel: Model<TTransaction> | null;\r\n TaxWithholdingModel?: Model<TTaxWithholding> | null;\r\n },\r\n events: EventBus\r\n): PayrollStateManager<TPayrollRecord, TTransaction, TTaxWithholding> {\r\n return new PayrollStateManager<TPayrollRecord, TTransaction, TTaxWithholding>(models, events);\r\n}\r\n","/**\n * Transaction Interface\n * @classytic/payroll\n *\n * Payroll uses the unified transaction interface from @classytic/shared-types\n * so revenue and payroll share a single cashflow event model.\n */\n\nimport type {\n ITransaction,\n ITransactionCreateInput,\n} from '@classytic/shared-types';\n\nimport { isTransaction } from '@classytic/shared-types';\n\n/**\n * Core transaction interface expected by payroll package\n * Apps must provide a Transaction model with AT LEAST these fields\n */\nexport type IPayrollTransaction = ITransaction;\n\n/**\n * Transaction write input (what payroll package creates)\n */\nexport type IPayrollTransactionCreateInput = ITransactionCreateInput;\n\n/**\n * Type guard to check if object is a Transaction\n */\nexport function isPayrollTransaction(obj: unknown): obj is IPayrollTransaction {\n return isTransaction(obj) && typeof obj === 'object' && obj !== null && 'employeeId' in obj;\n}\n","/**\r\n * @classytic/payroll - Timeline Audit Integration\r\n *\r\n * Integration with @classytic/mongoose-timeline-audit for comprehensive audit trails.\r\n * Provides automatic tracking of WHO performed WHAT action and WHEN.\r\n *\r\n * ## Setup\r\n *\r\n * 1. Install mongoose-timeline-audit:\r\n * ```bash\r\n * npm install @classytic/mongoose-timeline-audit\r\n * ```\r\n *\r\n * 2. Apply to your schemas BEFORE registering with Mongoose:\r\n * ```typescript\r\n * import timelineAuditPlugin from '@classytic/mongoose-timeline-audit';\r\n * import { PAYROLL_EVENTS } from '@classytic/payroll';\r\n *\r\n * // Apply to Employee schema\r\n * employeeSchema.plugin(timelineAuditPlugin, {\r\n * ownerField: 'organizationId',\r\n * eventLimits: PAYROLL_EVENTS.EMPLOYEE.limits,\r\n * });\r\n *\r\n * // Apply to PayrollRecord schema\r\n * payrollRecordSchema.plugin(timelineAuditPlugin, {\r\n * ownerField: 'organizationId',\r\n * eventLimits: PAYROLL_EVENTS.PAYROLL.limits,\r\n * });\r\n * ```\r\n *\r\n * 3. Use the Payroll events to add timeline entries:\r\n * ```typescript\r\n * payroll.on('employee:hired', async ({ data }) => {\r\n * const employee = await Employee.findById(data.employee.id);\r\n * employee.addTimelineEvent(\r\n * PAYROLL_EVENTS.EMPLOYEE.HIRED,\r\n * `Hired as ${data.employee.position}`,\r\n * request, // Express request for actor tracking\r\n * { department: data.employee.department }\r\n * );\r\n * await employee.save();\r\n * });\r\n * ```\r\n *\r\n * @module @classytic/payroll/timeline-audit\r\n */\r\n\r\n// ============================================================================\r\n// Payroll Event Constants\r\n// ============================================================================\r\n\r\n/**\r\n * Standard payroll events for timeline tracking\r\n *\r\n * Use these constants with mongoose-timeline-audit's addTimelineEvent()\r\n * to maintain consistent event naming across your application.\r\n */\r\nexport const PAYROLL_EVENTS = {\r\n /**\r\n * Employee lifecycle events\r\n */\r\n EMPLOYEE: {\r\n /** Employee was hired */\r\n HIRED: 'employee.hired',\r\n /** Employee was terminated */\r\n TERMINATED: 'employee.terminated',\r\n /** Employee was re-hired after termination */\r\n REHIRED: 'employee.rehired',\r\n /** Employee status changed (active, on_leave, suspended) */\r\n STATUS_CHANGED: 'employee.status_changed',\r\n /** Employee department/position changed */\r\n ROLE_CHANGED: 'employee.role_changed',\r\n /** Employee probation ended */\r\n PROBATION_ENDED: 'employee.probation_ended',\r\n\r\n /** Recommended event limits for employee timeline */\r\n limits: {\r\n 'employee.status_changed': 50,\r\n 'employee.role_changed': 20,\r\n },\r\n },\r\n\r\n /**\r\n * Compensation events\r\n */\r\n COMPENSATION: {\r\n /** Base salary was updated */\r\n SALARY_UPDATED: 'compensation.salary_updated',\r\n /** Allowance was added */\r\n ALLOWANCE_ADDED: 'compensation.allowance_added',\r\n /** Allowance was removed */\r\n ALLOWANCE_REMOVED: 'compensation.allowance_removed',\r\n /** Deduction was added */\r\n DEDUCTION_ADDED: 'compensation.deduction_added',\r\n /** Deduction was removed */\r\n DEDUCTION_REMOVED: 'compensation.deduction_removed',\r\n /** Bank details were updated */\r\n BANK_UPDATED: 'compensation.bank_updated',\r\n\r\n /** Recommended event limits */\r\n limits: {\r\n 'compensation.salary_updated': 24, // 2 years of monthly updates\r\n 'compensation.allowance_added': 20,\r\n 'compensation.allowance_removed': 20,\r\n 'compensation.deduction_added': 20,\r\n 'compensation.deduction_removed': 20,\r\n 'compensation.bank_updated': 10,\r\n },\r\n },\r\n\r\n /**\r\n * Payroll processing events\r\n */\r\n PAYROLL: {\r\n /** Salary was processed */\r\n PROCESSED: 'payroll.processed',\r\n /** Payroll was voided (before payment) */\r\n VOIDED: 'payroll.voided',\r\n /** Payroll was reversed (after payment) */\r\n REVERSED: 'payroll.reversed',\r\n /** Payroll was restored from voided state */\r\n RESTORED: 'payroll.restored',\r\n /** Payroll export was generated */\r\n EXPORTED: 'payroll.exported',\r\n\r\n /** Recommended event limits */\r\n limits: {\r\n 'payroll.processed': 36, // 3 years of monthly payroll\r\n 'payroll.voided': 10,\r\n 'payroll.reversed': 10,\r\n 'payroll.restored': 5,\r\n 'payroll.exported': 20,\r\n },\r\n },\r\n\r\n /**\r\n * Tax withholding events\r\n */\r\n TAX: {\r\n /** Tax was withheld */\r\n WITHHELD: 'tax.withheld',\r\n /** Tax was submitted to authorities */\r\n SUBMITTED: 'tax.submitted',\r\n /** Tax payment was made */\r\n PAID: 'tax.paid',\r\n /** Tax withholding was cancelled */\r\n CANCELLED: 'tax.cancelled',\r\n\r\n /** Recommended event limits */\r\n limits: {\r\n 'tax.withheld': 36,\r\n 'tax.submitted': 12,\r\n 'tax.paid': 12,\r\n 'tax.cancelled': 10,\r\n },\r\n },\r\n\r\n /**\r\n * Leave management events\r\n */\r\n LEAVE: {\r\n /** Leave was requested */\r\n REQUESTED: 'leave.requested',\r\n /** Leave was approved */\r\n APPROVED: 'leave.approved',\r\n /** Leave was rejected */\r\n REJECTED: 'leave.rejected',\r\n /** Leave was cancelled */\r\n CANCELLED: 'leave.cancelled',\r\n /** Leave balance was accrued */\r\n ACCRUED: 'leave.accrued',\r\n /** Annual leave was reset */\r\n RESET: 'leave.reset',\r\n\r\n /** Recommended event limits */\r\n limits: {\r\n 'leave.requested': 50,\r\n 'leave.approved': 50,\r\n 'leave.rejected': 20,\r\n 'leave.cancelled': 20,\r\n 'leave.accrued': 12,\r\n 'leave.reset': 5,\r\n },\r\n },\r\n} as const;\r\n\r\n/**\r\n * All payroll event types (for TypeScript)\r\n */\r\nexport type PayrollTimelineEvent =\r\n | typeof PAYROLL_EVENTS.EMPLOYEE[keyof typeof PAYROLL_EVENTS.EMPLOYEE]\r\n | typeof PAYROLL_EVENTS.COMPENSATION[keyof typeof PAYROLL_EVENTS.COMPENSATION]\r\n | typeof PAYROLL_EVENTS.PAYROLL[keyof typeof PAYROLL_EVENTS.PAYROLL]\r\n | typeof PAYROLL_EVENTS.TAX[keyof typeof PAYROLL_EVENTS.TAX]\r\n | typeof PAYROLL_EVENTS.LEAVE[keyof typeof PAYROLL_EVENTS.LEAVE];\r\n\r\n// ============================================================================\r\n// Timeline Audit Plugin Configuration\r\n// ============================================================================\r\n\r\n/**\r\n * Recommended timeline audit configuration for Employee model\r\n */\r\nexport const EMPLOYEE_TIMELINE_CONFIG = {\r\n ownerField: 'organizationId',\r\n fieldName: 'timeline',\r\n hideByDefault: true, // Don't include timeline in normal queries\r\n eventLimits: {\r\n ...PAYROLL_EVENTS.EMPLOYEE.limits,\r\n ...PAYROLL_EVENTS.COMPENSATION.limits,\r\n },\r\n};\r\n\r\n/**\r\n * Recommended timeline audit configuration for PayrollRecord model\r\n */\r\nexport const PAYROLL_RECORD_TIMELINE_CONFIG = {\r\n ownerField: 'organizationId',\r\n fieldName: 'timeline',\r\n hideByDefault: true,\r\n eventLimits: PAYROLL_EVENTS.PAYROLL.limits,\r\n};\r\n\r\n/**\r\n * Recommended timeline audit configuration for LeaveRequest model\r\n */\r\nexport const LEAVE_REQUEST_TIMELINE_CONFIG = {\r\n ownerField: 'organizationId',\r\n fieldName: 'timeline',\r\n hideByDefault: true,\r\n eventLimits: PAYROLL_EVENTS.LEAVE.limits,\r\n};\r\n\r\n// ============================================================================\r\n// Helper Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Build timeline event metadata from payroll context\r\n *\r\n * @param context - Operation context from payroll methods\r\n * @returns Metadata object for timeline event\r\n *\r\n * @example\r\n * ```typescript\r\n * employee.addTimelineEvent(\r\n * PAYROLL_EVENTS.EMPLOYEE.HIRED,\r\n * 'Hired as Software Engineer',\r\n * request,\r\n * buildTimelineMetadata(params.context)\r\n * );\r\n * ```\r\n */\r\nexport function buildTimelineMetadata(context?: {\r\n userId?: unknown;\r\n userName?: string;\r\n userRole?: string;\r\n organizationId?: unknown;\r\n}): Record<string, unknown> {\r\n if (!context) return {};\r\n\r\n const result: Record<string, unknown> = {};\r\n\r\n if (context.userId) {\r\n result.performedByUserId = String(context.userId);\r\n }\r\n if (context.userName) {\r\n result.performedByName = context.userName;\r\n }\r\n if (context.userRole) {\r\n result.performedByRole = context.userRole;\r\n }\r\n if (context.organizationId) {\r\n result.organizationId = String(context.organizationId);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Build context object for timeline event (IP, user agent, etc.)\r\n *\r\n * @param request - Express/Fastify request object\r\n * @returns Context object for timeline event\r\n *\r\n * @example\r\n * ```typescript\r\n * employee.addTimelineEvent(\r\n * PAYROLL_EVENTS.COMPENSATION.SALARY_UPDATED,\r\n * `Salary updated to ${newSalary}`,\r\n * request,\r\n * { previousSalary, newSalary },\r\n * buildRequestContext(request)\r\n * );\r\n * ```\r\n */\r\nexport function buildRequestContext(request?: {\r\n ip?: string;\r\n headers?: Record<string, string | string[] | undefined>;\r\n get?: (header: string) => string | undefined;\r\n}): Record<string, unknown> | undefined {\r\n if (!request) return undefined;\r\n\r\n const getHeader = (name: string): string | undefined => {\r\n if (request.get) return request.get(name);\r\n if (request.headers) {\r\n const value = request.headers[name.toLowerCase()];\r\n return Array.isArray(value) ? value[0] : value;\r\n }\r\n return undefined;\r\n };\r\n\r\n return {\r\n ip: request.ip || getHeader('x-forwarded-for'),\r\n userAgent: getHeader('user-agent'),\r\n origin: getHeader('origin'),\r\n };\r\n}\r\n\r\nexport default {\r\n PAYROLL_EVENTS,\r\n EMPLOYEE_TIMELINE_CONFIG,\r\n PAYROLL_RECORD_TIMELINE_CONFIG,\r\n LEAVE_REQUEST_TIMELINE_CONFIG,\r\n buildTimelineMetadata,\r\n buildRequestContext,\r\n};\r\n","/**\n * @classytic/payroll\n *\n * Enterprise-grade HRM and Payroll Management for MongoDB/Mongoose\n * One clear way: Payroll class + schemas + utilities\n *\n * ## Public API\n *\n * - **Payroll class**: Single entry point with full org isolation\n * - **Schemas, Types, Utilities**: For extending and customizing\n *\n * All services (Employee, Payroll, Compensation, Leave, TaxWithholding) are\n * internal-only. Use Payroll class methods for multi-tenant safe operations.\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Main API (Payroll Class - Single Entry Point)\n// ============================================================================\n\n/**\n * The Payroll class is the ONLY way to interact with payroll operations.\n * All employee, payroll, compensation, leave, and tax operations go through\n * this orchestrated API with built-in multi-tenant isolation.\n */\nexport {\n Payroll,\n PayrollBuilder,\n createPayrollInstance,\n} from './payroll.js';\n\n// ============================================================================\n// Types (common)\n// ============================================================================\n\nexport type {\n // Core types\n ObjectIdLike,\n AnyDocument,\n AnyModel,\n DeepPartial,\n Nullable,\n FilterQuery,\n\n // Configuration types\n PayrollInitConfig,\n HRMConfig,\n SingleTenantConfig,\n OperationContext,\n PayrollInstance,\n Logger,\n DataRetentionConfig,\n PayrollConfig,\n SalaryConfig,\n EmploymentConfig,\n ValidationConfig,\n EmployeeIdentityMode,\n EmployeeIdMode,\n TaxBracket,\n TaxCalculationOptions,\n PreTaxDeductionInput,\n TaxCreditInput,\n SalaryBandRange,\n RoleMappingConfig,\n\n // Document types\n EmployeeDocument,\n PayrollRecordDocument,\n\n // Sub-document / Schema types\n Compensation,\n BankDetails,\n Allowance,\n Deduction,\n WorkSchedule,\n PayrollStats,\n PayrollPeriod,\n PayrollBreakdown,\n PayrollCorrection,\n EmploymentHistoryEntry,\n UserReference,\n\n // Enum types\n AllowanceType,\n DeductionType,\n EmploymentType,\n EmployeeStatus,\n Department,\n TerminationReason,\n PaymentMethod,\n PayrollStatus,\n PaymentFrequency,\n SalaryBand,\n OrgRole,\n HRMTransactionCategory,\n LeaveType,\n LeaveRequestStatus,\n\n // Leave types\n LeaveBalance,\n LeaveRequestDocument,\n RequestLeaveInput,\n ReviewLeaveRequestInput,\n LeaveHistoryFilters,\n LeaveInitConfig,\n LeaveSummaryResult,\n WorkingDaysOptions,\n AccrueLeaveOptions,\n ResetAnnualLeaveOptions,\n\n // Operation parameter types\n EmployeeOperationParams, // v2.3.0: Base interface for all employee operations\n HireEmployeeParams,\n GetEmployeeParams, // v2.3.0: Includes organizationId, employeeIdMode\n UpdateEmploymentParams,\n TerminateEmployeeParams,\n ReHireEmployeeParams,\n UpdateSalaryParams,\n AddAllowanceParams,\n RemoveAllowanceParams,\n AddDeductionParams,\n RemoveDeductionParams,\n UpdateBankDetailsParams,\n ProcessSalaryParams,\n ProcessBulkPayrollParams,\n PayrollHistoryParams,\n PayrollSummaryParams,\n ExportPayrollParams,\n\n // Void / Reversal types (v2.4.0+)\n VoidPayrollParams,\n ReversePayrollParams,\n RestorePayrollParams,\n VoidPayrollResult,\n ReversePayrollResult,\n RestorePayrollResult,\n\n // Result types\n ProcessSalaryResult,\n BulkPayrollResult,\n BulkPayrollProgress,\n PayrollSummaryResult,\n TaxCalculationResult,\n CompensationBreakdownResult,\n\n // Plugin types (legacy - prefer PayrollPluginDefinition)\n PayrollPlugin,\n PluginFunction,\n PluginType,\n\n // Event types\n PayrollEvent,\n EventPayloadBase,\n EmployeeHiredEvent,\n SalaryProcessedEvent,\n EventPayload,\n\n // Error types\n ErrorCode,\n HttpError,\n\n // Utility types\n PayPeriodInfo,\n EmployeeValidationResult,\n QueryOptions,\n PayrollEmployee,\n WithPayroll,\n} from './types.js';\n\n// ============================================================================\n// TRANSACTION INTERFACE (aligned with @classytic/shared-types)\n// ============================================================================\n\n/**\n * Use @classytic/shared-types for transaction interfaces\n * This ensures alignment between payroll and revenue packages\n * \n * import type { ITransaction, ITransactionCreateInput } from '@classytic/shared-types';\n */\n\nexport type {\n IPayrollTransaction,\n IPayrollTransactionCreateInput,\n} from './types/transaction.interface.js';\n\nexport {\n isPayrollTransaction,\n} from './types/transaction.interface.js';\n\n// Transaction factory for creating consistent transactions\nexport {\n createPayrollTransaction,\n createTaxPaymentTransaction,\n TransactionFactory,\n type CreatePayrollTransactionInput,\n type CreateTaxPaymentTransactionInput,\n} from './factories/transaction.factory.js';\n\n// ============================================================================\n// Idempotency & Webhooks (Stripe-level features)\n// ============================================================================\n\nexport {\n IdempotencyManager,\n generatePayrollIdempotencyKey,\n type IdempotentResult,\n} from './core/idempotency.js';\n\nexport {\n WebhookManager,\n type WebhookConfig,\n type WebhookDelivery,\n} from './core/webhooks.js';\n\n// ============================================================================\n// Repository Plugins (Mongokit Integration - v2.4.0+)\n// ============================================================================\n\nexport {\n multiTenantPlugin,\n} from './core/repository-plugins.js';\n\n// ============================================================================\n// Plugin System (v2.4.0+)\n// ============================================================================\n\nexport {\n type PayrollPluginDefinition,\n type PluginContext,\n type PluginHooks,\n definePlugin,\n} from './core/plugin.js';\n\n// ============================================================================\n// Timeline Audit Integration (@classytic/mongoose-timeline-audit)\n// ============================================================================\n\nexport {\n PAYROLL_EVENTS,\n type PayrollTimelineEvent,\n EMPLOYEE_TIMELINE_CONFIG,\n PAYROLL_RECORD_TIMELINE_CONFIG,\n LEAVE_REQUEST_TIMELINE_CONFIG,\n buildTimelineMetadata,\n buildRequestContext,\n} from './core/timeline-audit.js';\n\n// ============================================================================\n// State Machines (v2.4.0+)\n// ============================================================================\n\nexport {\n // State machine utility\n StateMachine,\n createStateMachine,\n type StateMachineConfig,\n type StateTransition,\n type TransitionResult,\n // Status-specific state machines\n PayrollStatusMachine,\n TaxStatusMachine,\n LeaveRequestStatusMachine,\n EmployeeStatusMachine,\n // State types\n type PayrollStatusState,\n type TaxStatusState,\n type LeaveRequestStatusState,\n type EmployeeStatusState,\n} from './core/payroll-states.js';\n\n// ============================================================================\n// Enums / Constants (common)\n// ============================================================================\n\nexport {\n EMPLOYMENT_TYPE,\n EMPLOYEE_STATUS,\n DEPARTMENT,\n PAYMENT_FREQUENCY,\n ALLOWANCE_TYPE,\n DEDUCTION_TYPE,\n PAYROLL_STATUS,\n TERMINATION_REASON,\n LEAVE_TYPE,\n LEAVE_REQUEST_STATUS,\n isValidLeaveType,\n isPaidLeaveType,\n isValidLeaveRequestStatus,\n isPendingLeaveStatus,\n isApprovedLeaveStatus,\n // Payroll status helpers (v2.4.0+)\n isVoidablePayrollStatus,\n requiresReversalPayrollStatus,\n isVoidedOrReversedStatus,\n} from './enums.js';\n\n// ============================================================================\n// Configuration (optional)\n// ============================================================================\n\nexport {\n HRM_CONFIG,\n mergeConfig,\n determineOrgRole,\n} from './config.js';\n\n// ============================================================================\n// Schemas (required)\n// ============================================================================\n\nexport {\n // Schema options (multi-tenant / multi-branch flexibility)\n type PayrollSchemaOptions,\n // Sub-schemas\n allowanceSchema,\n deductionSchema,\n compensationSchema,\n workScheduleSchema,\n bankDetailsSchema,\n employmentHistorySchema,\n payrollStatsSchema,\n // Configurable field creators (for multi-branch/tenant setups)\n createEmploymentFields,\n createPayrollRecordFields,\n // Index helpers\n employeeIndexes,\n payrollRecordIndexes,\n applyEmployeeIndexes,\n applyPayrollRecordIndexes,\n // Schema factory functions\n createEmployeeSchema,\n createPayrollRecordSchema,\n // Leave schemas (utilities only - model exports are below)\n leaveBalanceSchema,\n leaveBalanceFields,\n leaveRequestIndexes,\n applyLeaveRequestIndexes,\n getLeaveRequestFields,\n} from './schemas/index.js';\n\n// ============================================================================\n// Plugins (recommended)\n// ============================================================================\n\nexport {\n employeePlugin,\n type EmployeePluginOptions,\n} from './plugins/index.js';\n\n// ============================================================================\n// Factories (data builders)\n// ============================================================================\n\nexport {\n EmployeeFactory,\n EmployeeBuilder,\n createEmployee,\n} from './factories/employee.factory.js';\n\nexport type {\n CreateEmployeeParams,\n EmployeeData,\n TerminationData,\n} from './factories/employee.factory.js';\n\n// ============================================================================\n// Errors\n// ============================================================================\n\nexport {\n PayrollError,\n NotInitializedError,\n EmployeeNotFoundError,\n InvalidEmployeeError,\n DuplicatePayrollError,\n NotEligibleError,\n EmployeeTerminatedError,\n AlreadyProcessedError,\n ValidationError,\n SecurityError,\n createError,\n isPayrollError,\n extractErrorInfo,\n toPayrollError,\n} from './errors/index.js';\n\n// ============================================================================\n// Attendance (ClockIn integration)\n// ============================================================================\n\nexport {\n getAttendance,\n batchGetAttendance,\n} from './attendance.js';\n\n// ============================================================================\n// Holidays\n// ============================================================================\n\nexport {\n createHolidaySchema,\n getHolidays,\n type Holiday,\n} from './holidays.js';\n\n// ============================================================================\n// Leave Management\n// ============================================================================\n\nexport {\n leaveRequestSchema,\n getLeaveRequestModel,\n type LeaveRequestModel,\n} from './models/index.js';\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} from './utils/index.js';\n\n// ============================================================================\n// Leave Service (INTERNAL ONLY - NOT EXPORTED)\n// ============================================================================\n\n// LeaveService is internal-only. Use Payroll class leave methods:\n// payroll.requestLeave(), payroll.reviewLeaveRequest(),\n// payroll.cancelLeaveRequest(), payroll.getLeaveHistory()\n\n// ============================================================================\n// Pure Calculators\n// ============================================================================\n\n/**\n * @since v2.3.0\n * Pure calculation functions with no database dependencies.\n * \n * Perfect for:\n * - Client-side salary previews\n * - Testing without DB setup\n * - Microservices/serverless\n * - Documentation examples\n * \n * All calculators are pure (no side effects) and can run in browser.\n */\nexport {\n // Salary breakdown calculator (main)\n calculateSalaryBreakdown,\n type SalaryCalculationInput,\n type ProcessedAllowance,\n type ProcessedDeduction,\n\n // Pro-rating calculator\n calculateProRating,\n applyProRating,\n shouldProRate,\n type ProRatingInput,\n type ProRatingResult,\n\n // Attendance deduction calculator\n calculateAttendanceDeduction,\n calculateDailyRate,\n calculateHourlyRate,\n calculatePartialDayDeduction,\n calculateTotalAttendanceDeduction,\n type AttendanceDeductionInput,\n type AttendanceDeductionResult,\n} from './calculators/index.js';\n\n// ============================================================================\n// Shift Compliance (NEW)\n// ============================================================================\n\nexport {\n // Main calculator\n calculateShiftCompliance,\n\n // Individual calculators (for advanced usage)\n calculateLatePenalty,\n calculateOvertimeBonus,\n\n // Granular calculation functions\n calculateFlatPenalty,\n calculatePerMinutePenalty,\n calculatePercentagePenalty,\n calculateTieredPenalty,\n calculateDailyOvertime,\n calculateWeeklyOvertime,\n calculateMonthlyOvertime,\n calculateWeekendPremium,\n calculateNightShiftDifferential,\n\n // Preset policies\n createPolicyFromPreset,\n DEFAULT_ATTENDANCE_POLICY,\n MANUFACTURING_POLICY,\n RETAIL_POLICY,\n OFFICE_POLICY,\n HEALTHCARE_POLICY,\n HOSPITALITY_POLICY,\n\n // Fluent builders\n AttendancePolicyBuilder,\n createLatePolicyBuilder,\n createOvertimePolicyBuilder,\n createClockRoundingPolicyBuilder,\n LatePolicyBuilder,\n TieredPenaltyBuilder,\n OvertimePolicyBuilder,\n ClockRoundingPolicyBuilder,\n\n // Mongoose schemas (optional)\n AttendancePolicySchema,\n AttendancePolicySchemaDefinition,\n LateArrivalPolicySchema,\n LateArrivalPolicySchemaDefinition,\n EarlyDeparturePolicySchema,\n EarlyDeparturePolicySchemaDefinition,\n OvertimePolicySchema,\n OvertimePolicySchemaDefinition,\n ClockRoundingPolicySchema,\n ClockRoundingPolicySchemaDefinition,\n PenaltyTierSchema,\n PenaltyTierSchemaDefinition,\n MaxPenaltiesSchema,\n MaxPenaltiesSchemaDefinition,\n WeekendPremiumSchema,\n WeekendPremiumSchemaDefinition,\n NightShiftDifferentialSchema,\n NightShiftDifferentialSchemaDefinition,\n\n // Main types\n type AttendancePolicy,\n type ShiftComplianceData,\n type ShiftComplianceResult,\n type CalculateShiftComplianceInput,\n\n // Policy types\n type LateArrivalPolicy,\n type EarlyDeparturePolicy,\n type OvertimePolicy,\n type ClockRoundingPolicy,\n\n // Mode and configuration types\n type PenaltyMode,\n type OvertimeMode,\n type ResetPeriod,\n type RoundingMode,\n\n // Supporting types\n type PenaltyTier,\n type MaxPenaltiesPerPeriod,\n type WeekendPremium,\n type NightShiftDifferential,\n\n // Occurrence types\n type LateOccurrence,\n type EarlyOccurrence,\n type OvertimeOccurrence,\n\n // Result types\n type LatePenaltyResult,\n type EarlyDeparturePenaltyResult,\n type OvertimeBonusResult,\n type ShiftDifferentialResult,\n\n // Manager override types\n type PenaltyOverride,\n\n // Schema model interfaces\n type AttendancePolicyDocument,\n type AttendancePolicyModel,\n} from './shift-compliance/index.js';\n\n// ============================================================================\n// Tax Withholding\n// ============================================================================\n\nexport type {\n TaxWithholdingDocument,\n TaxType,\n TaxStatus,\n GetPendingTaxParams,\n TaxSummaryParams,\n TaxSummaryResult,\n TaxSummaryByType,\n MarkTaxPaidParams,\n} from './types.js';\n\nexport {\n TAX_TYPE,\n TAX_STATUS,\n TAX_TYPE_VALUES,\n TAX_STATUS_VALUES,\n isValidTaxType,\n isValidTaxStatus,\n isPendingTaxStatus,\n isPaidTaxStatus,\n isCancelledTaxStatus,\n} from './enums.js';\n\nexport {\n taxWithholdingSchema,\n getTaxWithholdingModel,\n type TaxWithholdingModel,\n} from './models/index.js';\n\nexport {\n taxWithholdingIndexes,\n applyTaxWithholdingIndexes,\n getTaxWithholdingFields,\n} from './schemas/index.js';\n\n// ============================================================================\n// Tax Withholding Service (INTERNAL ONLY - NOT EXPORTED)\n// ============================================================================\n\n// TaxWithholdingService is internal-only. Use Payroll class methods:\n// payroll.getPendingTaxWithholdings(), payroll.getTaxSummary(),\n// payroll.markTaxWithholdingsPaid()\n\n// ============================================================================\n// Security Utilities (Multi-Tenant Isolation)\n// ============================================================================\n\n/**\n * @since v2.3.0\n * Secure employee lookup utilities that enforce organizationId isolation\n */\nexport {\n findEmployeeSecure,\n employeeExistsSecure,\n findEmployeesSecure,\n requireOrganizationId,\n type SecureEmployeeLookupOptions,\n} from './utils/index.js';\n\n/**\n * @since v2.3.0\n * Smart organization ID resolution with priority chain\n */\nexport {\n resolveOrganizationId,\n validateOrganizationId,\n tryResolveOrganizationId,\n type ResolveOrganizationIdParams,\n type ContainerLike,\n} from './utils/index.js';\n\n/**\n * @since v2.3.0\n * Dual identity system (ObjectId _id + string employeeId)\n */\nexport {\n detectEmployeeIdType,\n normalizeEmployeeId,\n isStringEmployeeId,\n isObjectIdEmployeeId,\n formatEmployeeId,\n type EmployeeIdType,\n type EmployeeQueryFilter,\n} from './utils/index.js';\n\n// ============================================================================\n// Type Guards & Error Helpers (DX Utilities)\n// ============================================================================\n\n/**\n * @since v2.7.0\n * Type-safe error checking and employee type guards.\n * Also available from '@classytic/payroll/utils'.\n */\nexport {\n isMongoError,\n isDuplicateKeyError,\n parseDuplicateKeyError,\n isTransactionError,\n isTransactionUnsupportedError,\n isConnectionError,\n isGuestEmployee,\n hasUserId,\n isValidationError,\n isError,\n getErrorMessage,\n} from './utils/type-guards.js';\n\nexport {\n getEmployeeEmail,\n getEmployeeName,\n} from './utils/employee-type-guards.js';\n\n/**\n * @since v2.7.5\n * Higher-level error handling utilities for common payroll scenarios.\n */\nexport {\n handleTransactionError,\n handleDuplicateKeyError,\n handlePayrollError,\n formatUserError,\n type TransactionErrorResult,\n type DuplicateKeyErrorResult,\n type PayrollErrorResult,\n} from './utils/error-helpers.js';\n\n// ============================================================================\n// Mongokit Audit Plugins\n// ============================================================================\n\n/**\n * @since v2.7.0\n * Repository plugins for audit trail tracking.\n */\nexport {\n payrollAuditPlugin,\n readAuditPlugin,\n fullAuditPlugin,\n type AuditContext,\n type AuditEvent,\n} from './core/mongokit-plugins/index.js';\n","/**\n * @classytic/payroll - Mongoose Schemas\n *\n * Reusable schema definitions for employee and payroll models\n * Can be spread into your own schemas\n */\n\nimport { Schema, type SchemaDefinition, type Types } from 'mongoose';\nimport {\n EMPLOYMENT_TYPE_VALUES,\n EMPLOYEE_STATUS_VALUES,\n DEPARTMENT_VALUES,\n PAYMENT_FREQUENCY_VALUES,\n ALLOWANCE_TYPE_VALUES,\n DEDUCTION_TYPE_VALUES,\n TERMINATION_REASON_VALUES,\n PAYROLL_STATUS_VALUES,\n PAYMENT_METHOD_VALUES,\n} from '../enums.js';\nimport { HRM_CONFIG } from '../config.js';\nimport { periodSchema } from './common.js';\n\n// ============================================================================\n// Schema Options (Multi-Tenant / Multi-Branch Flexibility)\n// ============================================================================\n\n/**\n * Options for configuring schema references.\n *\n * Use these to customize what collection `organizationId` references.\n * This supports multi-branch, multi-tenant, or any other hierarchy structure.\n *\n * @example\n * ```typescript\n * // Multi-branch setup (one company, multiple branches)\n * const employeeSchema = createEmployeeSchema({}, {\n * organizationRef: 'Branch',\n * });\n *\n * // Multi-tenant SaaS\n * const employeeSchema = createEmployeeSchema({}, {\n * organizationRef: 'Tenant',\n * });\n *\n * // Enterprise with workspaces\n * const employeeSchema = createEmployeeSchema({}, {\n * organizationRef: 'Workspace',\n * });\n * ```\n */\nexport interface PayrollSchemaOptions {\n /**\n * The collection name that `organizationId` references.\n *\n * This is used for Mongoose's `populate()` feature. The multi-tenant\n * plugin filters by the ObjectId value regardless of what collection\n * it references.\n *\n * @default 'Organization'\n *\n * @example 'Branch' | 'Company' | 'Tenant' | 'Workspace' | 'Team'\n */\n organizationRef?: string;\n\n /**\n * The collection name that `userId` references.\n *\n * @default 'User'\n */\n userRef?: string;\n}\n\n// ============================================================================\n// Sub-Schemas\n// ============================================================================\n\n/**\n * Allowance schema definition\n */\nexport const allowanceSchema = new Schema(\n {\n type: {\n type: String,\n enum: ALLOWANCE_TYPE_VALUES,\n required: true,\n },\n name: { type: String },\n amount: { type: Number, required: true, min: 0 },\n isPercentage: { type: Boolean, default: false },\n value: { type: Number },\n taxable: { type: Boolean, default: true },\n recurring: { type: Boolean, default: true },\n effectiveFrom: { type: Date, default: () => new Date() },\n effectiveTo: { type: Date },\n },\n { _id: false }\n);\n\n/**\n * Deduction schema definition\n */\nexport const deductionSchema = new Schema(\n {\n type: {\n type: String,\n enum: DEDUCTION_TYPE_VALUES,\n required: true,\n },\n name: { type: String },\n amount: { type: Number, required: true, min: 0 },\n isPercentage: { type: Boolean, default: false },\n value: { type: Number },\n auto: { type: Boolean, default: false },\n recurring: { type: Boolean, default: true },\n effectiveFrom: { type: Date, default: () => new Date() },\n effectiveTo: { type: Date },\n description: { type: String },\n },\n { _id: false }\n);\n\n/**\n * Compensation schema definition\n */\nexport const compensationSchema = new Schema(\n {\n baseAmount: { type: Number, required: true, min: 0 },\n frequency: {\n type: String,\n enum: PAYMENT_FREQUENCY_VALUES,\n default: 'monthly',\n },\n currency: { type: String }, // No default - use config or USD fallback in application logic\n allowances: [allowanceSchema],\n deductions: [deductionSchema],\n grossSalary: { type: Number, default: 0 },\n netSalary: { type: Number, default: 0 },\n effectiveFrom: { type: Date, default: () => new Date() },\n lastModified: { type: Date, default: () => new Date() },\n },\n { _id: false }\n);\n\n/**\n * Work schedule schema definition\n */\nexport const workScheduleSchema = new Schema(\n {\n hoursPerWeek: { type: Number, min: 0, max: 168 },\n hoursPerDay: { type: Number, min: 0, max: 24 },\n workingDays: [{ type: Number, min: 0, max: 6 }],\n shiftStart: { type: String },\n shiftEnd: { type: String },\n },\n { _id: false }\n);\n\n/**\n * Bank details schema definition\n */\nexport const bankDetailsSchema = new Schema(\n {\n accountName: { type: String },\n accountNumber: { type: String },\n bankName: { type: String },\n branchName: { type: String },\n routingNumber: { type: String },\n },\n { _id: false }\n);\n\n/**\n * Employment history entry schema\n */\nexport const employmentHistorySchema = new Schema(\n {\n hireDate: { type: Date, required: true },\n terminationDate: { type: Date, required: true },\n reason: { type: String, enum: TERMINATION_REASON_VALUES },\n finalSalary: { type: Number },\n position: { type: String },\n department: { type: String },\n notes: { type: String },\n },\n { timestamps: true }\n);\n\n/**\n * Payroll stats schema (pre-calculated)\n */\nexport const payrollStatsSchema = new Schema(\n {\n totalPaid: { type: Number, default: 0, min: 0 },\n lastPaymentDate: { type: Date },\n nextPaymentDate: { type: Date },\n paymentsThisYear: { type: Number, default: 0, min: 0 },\n averageMonthly: { type: Number, default: 0, min: 0 },\n updatedAt: { type: Date, default: () => new Date() },\n },\n { _id: false }\n);\n\n// ============================================================================\n// Employment Fields (Spread into Employee Schema)\n// ============================================================================\n\n/**\n * Employment fields to spread into your Employee schema.\n * Use `createEmploymentFields()` for configurable references.\n */\n/**\n * Create employment fields with configurable references.\n *\n * @param options - Schema options for configuring references\n * @returns SchemaDefinition for employment fields\n */\nexport function createEmploymentFields(options: PayrollSchemaOptions = {}): SchemaDefinition {\n const { organizationRef = 'Organization', userRef = 'User' } = options;\n\n return {\n userId: {\n type: Schema.Types.ObjectId,\n ref: userRef,\n required: false, // Allow guest employees (no user account)\n },\n email: {\n type: String,\n trim: true,\n lowercase: true,\n required: false, // For guest employees without user account\n },\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: organizationRef, // Configurable: 'Branch', 'Company', 'Tenant', etc.\n required: true,\n },\n employeeId: { type: String, required: true },\n employmentType: {\n type: String,\n enum: EMPLOYMENT_TYPE_VALUES,\n default: 'full_time',\n },\n status: {\n type: String,\n enum: EMPLOYEE_STATUS_VALUES,\n default: 'active',\n },\n department: { type: String, enum: DEPARTMENT_VALUES },\n position: { type: String, required: true },\n hireDate: { type: Date, required: true },\n terminationDate: { type: Date },\n probationEndDate: { type: Date },\n employmentHistory: [employmentHistorySchema],\n compensation: { type: compensationSchema, required: true },\n workSchedule: workScheduleSchema,\n bankDetails: bankDetailsSchema,\n payrollStats: { type: payrollStatsSchema, default: () => ({}) },\n };\n}\n\n\n// ============================================================================\n// Payroll Record Sub-Schemas\n// ============================================================================\n\n/**\n * Payroll breakdown schema\n */\nexport const payrollBreakdownSchema = new Schema(\n {\n baseAmount: { type: Number, required: true, min: 0 },\n allowances: [\n {\n type: { type: String, required: true },\n amount: { type: Number, required: true, min: 0 },\n taxable: { type: Boolean, default: true },\n },\n ],\n deductions: [\n {\n type: { type: String, required: true },\n amount: { type: Number, required: true, min: 0 },\n description: { type: String },\n },\n ],\n grossSalary: { type: Number, required: true, min: 0 },\n netSalary: { type: Number, required: true, min: 0 },\n taxableAmount: { type: Number, default: 0, min: 0 },\n taxAmount: { type: Number, default: 0, min: 0 },\n workingDays: { type: Number, min: 0 },\n actualDays: { type: Number, min: 0 },\n proRatedAmount: { type: Number, default: 0, min: 0 },\n attendanceDeduction: { type: Number, default: 0, min: 0 },\n overtimeAmount: { type: Number, default: 0, min: 0 },\n bonusAmount: { type: Number, default: 0, min: 0 },\n },\n { _id: false }\n);\n\n/**\n * Payroll period schema (imported from common to avoid circular dependencies)\n * Re-exported for external use\n */\nexport { periodSchema };\n\n/**\n * Create payroll record fields with configurable references.\n *\n * @param options - Schema options for configuring references\n * @returns SchemaDefinition for payroll record fields\n */\nexport function createPayrollRecordFields(options: PayrollSchemaOptions = {}): SchemaDefinition {\n const { organizationRef = 'Organization', userRef = 'User' } = options;\n\n return {\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: organizationRef, // Configurable: 'Branch', 'Company', 'Tenant', etc.\n required: true,\n },\n employeeId: {\n type: Schema.Types.ObjectId,\n required: true,\n },\n userId: {\n type: Schema.Types.ObjectId,\n ref: userRef,\n required: false, // Optional for guest employees\n },\n period: { type: periodSchema, required: true },\n breakdown: { type: payrollBreakdownSchema, required: true },\n transactionId: { type: Schema.Types.ObjectId },\n status: {\n type: String,\n enum: PAYROLL_STATUS_VALUES,\n default: 'pending',\n },\n paidAt: { type: Date },\n processedAt: { type: Date },\n paymentMethod: { type: String, enum: PAYMENT_METHOD_VALUES },\n metadata: { type: Schema.Types.Mixed },\n processedBy: { type: Schema.Types.ObjectId, ref: userRef },\n notes: { type: String },\n payslipUrl: { type: String },\n exported: { type: Boolean, default: false },\n exportedAt: { type: Date },\n // Void / Reversal fields (v2.4.0+)\n isVoided: { type: Boolean, default: false },\n voidedAt: { type: Date },\n voidedBy: { type: Schema.Types.ObjectId, ref: userRef },\n voidReason: { type: String },\n reversedAt: { type: Date },\n reversedBy: { type: Schema.Types.ObjectId, ref: userRef },\n reversalReason: { type: String },\n reversalTransactionId: { type: Schema.Types.ObjectId },\n originalPayrollId: { type: Schema.Types.ObjectId },\n // TTL expiration (per-document)\n expireAt: { type: Date },\n\n // Payroll run type (v2.8.0+)\n payrollRunType: {\n type: String,\n enum: ['regular', 'off-cycle', 'supplemental', 'retroactive'],\n default: 'regular',\n },\n\n // Payment frequency at time of processing (v2.9.0+)\n // Stored for proper idempotency key reconstruction in void/reverse operations\n paymentFrequency: {\n type: String,\n enum: PAYMENT_FREQUENCY_VALUES,\n default: 'monthly',\n },\n\n // Retroactive adjustment details (v2.8.0+)\n retroactiveAdjustment: {\n type: new Schema(\n {\n originalPeriod: {\n month: { type: Number, required: true, min: 1, max: 12 },\n year: { type: Number, required: true },\n },\n originalPayrollId: { type: Schema.Types.ObjectId },\n reason: { type: String, required: true },\n adjustmentAmount: { type: Number, required: true },\n approved: { type: Boolean },\n approvedBy: { type: Schema.Types.ObjectId },\n approvedAt: { type: Date },\n },\n { _id: false }\n ),\n required: false,\n },\n\n // Employer contributions (v2.8.0+)\n employerContributions: [\n {\n type: {\n type: String,\n enum: ['social_security', 'pension', 'unemployment', 'health_insurance', 'other'],\n required: true,\n },\n amount: { type: Number, required: true },\n description: { type: String },\n mandatory: { type: Boolean },\n referenceNumber: { type: String },\n },\n ],\n\n // Corrections history (v2.8.0+)\n corrections: [\n {\n previousAmount: { type: Number },\n newAmount: { type: Number },\n reason: { type: String },\n correctedBy: { type: Schema.Types.ObjectId, ref: userRef },\n correctedAt: { type: Date, default: Date.now },\n },\n ],\n };\n}\n\n\n// ============================================================================\n// Index Definitions\n// ============================================================================\n\n/**\n * Recommended indexes for Employee schema\n */\nexport const employeeIndexes = [\n { fields: { organizationId: 1, employeeId: 1 }, options: { unique: true } },\n // Partial unique index: Only includes docs with userId field (excludes guest employees)\n // Uses partialFilterExpression instead of sparse for compound indexes\n {\n fields: { userId: 1, organizationId: 1 },\n options: {\n unique: true,\n partialFilterExpression: { userId: { $exists: true } }\n }\n },\n // Partial unique index: Only includes non-terminated docs with email\n // This allows email reuse when employees are terminated and rehired\n {\n fields: { email: 1, organizationId: 1 },\n options: {\n unique: true,\n partialFilterExpression: {\n email: { $exists: true },\n status: { $in: ['active', 'on_leave', 'suspended'] }\n }\n }\n },\n { fields: { organizationId: 1, status: 1 } },\n { fields: { organizationId: 1, department: 1 } },\n { fields: { organizationId: 1, 'compensation.netSalary': -1 } },\n];\n\n/**\n * Recommended indexes for PayrollRecord schema\n *\n * Includes UNIQUE compound index on (org, employee, period, runType) with partial filter\n * to prevent race conditions while still allowing re-processing after void/reverse.\n */\nexport const payrollRecordIndexes = [\n /**\n * UNIQUE Compound Index (v2.9.0+) - PRIMARY duplicate protection\n *\n * Prevents duplicate payrolls at the database level for the same:\n * - Organization, Employee, Period (month + year + startDate), Payroll run type\n *\n * The period.startDate is critical for non-monthly frequencies (weekly, bi_weekly,\n * daily, hourly) where multiple payroll runs can occur within the same calendar month.\n *\n * Partial filter excludes voided records to allow re-processing.\n * Duplicate inserts fail with E11000 → converted to DuplicatePayrollError.\n */\n {\n fields: {\n organizationId: 1,\n employeeId: 1,\n 'period.month': 1,\n 'period.year': 1,\n 'period.startDate': 1,\n payrollRunType: 1,\n },\n options: {\n unique: true,\n name: 'unique_payroll_per_period_startdate_runtype',\n // Only enforce for non-voided records (uses $eq which is supported in partial indexes)\n // When a record is voided, isVoided is set to true, excluding it from unique constraint\n partialFilterExpression: {\n isVoided: { $eq: false },\n },\n },\n },\n // Composite index for common queries\n { fields: { organizationId: 1, employeeId: 1, 'period.month': 1, 'period.year': 1 } },\n { fields: { organizationId: 1, 'period.year': 1, 'period.month': 1 } },\n { fields: { employeeId: 1, 'period.year': -1, 'period.month': -1 } },\n { fields: { status: 1, createdAt: -1 } },\n { fields: { organizationId: 1, status: 1, 'period.payDate': 1 } },\n // Index for payroll run type queries (supplemental, retroactive, etc.)\n { fields: { organizationId: 1, payrollRunType: 1, 'period.year': 1, 'period.month': 1 } },\n // TTL index using expireAt field for per-document retention (jurisdiction-specific)\n {\n fields: { expireAt: 1 },\n options: {\n expireAfterSeconds: 0, // Delete immediately when expireAt is reached\n },\n },\n];\n\n/**\n * Apply indexes to schema\n */\nexport function applyEmployeeIndexes(schema: Schema): void {\n for (const { fields, options } of employeeIndexes) {\n schema.index(fields as unknown as Record<string, 1 | -1>, options);\n }\n}\n\n/**\n * Apply payroll record indexes to schema\n */\nexport function applyPayrollRecordIndexes(schema: Schema): void {\n for (const { fields, options } of payrollRecordIndexes) {\n schema.index(fields as unknown as Record<string, 1 | -1>, options);\n }\n}\n\n// ============================================================================\n// Complete Schema Creators\n// ============================================================================\n\n/**\n * Create a complete Employee schema with all HRM fields.\n *\n * @param additionalFields - Extra fields to add to the schema\n * @param options - Schema options (organizationRef, userRef)\n * @returns Mongoose Schema for Employee\n *\n * @example\n * ```typescript\n * // Default (references 'Organization')\n * const employeeSchema = createEmployeeSchema();\n *\n * // Multi-branch setup\n * const employeeSchema = createEmployeeSchema({}, {\n * organizationRef: 'Branch',\n * });\n *\n * // With additional fields\n * const employeeSchema = createEmployeeSchema({\n * customField: { type: String },\n * }, {\n * organizationRef: 'Company',\n * });\n * ```\n */\nexport function createEmployeeSchema(\n additionalFields: SchemaDefinition = {},\n options: PayrollSchemaOptions = {}\n): Schema {\n const schema = new Schema(\n {\n ...createEmploymentFields(options),\n ...additionalFields,\n },\n { timestamps: true }\n );\n\n // Note: Pre-save hooks are not needed for partial indexes since:\n // - Guest employees use insertOne() which bypasses Mongoose hooks\n // - User-linked employees use Model.create() which properly sets userId\n // - Partial indexes with partialFilterExpression handle inclusion/exclusion\n\n applyEmployeeIndexes(schema);\n return schema;\n}\n\n/**\n * Create a complete PayrollRecord schema.\n *\n * @param additionalFields - Extra fields to add to the schema\n * @param options - Schema options (organizationRef, userRef)\n * @returns Mongoose Schema for PayrollRecord\n *\n * @example\n * ```typescript\n * // Multi-branch setup\n * const payrollRecordSchema = createPayrollRecordSchema({}, {\n * organizationRef: 'Branch',\n * });\n * ```\n */\nexport function createPayrollRecordSchema(\n additionalFields: SchemaDefinition = {},\n options: PayrollSchemaOptions = {}\n): Schema {\n const schema = new Schema(\n {\n ...createPayrollRecordFields(options),\n ...additionalFields,\n },\n { timestamps: true }\n );\n\n applyPayrollRecordIndexes(schema);\n\n // Virtual: totalAmount\n schema.virtual('totalAmount').get(function () {\n return this.breakdown?.netSalary || 0;\n });\n\n // Virtual: isPaid\n schema.virtual('isPaid').get(function () {\n return this.status === 'paid';\n });\n\n // Virtual: periodLabel\n schema.virtual('periodLabel').get(function () {\n const months = [\n 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\n 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n ];\n return `${months[this.period.month - 1]} ${this.period.year}`;\n });\n\n // Method: markAsPaid\n schema.methods.markAsPaid = function (\n transactionId: Types.ObjectId,\n paidAt = new Date()\n ) {\n this.status = 'paid';\n this.transactionId = transactionId;\n this.paidAt = paidAt;\n };\n\n // Method: markAsExported\n schema.methods.markAsExported = function () {\n this.exported = true;\n this.exportedAt = new Date();\n };\n\n // Method: canBeDeleted\n schema.methods.canBeDeleted = function (): boolean {\n return this.exported && this.status === 'paid';\n };\n\n return schema;\n}\n\n\n// ============================================================================\n// Leave Schemas\n// ============================================================================\n\nexport {\n leaveBalanceSchema,\n leaveBalanceFields,\n leaveRequestSchema,\n leaveRequestIndexes,\n leaveRequestTTLIndex,\n applyLeaveRequestIndexes,\n getLeaveRequestFields,\n getLeaveRequestModel,\n} from './leave.js';\n\n// ============================================================================\n// Tax Withholding Schemas\n// ============================================================================\n\nexport {\n taxWithholdingSchema,\n taxWithholdingIndexes,\n applyTaxWithholdingIndexes,\n getTaxWithholdingFields,\n getTaxWithholdingModel,\n} from './tax-withholding.js';\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n // Sub-schemas\n allowanceSchema,\n deductionSchema,\n compensationSchema,\n workScheduleSchema,\n bankDetailsSchema,\n employmentHistorySchema,\n payrollStatsSchema,\n payrollBreakdownSchema,\n periodSchema,\n // Field creators (configurable references)\n createEmploymentFields,\n createPayrollRecordFields,\n // Indexes\n employeeIndexes,\n payrollRecordIndexes,\n applyEmployeeIndexes,\n applyPayrollRecordIndexes,\n // Schema creators\n createEmployeeSchema,\n createPayrollRecordSchema,\n};\n\n","/**\n * @classytic/payroll - Common Schema Definitions\n *\n * Shared sub-schemas used across multiple schema modules\n * Extracted to prevent circular dependencies\n */\n\nimport { Schema } from 'mongoose';\n\n// ============================================================================\n// Period Schema\n// ============================================================================\n\n/**\n * Payroll period schema\n * Shared across PayrollRecord and TaxWithholding schemas\n */\nexport const periodSchema = new Schema(\n {\n month: { type: Number, required: true, min: 1, max: 12 },\n year: { type: Number, required: true, min: 2020 },\n startDate: { type: Date, required: true },\n endDate: { type: Date, required: true },\n payDate: { type: Date, required: true },\n },\n { _id: false }\n);\n","/**\n * @classytic/payroll - Leave Schemas\n *\n * Leave balance sub-schema (for Employee embedding) and re-exports from\n * the authoritative LeaveRequest model definition.\n *\n * Single source of truth for LeaveRequest: models/leave-request.model.ts\n */\n\nimport { Schema, type SchemaDefinition, type IndexDefinition } from 'mongoose';\nimport { LEAVE_TYPE_VALUES, LEAVE_REQUEST_STATUS_VALUES } from '../enums.js';\nimport {\n leaveRequestSchema,\n getLeaveRequestModel,\n type LeaveRequestModel,\n} from '../models/leave-request.model.js';\n\n// Re-export the authoritative LeaveRequest schema and model\nexport { leaveRequestSchema, getLeaveRequestModel, type LeaveRequestModel };\n\n// ============================================================================\n// Leave Balance Sub-Schema (for Employee embedding)\n// ============================================================================\n\n/**\n * Leave balance schema (embedded in Employee documents)\n * This is NOT a standalone model - it's for embedding.\n */\nexport const leaveBalanceSchema = new Schema(\n {\n type: {\n type: String,\n enum: LEAVE_TYPE_VALUES,\n required: true,\n },\n allocated: { type: Number, default: 0, min: 0 },\n used: { type: Number, default: 0, min: 0 },\n pending: { type: Number, default: 0, min: 0 },\n carriedOver: { type: Number, default: 0, min: 0 },\n expiresAt: { type: Date },\n year: { type: Number, required: true },\n },\n { _id: false }\n);\n\n/**\n * Leave balance fields for embedding in Employee schema\n *\n * @example\n * const employeeSchema = new Schema({\n * ...createEmploymentFields({ organizationRef: 'Branch' }),\n * ...leaveBalanceFields,\n * });\n */\nexport const leaveBalanceFields: SchemaDefinition = {\n leaveBalances: [leaveBalanceSchema],\n};\n\n// ============================================================================\n// Index Definitions (for custom schema composition)\n// ============================================================================\n\n/**\n * Recommended indexes for LeaveRequest collection\n */\nexport const leaveRequestIndexes = [\n { fields: { organizationId: 1, employeeId: 1, startDate: -1 } },\n { fields: { organizationId: 1, status: 1, createdAt: -1 } },\n { fields: { employeeId: 1, status: 1 } },\n { fields: { organizationId: 1, type: 1, status: 1 } },\n];\n\n/**\n * TTL index config for auto-cleanup (opt-in)\n */\nexport const leaveRequestTTLIndex = {\n fields: { createdAt: 1 },\n options: {\n expireAfterSeconds: 63072000, // 2 years\n partialFilterExpression: {\n status: { $in: ['approved', 'rejected', 'cancelled'] },\n },\n },\n};\n\n/**\n * Apply indexes to a LeaveRequest schema\n */\nexport function applyLeaveRequestIndexes(\n schema: Schema,\n options: { createIndexes?: boolean; enableTTL?: boolean; ttlSeconds?: number } = {}\n): void {\n if (!options.createIndexes) return;\n\n for (const { fields } of leaveRequestIndexes) {\n schema.index(fields as unknown as IndexDefinition);\n }\n\n if (options.enableTTL) {\n schema.index(leaveRequestTTLIndex.fields as Record<string, 1>, {\n ...leaveRequestTTLIndex.options,\n expireAfterSeconds: options.ttlSeconds ?? leaveRequestTTLIndex.options.expireAfterSeconds,\n });\n }\n}\n\n// ============================================================================\n// Schema Field Extraction (for custom schema composition)\n// ============================================================================\n\n/**\n * Extract field definitions from the authoritative LeaveRequest schema.\n * Use this when composing custom schemas.\n *\n * @example\n * const customSchema = new Schema({\n * ...getLeaveRequestFields(),\n * myCustomField: String,\n * });\n */\nexport function getLeaveRequestFields(): SchemaDefinition {\n const paths = leaveRequestSchema.paths;\n const fields: SchemaDefinition = {};\n\n for (const [key, pathObj] of Object.entries(paths)) {\n if (key === '_id' || key === '__v' || key === 'createdAt' || key === 'updatedAt') {\n continue;\n }\n fields[key] = (pathObj as { options?: SchemaDefinition[string] }).options || {};\n }\n\n return fields;\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n leaveBalanceSchema,\n leaveBalanceFields,\n leaveRequestSchema,\n leaveRequestIndexes,\n leaveRequestTTLIndex,\n applyLeaveRequestIndexes,\n getLeaveRequestFields,\n getLeaveRequestModel,\n};\n","/**\n * @classytic/payroll - LeaveRequest Model\n *\n * Mongoose schema for leave requests with TTL support\n */\n\nimport mongoose, { Schema, Model } from 'mongoose';\nimport type {\n LeaveRequestDocument,\n LeaveType,\n LeaveRequestStatus,\n} from '../types.js';\nimport {\n LEAVE_REQUEST_STATUS,\n LEAVE_TYPE_VALUES,\n LEAVE_REQUEST_STATUS_VALUES,\n} from '../enums.js';\nimport { logger } from '../utils/logger.js';\n\n// ============================================================================\n// Schema Definition\n// ============================================================================\n\nconst leaveRequestSchema = new Schema(\n {\n organizationId: {\n type: Schema.Types.ObjectId,\n required: false, // Optional for single-tenant mode\n ref: 'Organization',\n },\n employeeId: {\n type: Schema.Types.ObjectId,\n required: true,\n ref: 'Employee',\n },\n userId: {\n type: Schema.Types.ObjectId,\n required: false, // Optional for guest employees\n ref: 'User',\n },\n type: {\n type: String,\n enum: LEAVE_TYPE_VALUES,\n required: true,\n },\n startDate: {\n type: Date,\n required: true,\n validate: {\n validator: function (this: { endDate?: Date }, value: Date) {\n return !this.endDate || value <= this.endDate;\n },\n message: 'Start date must be before or equal to end date',\n },\n },\n endDate: {\n type: Date,\n required: true,\n validate: {\n validator: function (this: { startDate?: Date }, value: Date) {\n return !this.startDate || value >= this.startDate;\n },\n message: 'End date must be after or equal to start date',\n },\n },\n days: {\n type: Number,\n required: true,\n min: [0.5, 'Days must be at least 0.5'],\n },\n halfDay: { type: Boolean, default: false },\n reason: String,\n status: {\n type: String,\n enum: LEAVE_REQUEST_STATUS_VALUES,\n default: 'pending',\n },\n reviewedBy: { type: Schema.Types.ObjectId, ref: 'User' },\n reviewedAt: Date,\n reviewNotes: String,\n attachments: [String],\n metadata: { type: Schema.Types.Mixed, default: {} },\n },\n { timestamps: true }\n);\n\n// ============================================================================\n// Indexes (opt-in via applyLeaveRequestIndexes)\n// ============================================================================\n\n// Note: Indexes are NOT applied automatically\n// Use applyLeaveRequestIndexes() from schemas/leave.ts if needed\n\n// ============================================================================\n// Virtuals\n// ============================================================================\n\nleaveRequestSchema.virtual('isPending').get(function () {\n return this.status === LEAVE_REQUEST_STATUS.PENDING;\n});\n\nleaveRequestSchema.virtual('isApproved').get(function () {\n return this.status === LEAVE_REQUEST_STATUS.APPROVED;\n});\n\nleaveRequestSchema.virtual('isRejected').get(function () {\n return this.status === LEAVE_REQUEST_STATUS.REJECTED;\n});\n\nleaveRequestSchema.virtual('isCancelled').get(function () {\n return this.status === LEAVE_REQUEST_STATUS.CANCELLED;\n});\n\n// ============================================================================\n// Methods\n// ============================================================================\n\nleaveRequestSchema.methods.approve = function (\n reviewerId: mongoose.Types.ObjectId,\n notes?: string\n) {\n if (this.status !== LEAVE_REQUEST_STATUS.PENDING) {\n throw new Error('Can only approve pending requests');\n }\n this.status = LEAVE_REQUEST_STATUS.APPROVED;\n this.reviewedBy = reviewerId;\n this.reviewedAt = new Date();\n if (notes) this.reviewNotes = notes;\n\n logger.info('Leave request approved', {\n requestId: this._id.toString(),\n employeeId: this.employeeId.toString(),\n type: this.type,\n days: this.days,\n });\n};\n\nleaveRequestSchema.methods.reject = function (\n reviewerId: mongoose.Types.ObjectId,\n notes?: string\n) {\n if (this.status !== LEAVE_REQUEST_STATUS.PENDING) {\n throw new Error('Can only reject pending requests');\n }\n this.status = LEAVE_REQUEST_STATUS.REJECTED;\n this.reviewedBy = reviewerId;\n this.reviewedAt = new Date();\n if (notes) this.reviewNotes = notes;\n\n logger.info('Leave request rejected', {\n requestId: this._id.toString(),\n employeeId: this.employeeId.toString(),\n type: this.type,\n days: this.days,\n });\n};\n\nleaveRequestSchema.methods.cancel = function () {\n if (this.status !== LEAVE_REQUEST_STATUS.PENDING) {\n throw new Error('Can only cancel pending requests');\n }\n this.status = LEAVE_REQUEST_STATUS.CANCELLED;\n\n logger.info('Leave request cancelled', {\n requestId: this._id.toString(),\n employeeId: this.employeeId.toString(),\n type: this.type,\n days: this.days,\n });\n};\n\n// ============================================================================\n// Statics\n// ============================================================================\n\nleaveRequestSchema.statics.findByEmployee = function (\n employeeId: mongoose.Types.ObjectId,\n options: { status?: LeaveRequestStatus; year?: number; limit?: number } = {}\n) {\n const query: Record<string, unknown> = { employeeId };\n\n if (options.status) query.status = options.status;\n if (options.year) {\n query.startDate = {\n $gte: new Date(options.year, 0, 1),\n $lt: new Date(options.year + 1, 0, 1),\n };\n }\n\n return this.find(query)\n .sort({ startDate: -1 })\n .limit(options.limit || 50);\n};\n\nleaveRequestSchema.statics.findPendingByOrganization = function (\n organizationId?: mongoose.Types.ObjectId\n) {\n const query: Record<string, unknown> = {\n status: LEAVE_REQUEST_STATUS.PENDING,\n };\n\n if (organizationId) {\n query.organizationId = organizationId;\n }\n\n return this.find(query).sort({ createdAt: -1 });\n};\n\nleaveRequestSchema.statics.findByPeriod = function (\n organizationId: mongoose.Types.ObjectId | undefined,\n startDate: Date,\n endDate: Date,\n options: { status?: LeaveRequestStatus; type?: LeaveType } = {}\n) {\n const query: Record<string, unknown> = {\n $or: [\n { startDate: { $gte: startDate, $lte: endDate } },\n { endDate: { $gte: startDate, $lte: endDate } },\n {\n startDate: { $lte: startDate },\n endDate: { $gte: endDate },\n },\n ],\n };\n\n if (organizationId) {\n query.organizationId = organizationId;\n }\n\n if (options.status) query.status = options.status;\n if (options.type) query.type = options.type;\n\n return this.find(query).sort({ startDate: 1 });\n};\n\nleaveRequestSchema.statics.getLeaveStats = function (\n employeeId: mongoose.Types.ObjectId,\n year: number\n) {\n return this.aggregate([\n {\n $match: {\n employeeId,\n status: LEAVE_REQUEST_STATUS.APPROVED,\n startDate: {\n $gte: new Date(year, 0, 1),\n $lt: new Date(year + 1, 0, 1),\n },\n },\n },\n {\n $group: {\n _id: '$type',\n totalDays: { $sum: '$days' },\n count: { $sum: 1 },\n },\n },\n ]).then((results: unknown[]) =>\n results as Array<{ _id: LeaveType; totalDays: number; count: number }>\n );\n};\n\nleaveRequestSchema.statics.getOrganizationSummary = function (\n organizationId: mongoose.Types.ObjectId | undefined,\n year: number\n) {\n const matchStage: Record<string, unknown> = {\n startDate: {\n $gte: new Date(year, 0, 1),\n $lt: new Date(year + 1, 0, 1),\n },\n };\n\n if (organizationId) {\n matchStage.organizationId = organizationId;\n }\n\n return this.aggregate([\n {\n $match: matchStage,\n },\n {\n $group: {\n _id: { status: '$status', type: '$type' },\n totalDays: { $sum: '$days' },\n count: { $sum: 1 },\n },\n },\n ]);\n};\n\nleaveRequestSchema.statics.findOverlapping = function (\n employeeId: mongoose.Types.ObjectId,\n startDate: Date,\n endDate: Date,\n excludeRequestId?: mongoose.Types.ObjectId\n) {\n const query: Record<string, unknown> = {\n employeeId,\n status: { $in: [LEAVE_REQUEST_STATUS.PENDING, LEAVE_REQUEST_STATUS.APPROVED] },\n // Overlapping condition: new request overlaps with existing\n startDate: { $lte: endDate },\n endDate: { $gte: startDate },\n };\n\n if (excludeRequestId) {\n query._id = { $ne: excludeRequestId };\n }\n\n return this.find(query).sort({ startDate: 1 });\n};\n\nleaveRequestSchema.statics.hasOverlap = async function (\n employeeId: mongoose.Types.ObjectId,\n startDate: Date,\n endDate: Date,\n excludeRequestId?: mongoose.Types.ObjectId\n): Promise<boolean> {\n const query: Record<string, unknown> = {\n employeeId,\n status: { $in: [LEAVE_REQUEST_STATUS.PENDING, LEAVE_REQUEST_STATUS.APPROVED] },\n startDate: { $lte: endDate },\n endDate: { $gte: startDate },\n };\n\n if (excludeRequestId) {\n query._id = { $ne: excludeRequestId };\n }\n\n const count = await this.countDocuments(query);\n return count > 0;\n};\n\n// ============================================================================\n// Model Interface\n// ============================================================================\n\nexport interface LeaveRequestModel extends Model<LeaveRequestDocument> {\n findByEmployee(\n employeeId: mongoose.Types.ObjectId,\n options?: { status?: LeaveRequestStatus; year?: number; limit?: number }\n ): ReturnType<Model<LeaveRequestDocument>['find']>;\n\n findPendingByOrganization(\n organizationId?: mongoose.Types.ObjectId\n ): ReturnType<Model<LeaveRequestDocument>['find']>;\n\n findByPeriod(\n organizationId: mongoose.Types.ObjectId | undefined,\n startDate: Date,\n endDate: Date,\n options?: { status?: LeaveRequestStatus; type?: LeaveType }\n ): ReturnType<Model<LeaveRequestDocument>['find']>;\n\n getLeaveStats(\n employeeId: mongoose.Types.ObjectId,\n year: number\n ): Promise<Array<{ _id: LeaveType; totalDays: number; count: number }>>;\n\n getOrganizationSummary(\n organizationId: mongoose.Types.ObjectId | undefined,\n year: number\n ): Promise<\n Array<{\n _id: { status: LeaveRequestStatus; type: LeaveType };\n totalDays: number;\n count: number;\n }>\n >;\n\n findOverlapping(\n employeeId: mongoose.Types.ObjectId,\n startDate: Date,\n endDate: Date,\n excludeRequestId?: mongoose.Types.ObjectId\n ): ReturnType<Model<LeaveRequestDocument>['find']>;\n\n hasOverlap(\n employeeId: mongoose.Types.ObjectId,\n startDate: Date,\n endDate: Date,\n excludeRequestId?: mongoose.Types.ObjectId\n ): Promise<boolean>;\n}\n\n// ============================================================================\n// Model Factory\n// ============================================================================\n\n/**\n * Get or create LeaveRequest model\n *\n * @example\n * const LeaveRequest = getLeaveRequestModel();\n *\n * // With custom connection\n * const LeaveRequest = getLeaveRequestModel(customConnection);\n */\nexport function getLeaveRequestModel(\n connection: mongoose.Connection = mongoose.connection\n): LeaveRequestModel {\n const modelName = 'LeaveRequest';\n\n if (connection.models[modelName]) {\n return connection.models[modelName] as LeaveRequestModel;\n }\n\n return connection.model<LeaveRequestDocument, LeaveRequestModel>(\n modelName,\n leaveRequestSchema\n );\n}\n\nexport { leaveRequestSchema };\nexport default leaveRequestSchema;\n","/**\n * @classytic/payroll - TaxWithholding Model\n *\n * Mongoose schema for tax withholding tracking with aggregation support\n */\n\nimport mongoose, { Schema, Model } from 'mongoose';\nimport type {\n TaxWithholdingDocument,\n TaxType,\n TaxStatus,\n} from '../types.js';\nimport {\n TAX_STATUS,\n TAX_TYPE_VALUES,\n TAX_STATUS_VALUES,\n} from '../enums.js';\nimport { TaxStatusMachine } from '../core/payroll-states.js';\nimport { logger } from '../utils/logger.js';\nimport { periodSchema } from '../schemas/common.js';\n\n// ============================================================================\n// Schema Definition\n// ============================================================================\n\nconst taxWithholdingSchema = new Schema(\n {\n organizationId: {\n type: Schema.Types.ObjectId,\n required: true,\n ref: 'Organization',\n },\n employeeId: {\n type: Schema.Types.ObjectId,\n required: true,\n ref: 'Employee',\n },\n userId: {\n type: Schema.Types.ObjectId,\n required: false,\n ref: 'User',\n },\n payrollRecordId: {\n type: Schema.Types.ObjectId,\n required: true,\n ref: 'PayrollRecord',\n },\n transactionId: {\n type: Schema.Types.ObjectId,\n required: true,\n ref: 'Transaction',\n },\n\n period: {\n type: periodSchema,\n required: true,\n },\n\n amount: {\n type: Number,\n required: true,\n min: 0,\n },\n currency: {\n type: String,\n default: 'USD',\n },\n\n taxType: {\n type: String,\n enum: TAX_TYPE_VALUES,\n required: true,\n },\n taxRate: {\n type: Number,\n required: true,\n min: 0,\n max: 1,\n },\n taxableAmount: {\n type: Number,\n required: true,\n min: 0,\n },\n\n status: {\n type: String,\n enum: TAX_STATUS_VALUES,\n default: 'pending',\n },\n\n submittedAt: Date,\n paidAt: Date,\n governmentTransactionId: {\n type: Schema.Types.ObjectId,\n ref: 'Transaction',\n },\n referenceNumber: String,\n\n // Void metadata (when payroll is voided/reversed)\n voidedAt: { type: Date },\n voidedBy: { type: Schema.Types.ObjectId, ref: 'User' },\n voidReason: { type: String },\n voidMetadata: { type: Schema.Types.Mixed },\n\n notes: String,\n metadata: { type: Schema.Types.Mixed, default: {} },\n },\n { timestamps: true }\n);\n\n// ============================================================================\n// Indexes\n// ============================================================================\n\ntaxWithholdingSchema.index({ organizationId: 1, status: 1, 'period.year': 1, 'period.month': 1 });\ntaxWithholdingSchema.index({ employeeId: 1, 'period.year': -1, 'period.month': -1 });\ntaxWithholdingSchema.index({ payrollRecordId: 1 });\ntaxWithholdingSchema.index({ transactionId: 1 });\ntaxWithholdingSchema.index({ organizationId: 1, taxType: 1, status: 1 });\ntaxWithholdingSchema.index({ governmentTransactionId: 1 }, { sparse: true });\n\n// ============================================================================\n// Virtuals\n// ============================================================================\n\ntaxWithholdingSchema.virtual('isPending').get(function () {\n return this.status === TAX_STATUS.PENDING;\n});\n\ntaxWithholdingSchema.virtual('isPaid').get(function () {\n return this.status === TAX_STATUS.PAID;\n});\n\ntaxWithholdingSchema.virtual('isSubmitted').get(function () {\n return this.status === TAX_STATUS.SUBMITTED;\n});\n\n// ============================================================================\n// Methods\n// ============================================================================\n\ntaxWithholdingSchema.methods.markAsSubmitted = function (submittedAt = new Date()) {\n // Validate state transition\n const transition = TaxStatusMachine.validateTransition(this.status, TAX_STATUS.SUBMITTED);\n if (!transition.success) {\n throw new Error(transition.error);\n }\n\n this.status = TAX_STATUS.SUBMITTED;\n this.submittedAt = submittedAt;\n\n logger.info('Tax withholding marked as submitted', {\n withholdingId: this._id.toString(),\n employeeId: this.employeeId.toString(),\n taxType: this.taxType,\n amount: this.amount,\n });\n};\n\ntaxWithholdingSchema.methods.markAsPaid = function (\n transactionId: mongoose.Types.ObjectId,\n referenceNumber?: string,\n paidAt = new Date()\n) {\n // Validate state transition\n const transition = TaxStatusMachine.validateTransition(this.status, TAX_STATUS.PAID);\n if (!transition.success) {\n throw new Error(transition.error);\n }\n\n this.status = TAX_STATUS.PAID;\n this.governmentTransactionId = transactionId;\n this.referenceNumber = referenceNumber;\n this.paidAt = paidAt;\n\n logger.info('Tax withholding marked as paid', {\n withholdingId: this._id.toString(),\n employeeId: this.employeeId.toString(),\n taxType: this.taxType,\n amount: this.amount,\n referenceNumber,\n });\n};\n\n// ============================================================================\n// Statics\n// ============================================================================\n\ntaxWithholdingSchema.statics.findByPeriod = function (\n organizationId: mongoose.Types.ObjectId,\n month: number,\n year: number\n) {\n return this.find({\n organizationId,\n 'period.month': month,\n 'period.year': year,\n });\n};\n\ntaxWithholdingSchema.statics.findByEmployee = function (\n employeeId: mongoose.Types.ObjectId,\n options: { year?: number; taxType?: TaxType; status?: TaxStatus; limit?: number } = {}\n) {\n const query: Record<string, unknown> = { employeeId };\n\n if (options.year) {\n query['period.year'] = options.year;\n }\n if (options.taxType) {\n query.taxType = options.taxType;\n }\n if (options.status) {\n query.status = options.status;\n }\n\n return this.find(query)\n .sort({ 'period.year': -1, 'period.month': -1 })\n .limit(options.limit || 50);\n};\n\ntaxWithholdingSchema.statics.findPending = function (\n organizationId: mongoose.Types.ObjectId,\n options: {\n fromMonth?: number;\n fromYear?: number;\n toMonth?: number;\n toYear?: number;\n taxType?: TaxType;\n } = {}\n) {\n const query: Record<string, unknown> = {\n organizationId,\n status: TAX_STATUS.PENDING,\n };\n\n if (options.taxType) {\n query.taxType = options.taxType;\n }\n\n if (options.fromMonth && options.fromYear) {\n query.$or = query.$or || [];\n (query.$or as Array<Record<string, unknown>>).push({\n $and: [\n { 'period.year': { $gt: options.fromYear } },\n ],\n });\n (query.$or as Array<Record<string, unknown>>).push({\n $and: [\n { 'period.year': options.fromYear },\n { 'period.month': { $gte: options.fromMonth } },\n ],\n });\n }\n\n if (options.toMonth && options.toYear) {\n const existingOr = query.$or;\n delete query.$or;\n\n query.$and = query.$and || [];\n if (existingOr) {\n (query.$and as Array<Record<string, unknown>>).push({ $or: existingOr });\n }\n\n (query.$and as Array<Record<string, unknown>>).push({\n $or: [\n { 'period.year': { $lt: options.toYear } },\n {\n $and: [\n { 'period.year': options.toYear },\n { 'period.month': { $lte: options.toMonth } },\n ],\n },\n ],\n });\n }\n\n return this.find(query).sort({ 'period.year': 1, 'period.month': 1 });\n};\n\ntaxWithholdingSchema.statics.getSummaryByType = function (\n organizationId: mongoose.Types.ObjectId,\n fromPeriod: { month: number; year: number },\n toPeriod: { month: number; year: number }\n) {\n return this.aggregate([\n {\n $match: {\n organizationId,\n $or: [\n { 'period.year': { $gt: fromPeriod.year } },\n {\n $and: [\n { 'period.year': fromPeriod.year },\n { 'period.month': { $gte: fromPeriod.month } },\n ],\n },\n ],\n $and: [\n {\n $or: [\n { 'period.year': { $lt: toPeriod.year } },\n {\n $and: [\n { 'period.year': toPeriod.year },\n { 'period.month': { $lte: toPeriod.month } },\n ],\n },\n ],\n },\n ],\n },\n },\n {\n $group: {\n _id: '$taxType',\n totalAmount: { $sum: '$amount' },\n count: { $sum: 1 },\n withholdingIds: { $push: '$_id' },\n },\n },\n {\n $project: {\n _id: 0,\n taxType: '$_id',\n totalAmount: 1,\n count: 1,\n withholdingIds: 1,\n },\n },\n ]).then((results) =>\n results.map((r) => ({\n taxType: r.taxType,\n totalAmount: r.totalAmount,\n count: r.count,\n withholdingIds: r.withholdingIds,\n }))\n );\n};\n\ntaxWithholdingSchema.statics.getByPayrollRecord = function (\n payrollRecordId: mongoose.Types.ObjectId\n) {\n return this.find({ payrollRecordId });\n};\n\ntaxWithholdingSchema.statics.getTotalByOrganization = function (\n organizationId: mongoose.Types.ObjectId,\n options: { status?: TaxStatus; year?: number } = {}\n) {\n const match: Record<string, unknown> = { organizationId };\n\n if (options.status) {\n match.status = options.status;\n }\n if (options.year) {\n match['period.year'] = options.year;\n }\n\n return this.aggregate([\n { $match: match },\n {\n $group: {\n _id: null,\n totalAmount: { $sum: '$amount' },\n count: { $sum: 1 },\n },\n },\n ]).then((results) =>\n results[0] || { totalAmount: 0, count: 0 }\n );\n};\n\n// ============================================================================\n// TTL Index Management\n// ============================================================================\n\n/**\n * Add TTL index on any date field for automatic cleanup\n *\n * Creates a TTL index that automatically deletes documents after a specified time\n * from the date stored in the field. Useful for auto-cleanup of voided tax withholdings.\n *\n * @param fieldName - Name of the date field (e.g., 'voidedAt', 'paidAt')\n * @param ttlSeconds - Time in seconds after field date when document should be deleted\n * @param options - Optional configuration\n *\n * @example Auto-delete voided withholdings after 90 days\n * ```typescript\n * await TaxWithholding.addTTLIndex('voidedAt', 90 * 24 * 60 * 60);\n * ```\n *\n * @example Auto-delete paid withholdings after 7 years\n * ```typescript\n * const YEARS = 365.25 * 24 * 60 * 60;\n * await TaxWithholding.addTTLIndex('paidAt', 7 * YEARS);\n * ```\n */\ntaxWithholdingSchema.statics.addTTLIndex = async function (\n fieldName: string,\n ttlSeconds: number,\n options: { partialFilter?: Record<string, unknown> } = {}\n): Promise<void> {\n const collection = this.collection;\n const indexName = `${fieldName}_ttl_1`;\n\n try {\n // Drop existing TTL index if it exists\n const indexes = await collection.indexes();\n const hasTTLIndex = indexes.some((idx) => idx.name === indexName);\n\n if (hasTTLIndex) {\n await collection.dropIndex(indexName);\n logger.info('Dropped existing TTL index', { indexName, fieldName });\n }\n\n // Build index options\n const indexOptions: {\n name: string;\n expireAfterSeconds: number;\n partialFilterExpression?: Record<string, unknown>;\n } = {\n name: indexName,\n expireAfterSeconds: ttlSeconds,\n };\n\n // Add partial filter to only apply TTL to documents with this field set\n // Note: MongoDB partial filters don't support $ne operator\n indexOptions.partialFilterExpression = {\n [fieldName]: { $exists: true },\n ...options.partialFilter,\n };\n\n // Create TTL index\n await collection.createIndex(\n { [fieldName]: 1 },\n indexOptions\n );\n\n logger.info('Added TTL index for auto-cleanup', {\n fieldName,\n indexName,\n expireAfterSeconds: ttlSeconds,\n retentionDays: Math.round(ttlSeconds / (24 * 60 * 60)),\n partialFilter: indexOptions.partialFilterExpression,\n });\n } catch (error) {\n logger.error('Failed to add TTL index', {\n fieldName,\n error: (error as Error).message,\n });\n throw error;\n }\n};\n\n/**\n * Remove TTL index from a field\n *\n * @param fieldName - Name of the field to remove TTL index from\n *\n * @example\n * ```typescript\n * await TaxWithholding.removeTTLIndex('voidedAt');\n * ```\n */\ntaxWithholdingSchema.statics.removeTTLIndex = async function (\n fieldName: string\n): Promise<void> {\n const collection = this.collection;\n const indexName = `${fieldName}_ttl_1`;\n\n try {\n const indexes = await collection.indexes();\n const hasTTLIndex = indexes.some((idx) => idx.name === indexName);\n\n if (hasTTLIndex) {\n await collection.dropIndex(indexName);\n logger.info('Removed TTL index', { fieldName, indexName });\n } else {\n logger.warn('TTL index not found', { fieldName, indexName });\n }\n } catch (error) {\n logger.error('Failed to remove TTL index', {\n fieldName,\n error: (error as Error).message,\n });\n throw error;\n }\n};\n\n// ============================================================================\n// Model Interface\n// ============================================================================\n\nexport interface TaxWithholdingModel extends Model<TaxWithholdingDocument> {\n findByPeriod(\n organizationId: mongoose.Types.ObjectId,\n month: number,\n year: number\n ): ReturnType<Model<TaxWithholdingDocument>['find']>;\n\n findByEmployee(\n employeeId: mongoose.Types.ObjectId,\n options?: { year?: number; taxType?: TaxType; status?: TaxStatus; limit?: number }\n ): ReturnType<Model<TaxWithholdingDocument>['find']>;\n\n findPending(\n organizationId: mongoose.Types.ObjectId,\n options?: {\n fromMonth?: number;\n fromYear?: number;\n toMonth?: number;\n toYear?: number;\n taxType?: TaxType;\n }\n ): ReturnType<Model<TaxWithholdingDocument>['find']>;\n\n getSummaryByType(\n organizationId: mongoose.Types.ObjectId,\n fromPeriod: { month: number; year: number },\n toPeriod: { month: number; year: number }\n ): Promise<\n Array<{\n taxType: TaxType;\n totalAmount: number;\n count: number;\n withholdingIds: mongoose.Types.ObjectId[];\n }>\n >;\n\n getByPayrollRecord(\n payrollRecordId: mongoose.Types.ObjectId\n ): ReturnType<Model<TaxWithholdingDocument>['find']>;\n\n getTotalByOrganization(\n organizationId: mongoose.Types.ObjectId,\n options?: { status?: TaxStatus; year?: number }\n ): Promise<{ totalAmount: number; count: number }>;\n\n addTTLIndex(\n fieldName: string,\n ttlSeconds: number,\n options?: { partialFilter?: Record<string, unknown> }\n ): Promise<void>;\n removeTTLIndex(fieldName: string): Promise<void>;\n}\n\n// ============================================================================\n// Model Factory\n// ============================================================================\n\n/**\n * Get or create TaxWithholding model\n *\n * @example\n * const TaxWithholding = getTaxWithholdingModel();\n *\n * // With custom connection\n * const TaxWithholding = getTaxWithholdingModel(customConnection);\n */\nexport function getTaxWithholdingModel(\n connection: mongoose.Connection = mongoose.connection\n): TaxWithholdingModel {\n const modelName = 'TaxWithholding';\n\n if (connection.models[modelName]) {\n return connection.models[modelName] as TaxWithholdingModel;\n }\n\n return connection.model<TaxWithholdingDocument, TaxWithholdingModel>(\n modelName,\n taxWithholdingSchema\n );\n}\n\nexport { taxWithholdingSchema };\nexport default taxWithholdingSchema;\n","/**\n * @classytic/payroll - Tax Withholding Schema\n *\n * Re-exports from the authoritative model definition.\n * Use this for schema composition when building custom schemas.\n *\n * Single source of truth: models/tax-withholding.model.ts\n */\n\nimport {\n taxWithholdingSchema,\n getTaxWithholdingModel,\n type TaxWithholdingModel,\n} from '../models/tax-withholding.model.js';\nimport type { Schema, SchemaDefinition, IndexDefinition } from 'mongoose';\n\n// Re-export the authoritative schema\nexport { taxWithholdingSchema, getTaxWithholdingModel, type TaxWithholdingModel };\n\n// ============================================================================\n// Index Definitions (for custom schema composition)\n// ============================================================================\n\n/**\n * Recommended indexes for tax withholding collection\n */\nexport const taxWithholdingIndexes = [\n { fields: { organizationId: 1, status: 1, 'period.year': 1, 'period.month': 1 } },\n { fields: { employeeId: 1, 'period.year': -1, 'period.month': -1 } },\n { fields: { payrollRecordId: 1 } },\n { fields: { transactionId: 1 } },\n { fields: { organizationId: 1, taxType: 1, status: 1 } },\n { fields: { governmentTransactionId: 1 }, options: { sparse: true } },\n];\n\n/**\n * Apply recommended indexes to a custom tax withholding schema\n */\nexport function applyTaxWithholdingIndexes(schema: Schema): void {\n for (const { fields, options } of taxWithholdingIndexes) {\n schema.index(fields as unknown as IndexDefinition, options);\n }\n}\n\n// ============================================================================\n// Schema Field Extraction (for custom schema composition)\n// ============================================================================\n\n/**\n * Extract field definitions from the authoritative schema.\n * Use this when composing custom schemas that need tax withholding fields.\n *\n * @example\n * const customSchema = new Schema({\n * ...getTaxWithholdingFields(),\n * myCustomField: String,\n * });\n */\nexport function getTaxWithholdingFields(): SchemaDefinition {\n const paths = taxWithholdingSchema.paths;\n const fields: SchemaDefinition = {};\n\n for (const [key, pathObj] of Object.entries(paths)) {\n if (key === '_id' || key === '__v' || key === 'createdAt' || key === 'updatedAt') {\n continue;\n }\n fields[key] = (pathObj as { options?: SchemaDefinition[string] }).options || {};\n }\n\n return fields;\n}\n\nexport default taxWithholdingSchema;\n","/**\n * @classytic/payroll - Employee Plugin\n *\n * Mongoose plugin that adds HRM methods and virtuals to Employee schema\n */\n\nimport type { Schema, Document } from 'mongoose';\nimport type {\n EmployeeStatus,\n Compensation,\n TerminationReason,\n Allowance,\n Deduction,\n LeaveBalance,\n LeaveType,\n LeaveInitConfig,\n LeaveSummaryResult,\n} from '../types.js';\nimport { diffInDays } from '../utils/date.js';\nimport { sumDeductions } from '../utils/calculation.js';\nimport { isActive, isTerminated } from '../utils/validation.js';\nimport { CompensationFactory } from '../factories/compensation.factory.js';\nimport { logger } from '../utils/logger.js';\nimport {\n getLeaveBalance,\n getLeaveBalances,\n getAvailableDays,\n getLeaveSummary,\n hasLeaveBalance,\n initializeLeaveBalances,\n calculateCarryOver,\n accrueLeaveToBalance,\n DEFAULT_LEAVE_ALLOCATIONS,\n DEFAULT_CARRY_OVER,\n} from '../utils/leave.js';\n\n// ============================================================================\n// Plugin Options\n// ============================================================================\n\nexport interface EmployeePluginOptions {\n /** Require bank details for salary payment */\n requireBankDetails?: boolean;\n /** Field name for compensation */\n compensationField?: string;\n /** Field name for status */\n statusField?: string;\n /** Enable auto salary calculation on save */\n autoCalculateSalary?: boolean;\n /** Create indexes on schema (default: false) */\n createIndexes?: boolean;\n /** Enable leave management methods (default: false) */\n enableLeave?: boolean;\n /** Leave configuration */\n leaveConfig?: LeaveInitConfig;\n /** Field name for leave balances (default: 'leaveBalances') */\n leaveBalancesField?: string;\n}\n\n// ============================================================================\n// Employee Plugin\n// ============================================================================\n\n/**\n * Mongoose plugin that adds HRM functionality to Employee schema\n *\n * @example\n * ```typescript\n * const employeeSchema = new Schema({\n * ...createEmploymentFields({ organizationRef: 'Branch' }),\n * // Custom fields\n * });\n *\n * employeeSchema.plugin(employeePlugin);\n * ```\n */\nexport function employeePlugin(\n schema: Schema,\n options: EmployeePluginOptions = {}\n): void {\n const {\n requireBankDetails = false,\n compensationField = 'compensation',\n statusField = 'status',\n autoCalculateSalary = true,\n enableLeave = false,\n leaveConfig = {},\n leaveBalancesField = 'leaveBalances',\n } = options;\n\n // ========================================\n // Virtuals\n // ========================================\n\n /**\n * Virtual: Current net salary\n */\n schema.virtual('currentSalary').get(function (this: Document & Record<string, unknown>) {\n const compensation = this[compensationField] as Compensation | undefined;\n return compensation?.netSalary || 0;\n });\n\n /**\n * Virtual: Is active\n */\n schema.virtual('isActive').get(function (this: Document & Record<string, unknown>) {\n return isActive({ status: this[statusField] as EmployeeStatus });\n });\n\n /**\n * Virtual: Is terminated\n */\n schema.virtual('isTerminated').get(function (this: Document & Record<string, unknown>) {\n return isTerminated({ status: this[statusField] as EmployeeStatus });\n });\n\n /**\n * Virtual: Years of service\n */\n schema.virtual('yearsOfService').get(function (this: Document & Record<string, unknown>) {\n const hireDate = this.hireDate as Date | undefined;\n const terminationDate = this.terminationDate as Date | undefined;\n if (!hireDate) return 0;\n \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 * Virtual: Is on probation\n */\n schema.virtual('isOnProbation').get(function (this: Document & Record<string, unknown>) {\n const probationEndDate = this.probationEndDate as Date | undefined;\n if (!probationEndDate) return false;\n return new Date() < new Date(probationEndDate);\n });\n\n // ========================================\n // Methods\n // ========================================\n\n /**\n * Calculate salary breakdown\n */\n schema.methods.calculateSalary = function (this: Document & Record<string, unknown>) {\n const compensation = this[compensationField] as Compensation | undefined;\n if (!compensation) {\n return { gross: 0, deductions: 0, net: 0 };\n }\n\n const breakdown = CompensationFactory.calculateBreakdown(compensation);\n\n return {\n gross: breakdown.grossAmount,\n deductions: sumDeductions(\n breakdown.deductions.map((d) => ({ amount: d.calculatedAmount }))\n ),\n net: breakdown.netAmount,\n };\n };\n\n /**\n * Update salary calculations\n */\n schema.methods.updateSalaryCalculations = function (this: Document & Record<string, unknown>) {\n const compensation = this[compensationField] as Compensation | undefined;\n if (!compensation) return;\n\n const calculated = (this as unknown as { calculateSalary: () => { gross: number; net: number } }).calculateSalary();\n (this[compensationField] as Compensation).grossSalary = calculated.gross;\n (this[compensationField] as Compensation).netSalary = calculated.net;\n (this[compensationField] as Compensation).lastModified = new Date();\n };\n\n /**\n * Check if can receive salary\n */\n schema.methods.canReceiveSalary = function (this: Document & Record<string, unknown>): boolean {\n const status = this[statusField] as EmployeeStatus;\n const compensation = this[compensationField] as Compensation | undefined;\n const bankDetails = this.bankDetails as { accountNumber?: string } | undefined;\n\n return (\n status === 'active' &&\n (compensation?.baseAmount ?? 0) > 0 &&\n (!requireBankDetails || !!bankDetails?.accountNumber)\n );\n };\n\n /**\n * Add allowance\n */\n schema.methods.addAllowance = function (\n this: Document & Record<string, unknown>,\n type: Allowance['type'],\n amount: number,\n taxable = true\n ) {\n const compensation = this[compensationField] as Compensation;\n if (!compensation.allowances) {\n compensation.allowances = [];\n }\n compensation.allowances.push({\n type,\n name: type,\n amount,\n taxable,\n recurring: true,\n effectiveFrom: new Date(),\n });\n (this as unknown as { updateSalaryCalculations: () => void }).updateSalaryCalculations();\n };\n\n /**\n * Add deduction\n */\n schema.methods.addDeduction = function (\n this: Document & Record<string, unknown>,\n type: Deduction['type'],\n amount: number,\n auto = false,\n description = ''\n ) {\n const compensation = this[compensationField] as Compensation;\n if (!compensation.deductions) {\n compensation.deductions = [];\n }\n compensation.deductions.push({\n type,\n name: type,\n amount,\n auto,\n recurring: true,\n description,\n effectiveFrom: new Date(),\n });\n (this as unknown as { updateSalaryCalculations: () => void }).updateSalaryCalculations();\n };\n\n /**\n * Remove allowance\n */\n schema.methods.removeAllowance = function (\n this: Document & Record<string, unknown>,\n type: Allowance['type']\n ) {\n const compensation = this[compensationField] as Compensation;\n if (!compensation.allowances) return;\n compensation.allowances = compensation.allowances.filter((a) => a.type !== type);\n (this as unknown as { updateSalaryCalculations: () => void }).updateSalaryCalculations();\n };\n\n /**\n * Remove deduction\n */\n schema.methods.removeDeduction = function (\n this: Document & Record<string, unknown>,\n type: Deduction['type']\n ) {\n const compensation = this[compensationField] as Compensation;\n if (!compensation.deductions) return;\n compensation.deductions = compensation.deductions.filter((d) => d.type !== type);\n (this as unknown as { updateSalaryCalculations: () => void }).updateSalaryCalculations();\n };\n\n /**\n * Terminate employee\n */\n schema.methods.terminate = function (\n this: Document & Record<string, unknown>,\n reason: TerminationReason,\n terminationDate = new Date()\n ) {\n const status = this[statusField] as EmployeeStatus;\n if (status === 'terminated') {\n throw new Error('Employee already terminated');\n }\n\n const compensation = this[compensationField] as Compensation;\n const employmentHistory = (this.employmentHistory as unknown[]) || [];\n\n employmentHistory.push({\n hireDate: this.hireDate,\n terminationDate,\n reason,\n finalSalary: compensation?.netSalary || 0,\n position: this.position,\n department: this.department,\n });\n\n this[statusField] = 'terminated';\n this.terminationDate = terminationDate;\n this.employmentHistory = employmentHistory;\n\n logger.info('Employee terminated', {\n employeeId: this.employeeId,\n organizationId: this.organizationId?.toString(),\n reason,\n });\n };\n\n /**\n * Re-hire employee\n */\n schema.methods.reHire = function (\n this: Document & Record<string, unknown>,\n hireDate = new Date(),\n position?: string,\n department?: string\n ) {\n const status = this[statusField] as EmployeeStatus;\n if (status !== 'terminated') {\n throw new Error('Can only re-hire terminated employees');\n }\n\n this[statusField] = 'active';\n this.hireDate = hireDate;\n this.terminationDate = null;\n\n if (position) this.position = position;\n if (department) this.department = department;\n\n logger.info('Employee re-hired', {\n employeeId: this.employeeId,\n organizationId: this.organizationId?.toString(),\n });\n };\n\n // ========================================\n // Hooks\n // ========================================\n\n /**\n * Pre-save hook to update salary calculations\n * Mongoose v9 compatible - uses async without next callback\n */\n if (autoCalculateSalary) {\n schema.pre('save', async function () {\n if (this.isModified(compensationField)) {\n (this as unknown as { updateSalaryCalculations: () => void }).updateSalaryCalculations();\n }\n });\n }\n\n // ========================================\n // Leave Management (opt-in)\n // ========================================\n\n if (enableLeave) {\n /**\n * Virtual: Total available leave days across all types\n */\n schema.virtual('availableLeave').get(function (this: Document & Record<string, unknown>) {\n const balances = this[leaveBalancesField] as LeaveBalance[] | undefined;\n if (!balances || !balances.length) return 0;\n\n const year = new Date().getFullYear();\n return balances\n .filter((b) => b.year === year)\n .reduce(\n (sum, b) =>\n sum + Math.max(0, b.allocated + b.carriedOver - b.used - b.pending),\n 0\n );\n });\n\n /**\n * Virtual: Can take leave (active status and has available balance)\n */\n schema.virtual('canTakeLeave').get(function (this: Document & Record<string, unknown>) {\n const status = this[statusField] as EmployeeStatus;\n return status === 'active' && (((this as Record<string, unknown>).availableLeave as number) > 0);\n });\n\n /**\n * Method: Get leave balance for a specific type or all balances\n */\n schema.methods.getLeaveBalance = function (\n this: Document & Record<string, unknown>,\n type?: LeaveType,\n year = new Date().getFullYear()\n ): LeaveBalance | LeaveBalance[] | undefined {\n const employee = { leaveBalances: this[leaveBalancesField] as LeaveBalance[] };\n if (type) {\n return getLeaveBalance(employee, type, year);\n }\n return getLeaveBalances(employee, year);\n };\n\n /**\n * Method: Get available days for a leave type\n */\n schema.methods.getAvailableLeaveDays = function (\n this: Document & Record<string, unknown>,\n type: LeaveType,\n year = new Date().getFullYear()\n ): number {\n const employee = { leaveBalances: this[leaveBalancesField] as LeaveBalance[] };\n return getAvailableDays(employee, type, year);\n };\n\n /**\n * Method: Check if has sufficient leave balance\n */\n schema.methods.hasLeaveBalance = function (\n this: Document & Record<string, unknown>,\n type: LeaveType,\n days: number,\n year = new Date().getFullYear()\n ): boolean {\n const employee = { leaveBalances: this[leaveBalancesField] as LeaveBalance[] };\n return hasLeaveBalance(employee, type, days, year);\n };\n\n /**\n * Method: Get comprehensive leave summary\n */\n schema.methods.getLeaveSummary = function (\n this: Document & Record<string, unknown>,\n year = new Date().getFullYear()\n ): LeaveSummaryResult {\n const employee = { leaveBalances: this[leaveBalancesField] as LeaveBalance[] };\n return getLeaveSummary(employee, year);\n };\n\n /**\n * Method: Initialize leave balances (for new employees)\n */\n schema.methods.initializeLeaveBalances = function (\n this: Document & Record<string, unknown>,\n year = new Date().getFullYear()\n ): void {\n const hireDate = this.hireDate as Date;\n if (!hireDate) {\n throw new Error('Cannot initialize leave balances without hire date');\n }\n\n const balances = initializeLeaveBalances(hireDate, leaveConfig, year);\n this[leaveBalancesField] = balances;\n\n logger.debug('Leave balances initialized', {\n employeeId: this.employeeId,\n year,\n balanceCount: balances.length,\n });\n };\n\n /**\n * Method: Add pending leave (when request is submitted)\n */\n schema.methods.addPendingLeave = function (\n this: Document & Record<string, unknown>,\n type: LeaveType,\n days: number,\n year = new Date().getFullYear()\n ): void {\n const balances = (this[leaveBalancesField] as LeaveBalance[]) || [];\n const balance = balances.find((b) => b.type === type && b.year === year);\n\n if (balance) {\n balance.pending += days;\n } else if (type !== 'unpaid') {\n // Create balance entry if doesn't exist (except for unpaid)\n balances.push({\n type,\n allocated: 0,\n used: 0,\n pending: days,\n carriedOver: 0,\n year,\n });\n this[leaveBalancesField] = balances;\n }\n };\n\n /**\n * Method: Remove pending leave (when request is cancelled/rejected)\n */\n schema.methods.removePendingLeave = function (\n this: Document & Record<string, unknown>,\n type: LeaveType,\n days: number,\n year = new Date().getFullYear()\n ): void {\n const balances = (this[leaveBalancesField] as LeaveBalance[]) || [];\n const balance = balances.find((b) => b.type === type && b.year === year);\n\n if (balance) {\n balance.pending = Math.max(0, balance.pending - days);\n }\n };\n\n /**\n * Method: Use leave (when request is approved)\n */\n schema.methods.useLeave = function (\n this: Document & Record<string, unknown>,\n type: LeaveType,\n days: number,\n year = new Date().getFullYear()\n ): void {\n const balances = (this[leaveBalancesField] as LeaveBalance[]) || [];\n const balance = balances.find((b) => b.type === type && b.year === year);\n\n if (balance) {\n balance.pending = Math.max(0, balance.pending - days);\n balance.used += days;\n } else if (type === 'unpaid') {\n // Track unpaid leave even without initial balance\n balances.push({\n type,\n allocated: 0,\n used: days,\n pending: 0,\n carriedOver: 0,\n year,\n });\n this[leaveBalancesField] = balances;\n }\n\n logger.debug('Leave used', {\n employeeId: this.employeeId,\n type,\n days,\n year,\n });\n };\n\n /**\n * Method: Restore leave (when approved request is cancelled)\n */\n schema.methods.restoreLeave = function (\n this: Document & Record<string, unknown>,\n type: LeaveType,\n days: number,\n year = new Date().getFullYear()\n ): void {\n const balances = (this[leaveBalancesField] as LeaveBalance[]) || [];\n const balance = balances.find((b) => b.type === type && b.year === year);\n\n if (balance) {\n balance.used = Math.max(0, balance.used - days);\n }\n\n logger.debug('Leave restored', {\n employeeId: this.employeeId,\n type,\n days,\n year,\n });\n };\n\n /**\n * Method: Accrue leave (add to allocation)\n */\n schema.methods.accrueLeave = function (\n this: Document & Record<string, unknown>,\n type: LeaveType,\n amount: number,\n year = new Date().getFullYear()\n ): void {\n const balances = (this[leaveBalancesField] as LeaveBalance[]) || [];\n accrueLeaveToBalance(balances, type, amount, year);\n this[leaveBalancesField] = balances;\n\n logger.debug('Leave accrued', {\n employeeId: this.employeeId,\n type,\n amount,\n year,\n });\n };\n\n /**\n * Method: Process year-end carry-over\n */\n schema.methods.processLeaveCarryOver = function (\n this: Document & Record<string, unknown>,\n fromYear = new Date().getFullYear(),\n maxCarryOver: Partial<Record<LeaveType, number>> = leaveConfig.maxCarryOver || DEFAULT_CARRY_OVER,\n newYearAllocations: Partial<Record<LeaveType, number>> = leaveConfig.defaultAllocations || DEFAULT_LEAVE_ALLOCATIONS\n ): LeaveBalance[] {\n const balances = (this[leaveBalancesField] as LeaveBalance[]) || [];\n const currentYearBalances = balances.filter((b) => b.year === fromYear);\n const newBalances = calculateCarryOver(currentYearBalances, maxCarryOver, newYearAllocations);\n\n // Add new year balances\n for (const nb of newBalances) {\n const existingIdx = balances.findIndex(\n (b) => b.type === nb.type && b.year === nb.year\n );\n if (existingIdx >= 0) {\n balances[existingIdx] = nb;\n } else {\n balances.push(nb);\n }\n }\n\n this[leaveBalancesField] = balances;\n\n logger.info('Leave carry-over processed', {\n employeeId: this.employeeId,\n fromYear,\n toYear: fromYear + 1,\n balancesCreated: newBalances.length,\n });\n\n return newBalances;\n };\n\n logger.debug('Leave management enabled for employee plugin');\n }\n\n // ========================================\n // Indexes (opt-in)\n // ========================================\n\n if (options.createIndexes) {\n schema.index({ organizationId: 1, employeeId: 1 }, { unique: true });\n // Sparse unique index: Allows multiple guest employees (userId=null) per org\n schema.index({ userId: 1, organizationId: 1 }, { unique: true, sparse: true });\n // Email lookup for guest employees\n schema.index({ email: 1, organizationId: 1 }, { sparse: true });\n schema.index({ organizationId: 1, status: 1 });\n schema.index({ organizationId: 1, department: 1 });\n schema.index({ organizationId: 1, 'compensation.netSalary': -1 });\n }\n\n logger.debug('Employee plugin applied', {\n requireBankDetails,\n autoCalculateSalary,\n enableLeave,\n });\n}\n\nexport default employeePlugin;\n\n","/**\n * @classytic/payroll - Attendance Integration\n *\n * Native integration with @classytic/clockin.\n * ClockIn is an optional peer dependency for attendance-based deductions.\n */\n\nimport type { Model } from 'mongoose';\nimport type { AttendanceInput } from './core/config.js';\nimport type { ObjectIdLike } from './types.js';\n\n/**\n * ClockIn attendance shape (from @classytic/clockin)\n *\n * ClockIn stores one document per employee per month with:\n * - totalWorkDays: Total days worked\n * - fullDaysCount: Full work days\n * - halfDaysCount: Half days (counted as 0.5)\n * - paidLeaveDaysCount: Paid leave\n */\ninterface ClockInAttendance {\n organizationId: unknown;\n targetId: unknown;\n targetModel: string;\n year: number;\n month: number;\n monthlyTotal: number;\n uniqueDaysVisited: number;\n fullDaysCount: number;\n halfDaysCount: number;\n paidLeaveDaysCount: number;\n overtimeDaysCount: number;\n totalWorkDays: number;\n}\n\n/**\n * Get attendance for payroll calculation\n *\n * @example\n * ```typescript\n * import { getAttendance } from '@classytic/payroll';\n *\n * const attendance = await getAttendance(Attendance, {\n * organizationId: org._id,\n * employeeId: emp._id,\n * month: 3,\n * year: 2024,\n * expectedDays: 22,\n * });\n *\n * await payroll.processSalary({ employeeId, month: 3, year: 2024, attendance });\n * ```\n */\nexport async function getAttendance(\n AttendanceModel: Model<unknown>,\n params: {\n organizationId: ObjectIdLike;\n employeeId: ObjectIdLike;\n month: number;\n year: number;\n expectedDays: number;\n }\n): Promise<(AttendanceInput & { absentDays: number; overtimeDays: number }) | null> {\n const record = await AttendanceModel.findOne({\n organizationId: params.organizationId,\n targetId: params.employeeId,\n targetModel: 'Employee',\n year: params.year,\n month: params.month,\n }).lean<ClockInAttendance>();\n\n if (!record) return null;\n\n // Calculate actual days worked\n const fullDays = record.fullDaysCount || 0;\n const halfDays = (record.halfDaysCount || 0) * 0.5;\n const paidLeave = record.paidLeaveDaysCount || 0;\n const actualDays = fullDays + halfDays + paidLeave;\n const absentDays = Math.max(0, params.expectedDays - actualDays);\n const overtimeDays = record.overtimeDaysCount || 0;\n\n return {\n expectedDays: params.expectedDays,\n actualDays,\n absentDays,\n overtimeDays,\n };\n}\n\n/**\n * Get attendance for multiple employees (efficient batch operation)\n *\n * @example\n * ```typescript\n * const attendanceMap = await batchGetAttendance(Attendance, {\n * organizationId: org._id,\n * employeeIds: [emp1._id, emp2._id, emp3._id],\n * month: 3,\n * year: 2024,\n * expectedDays: 22,\n * });\n *\n * const emp1Attendance = attendanceMap.get(emp1._id.toString());\n * ```\n */\nexport async function batchGetAttendance(\n AttendanceModel: Model<unknown>,\n params: {\n organizationId: ObjectIdLike;\n employeeIds: ObjectIdLike[];\n month: number;\n year: number;\n expectedDays: number;\n }\n): Promise<Map<string, AttendanceInput & { absentDays: number; overtimeDays: number }>> {\n const records = await AttendanceModel.find({\n organizationId: params.organizationId,\n targetId: { $in: params.employeeIds },\n targetModel: 'Employee',\n year: params.year,\n month: params.month,\n }).lean<ClockInAttendance[]>();\n\n const map = new Map<string, AttendanceInput & { absentDays: number; overtimeDays: number }>();\n\n for (const record of records) {\n const fullDays = record.fullDaysCount || 0;\n const halfDays = (record.halfDaysCount || 0) * 0.5;\n const paidLeave = record.paidLeaveDaysCount || 0;\n const actualDays = fullDays + halfDays + paidLeave;\n const absentDays = Math.max(0, params.expectedDays - actualDays);\n const overtimeDays = record.overtimeDaysCount || 0;\n\n map.set(String(record.targetId), {\n expectedDays: params.expectedDays,\n actualDays,\n absentDays,\n overtimeDays,\n });\n }\n\n return map;\n}\n\n","/**\n * @classytic/payroll - Holiday Management\n *\n * Simple holiday storage and retrieval.\n * ONE way to manage holidays - no confusion.\n */\n\nimport { Schema, type Model, type Types, type SchemaDefinition } from 'mongoose';\n\n/**\n * Holiday document\n */\nexport interface Holiday {\n organizationId?: Types.ObjectId;\n date: Date;\n name: string;\n type: 'public' | 'company' | 'religious';\n paid: boolean;\n}\n\n/**\n * Create holiday schema\n *\n * @example\n * ```typescript\n * import { createHolidaySchema } from '@classytic/payroll';\n *\n * // Multi-tenant\n * const Holiday = model('Holiday', createHolidaySchema());\n *\n * // Single-tenant\n * const Holiday = model('Holiday', createHolidaySchema({ singleTenant: true }));\n * ```\n */\nexport function createHolidaySchema(options: {\n singleTenant?: boolean;\n} = {}): Schema {\n const fields: Record<string, unknown> = {\n date: { type: Date, required: true },\n name: { type: String, required: true },\n type: { \n type: String, \n enum: ['public', 'company', 'religious'], \n default: 'company' \n },\n paid: { type: Boolean, default: true },\n };\n\n if (!options.singleTenant) {\n fields.organizationId = {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: true,\n };\n }\n\n const schema = new Schema(fields as unknown as SchemaDefinition, { timestamps: true });\n\n // Indexes\n if (!options.singleTenant) {\n schema.index({ organizationId: 1, date: 1 });\n } else {\n schema.index({ date: 1 });\n }\n\n return schema;\n}\n\n/**\n * Get holidays for a period\n *\n * @example\n * ```typescript\n * const holidays = await getHolidays(Holiday, {\n * organizationId: org._id, // optional for single-tenant\n * startDate: new Date('2024-03-01'),\n * endDate: new Date('2024-03-31'),\n * });\n * ```\n */\nexport async function getHolidays(\n HolidayModel: Model<Holiday>,\n params: {\n organizationId?: Types.ObjectId;\n startDate: Date;\n endDate: Date;\n }\n): Promise<Date[]> {\n const query: Record<string, unknown> = {\n date: { $gte: params.startDate, $lte: params.endDate },\n };\n\n if (params.organizationId) {\n query.organizationId = params.organizationId;\n }\n\n const holidays = await HolidayModel.find(query).select('date').lean();\n return holidays.map((h: { date: Date }) => h.date);\n}\n\n","/**\n * @classytic/payroll - Pure Calculators\n *\n * Pure functions for payroll calculations.\n * No database dependencies - perfect for:\n * - Client-side salary previews\n * - Testing without DB setup\n * - Microservices/serverless\n * - Documentation examples\n *\n * All calculators are:\n * - Pure (no side effects)\n * - Stateless (no external dependencies)\n * - Testable (simple input/output)\n * - Reusable (can be imported anywhere)\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Salary Calculator\n// ============================================================================\n\nexport {\n calculateSalaryBreakdown,\n type SalaryCalculationInput,\n type ProcessedAllowance,\n type ProcessedDeduction,\n} from './salary.calculator.js';\n\n// ============================================================================\n// Pro-Rating Calculator\n// ============================================================================\n\nexport {\n calculateProRating,\n applyProRating,\n shouldProRate,\n type ProRatingInput,\n type ProRatingResult,\n} from './prorating.calculator.js';\n\n// ============================================================================\n// Attendance Calculator\n// ============================================================================\n\nexport {\n calculateAttendanceDeduction,\n calculateDailyRate,\n calculateHourlyRate,\n calculatePartialDayDeduction,\n calculateTotalAttendanceDeduction,\n type AttendanceDeductionInput,\n type AttendanceDeductionResult,\n} from './attendance.calculator.js';\n\n","/**\n * @classytic/payroll - Late Penalty Calculator\n *\n * Pure functions for calculating late arrival penalties.\n * No side effects, no DB calls - just math.\n */\n\nimport type {\n LateArrivalPolicy,\n LatePenaltyResult,\n LateOccurrence,\n PenaltyTier,\n} from '../types.js';\nimport { roundMoney } from '../../utils/money.js';\n\n// ============================================================================\n// Flat Penalty Mode\n// ============================================================================\n\n/**\n * Calculate penalty using flat rate per occurrence\n *\n * @example\n * ```typescript\n * // $50 per late occurrence\n * const result = calculateFlatPenalty(3, 50);\n * // → { amount: 150, occurrences: 3 }\n * ```\n */\nexport function calculateFlatPenalty(\n occurrenceCount: number,\n flatAmount: number\n): { amount: number; occurrences: number } {\n return {\n amount: occurrenceCount * flatAmount,\n occurrences: occurrenceCount,\n };\n}\n\n// ============================================================================\n// Per-Minute Penalty Mode\n// ============================================================================\n\n/**\n * Calculate penalty based on minutes late\n *\n * @example\n * ```typescript\n * // $2 per minute, 45 minutes late\n * const result = calculatePerMinutePenalty(45, 2);\n * // → { amount: 90, minutes: 45 }\n * ```\n */\nexport function calculatePerMinutePenalty(\n totalMinutesLate: number,\n perMinuteRate: number\n): { amount: number; minutes: number } {\n return {\n amount: roundMoney(totalMinutesLate * perMinuteRate, 2),\n minutes: totalMinutesLate,\n };\n}\n\n// ============================================================================\n// Percentage Penalty Mode\n// ============================================================================\n\n/**\n * Calculate penalty as percentage of daily wage\n *\n * @example\n * ```typescript\n * // 2% of $500 daily wage, 3 late occurrences\n * const result = calculatePercentagePenalty(3, 2, 500);\n * // → { amount: 30, percentage: 2 }\n * ```\n */\nexport function calculatePercentagePenalty(\n occurrenceCount: number,\n percentageRate: number,\n dailyWage: number\n): { amount: number; percentage: number } {\n const penaltyPerOccurrence = roundMoney((dailyWage * percentageRate) / 100, 2);\n return {\n amount: occurrenceCount * penaltyPerOccurrence,\n percentage: percentageRate,\n };\n}\n\n// ============================================================================\n// Tiered Penalty Mode (Progressive Discipline)\n// ============================================================================\n\n/**\n * Find which tier an occurrence falls into\n *\n * @example\n * ```typescript\n * const tiers = [\n * { from: 1, to: 2, penalty: 0, warning: true },\n * { from: 3, to: 4, penalty: 25 },\n * { from: 5, penalty: 50 },\n * ];\n *\n * findTier(1, tiers); // → tier 0 (warning)\n * findTier(3, tiers); // → tier 1 ($25)\n * findTier(6, tiers); // → tier 2 ($50)\n * ```\n */\nexport function findTier(occurrenceNumber: number, tiers: PenaltyTier[]): PenaltyTier | null {\n for (const tier of tiers) {\n // Open-ended tier (e.g., \"5th and above\")\n if (tier.to === undefined && occurrenceNumber >= tier.from) {\n return tier;\n }\n\n // Bounded tier (e.g., \"3rd to 4th\")\n if (tier.to !== undefined && occurrenceNumber >= tier.from && occurrenceNumber <= tier.to) {\n return tier;\n }\n }\n\n return null;\n}\n\n/**\n * Calculate penalty for a single occurrence using tiered system\n *\n * @example\n * ```typescript\n * const tiers = [\n * { from: 1, to: 2, penalty: 0, warning: true },\n * { from: 3, penalty: 25 },\n * ];\n *\n * calculateTieredPenaltyForOccurrence(1, tiers); // → 0 (warning)\n * calculateTieredPenaltyForOccurrence(3, tiers); // → 25\n * ```\n */\nexport function calculateTieredPenaltyForOccurrence(\n occurrenceNumber: number,\n tiers: PenaltyTier[]\n): { amount: number; tier: PenaltyTier | null; warning: boolean } {\n const tier = findTier(occurrenceNumber, tiers);\n\n if (!tier) {\n // No tier found - no penalty\n return { amount: 0, tier: null, warning: false };\n }\n\n if (tier.warning) {\n // Warning only - no financial penalty\n return { amount: 0, tier, warning: true };\n }\n\n return { amount: tier.penalty, tier, warning: false };\n}\n\n/**\n * Calculate total tiered penalties for multiple occurrences\n *\n * @example\n * ```typescript\n * const tiers = [\n * { from: 1, to: 2, penalty: 0, warning: true },\n * { from: 3, to: 4, penalty: 25 },\n * { from: 5, penalty: 50 },\n * ];\n *\n * // Employee has 5 late occurrences\n * const result = calculateTieredPenalty(5, 2, tiers);\n * // → {\n * // amount: 125, // 0 + 0 + 25 + 25 + 50\n * // breakdown: [...]\n * // }\n * ```\n */\nexport function calculateTieredPenalty(\n newOccurrences: number,\n currentOccurrenceCount: number,\n tiers: PenaltyTier[]\n): { amount: number; breakdown: Array<{ occurrence: number; penalty: number; tier?: number; warning: boolean }> } {\n let totalPenalty = 0;\n const breakdown: Array<{ occurrence: number; penalty: number; tier?: number; warning: boolean }> = [];\n\n for (let i = 0; i < newOccurrences; i++) {\n const occurrenceNumber = currentOccurrenceCount + i + 1;\n const result = calculateTieredPenaltyForOccurrence(occurrenceNumber, tiers);\n\n totalPenalty += result.amount;\n\n breakdown.push({\n occurrence: occurrenceNumber,\n penalty: result.amount,\n tier: result.tier ? tiers.indexOf(result.tier) : undefined,\n warning: result.warning,\n });\n }\n\n return { amount: totalPenalty, breakdown };\n}\n\n// ============================================================================\n// Main Late Penalty Calculator\n// ============================================================================\n\n/**\n * Calculate late arrival penalties based on policy\n *\n * @example\n * ```typescript\n * const policy: LateArrivalPolicy = {\n * enabled: true,\n * gracePeriod: 5,\n * mode: 'flat',\n * flatAmount: 50,\n * };\n *\n * const occurrences: LateOccurrence[] = [\n * { date: new Date(), scheduledTime, actualTime, minutesLate: 10 },\n * { date: new Date(), scheduledTime, actualTime, minutesLate: 3 }, // Within grace\n * ];\n *\n * const result = calculateLatePenalty({\n * policy,\n * occurrences,\n * dailyWage: 500,\n * });\n * // → { amount: 50, occurrences: 1, breakdown: [...] }\n * ```\n */\nexport function calculateLatePenalty(input: {\n policy: LateArrivalPolicy;\n occurrences?: LateOccurrence[];\n lateCount?: number;\n totalLateMinutes?: number;\n dailyWage?: number;\n currentOccurrenceCount?: number;\n}): LatePenaltyResult {\n const {\n policy,\n occurrences = [],\n lateCount = 0,\n totalLateMinutes = 0,\n dailyWage = 0,\n currentOccurrenceCount = 0,\n } = input;\n\n // If disabled, return zeros\n if (!policy.enabled) {\n return {\n amount: 0,\n occurrences: 0,\n breakdown: [],\n };\n }\n\n // Filter occurrences beyond grace period\n const penalizableOccurrences = occurrences.filter(\n (occ) => occ.minutesLate > policy.gracePeriod\n );\n\n const penalizableCount = penalizableOccurrences.length || Math.max(0, lateCount);\n const penalizableMinutes = penalizableOccurrences.reduce((sum, occ) => sum + Math.max(0, occ.minutesLate - policy.gracePeriod), 0) || totalLateMinutes;\n\n // No penalizable occurrences\n if (penalizableCount === 0) {\n return {\n amount: 0,\n occurrences: 0,\n breakdown: occurrences.map((occ) => ({\n date: occ.date,\n minutesLate: occ.minutesLate,\n penaltyAmount: 0,\n waived: true,\n reason: 'Within grace period',\n })),\n };\n }\n\n // Calculate based on mode\n let totalPenalty = 0;\n let tierBreakdown: Array<{ occurrence: number; penalty: number; tier?: number; warning: boolean }> = [];\n\n switch (policy.mode) {\n case 'flat':\n if (policy.flatAmount) {\n const result = calculateFlatPenalty(penalizableCount, policy.flatAmount);\n totalPenalty = result.amount;\n }\n break;\n\n case 'per-minute':\n if (policy.perMinuteRate) {\n const result = calculatePerMinutePenalty(penalizableMinutes, policy.perMinuteRate);\n totalPenalty = result.amount;\n }\n break;\n\n case 'percentage':\n if (policy.percentageRate && dailyWage > 0) {\n const result = calculatePercentagePenalty(penalizableCount, policy.percentageRate, dailyWage);\n totalPenalty = result.amount;\n }\n break;\n\n case 'tiered':\n if (policy.tiers && policy.tiers.length > 0) {\n const result = calculateTieredPenalty(penalizableCount, currentOccurrenceCount, policy.tiers);\n totalPenalty = result.amount;\n tierBreakdown = result.breakdown;\n }\n break;\n }\n\n // Apply caps if configured\n if (policy.maxPenaltyAmount) {\n totalPenalty = Math.min(totalPenalty, policy.maxPenaltyAmount.amount);\n }\n\n // Build breakdown\n const breakdown = penalizableOccurrences.map((occ, index) => {\n const tierInfo = tierBreakdown[index];\n const penaltyPerOccurrence = policy.mode === 'tiered' && tierInfo\n ? tierInfo.penalty\n : totalPenalty / penalizableCount;\n\n return {\n date: occ.date,\n minutesLate: occ.minutesLate,\n penaltyAmount: roundMoney(penaltyPerOccurrence, 2),\n tier: tierInfo?.tier,\n waived: false,\n };\n });\n\n return {\n amount: roundMoney(totalPenalty, 2),\n occurrences: penalizableCount,\n breakdown,\n };\n}\n","/**\n * @classytic/payroll - Overtime Calculator\n *\n * Pure functions for calculating overtime bonuses.\n * No side effects, no DB calls - just math.\n */\n\nimport type {\n OvertimePolicy,\n OvertimeBonusResult,\n OvertimeOccurrence,\n} from '../types.js';\nimport { roundMoney } from '../../utils/money.js';\n\n// ============================================================================\n// Daily Overtime\n// ============================================================================\n\n/**\n * Calculate daily overtime bonus\n *\n * @example\n * ```typescript\n * // Employee worked 10 hours, threshold is 8, rate is $100/hour\n * const result = calculateDailyOvertime(10, 8, 1.5, 100);\n * // → { amount: 100, overtimeHours: 2 }\n * // Calculation: 2 hours × $100 × 0.5 (extra) = $100\n * ```\n */\nexport function calculateDailyOvertime(\n hoursWorked: number,\n threshold: number,\n multiplier: number,\n hourlyRate: number\n): { amount: number; overtimeHours: number } {\n const overtimeHours = Math.max(0, hoursWorked - threshold);\n\n if (overtimeHours === 0) {\n return { amount: 0, overtimeHours: 0 };\n }\n\n // Calculate EXTRA pay (multiplier - 1)\n // e.g., 1.5x means 0.5x extra on top of regular pay\n const extraMultiplier = multiplier - 1;\n const bonus = roundMoney(overtimeHours * hourlyRate * extraMultiplier, 2);\n\n return { amount: bonus, overtimeHours };\n}\n\n// ============================================================================\n// Weekly Overtime\n// ============================================================================\n\n/**\n * Calculate weekly overtime bonus\n *\n * @example\n * ```typescript\n * // Employee worked 45 hours, threshold is 40, rate is $100/hour\n * const result = calculateWeeklyOvertime(45, 40, 1.5, 100);\n * // → { amount: 250, overtimeHours: 5 }\n * ```\n */\nexport function calculateWeeklyOvertime(\n hoursWorked: number,\n threshold: number,\n multiplier: number,\n hourlyRate: number\n): { amount: number; overtimeHours: number } {\n // Same logic as daily\n return calculateDailyOvertime(hoursWorked, threshold, multiplier, hourlyRate);\n}\n\n// ============================================================================\n// Monthly Overtime\n// ============================================================================\n\n/**\n * Calculate monthly overtime bonus\n *\n * @example\n * ```typescript\n * // Employee worked 170 hours, threshold is 160\n * const result = calculateMonthlyOvertime(170, 160, 1.5, 100);\n * // → { amount: 500, overtimeHours: 10 }\n * ```\n */\nexport function calculateMonthlyOvertime(\n hoursWorked: number,\n threshold: number,\n multiplier: number,\n hourlyRate: number\n): { amount: number; overtimeHours: number } {\n // Same logic as daily/weekly\n return calculateDailyOvertime(hoursWorked, threshold, multiplier, hourlyRate);\n}\n\n// ============================================================================\n// Weekend Premium\n// ============================================================================\n\n/**\n * Calculate weekend premium pay\n *\n * @example\n * ```typescript\n * // Employee worked 8 hours on Saturday\n * const result = calculateWeekendPremium(8, 1.5, 100, 'saturday');\n * // → { amount: 400, hours: 8 }\n * // Regular: 8 × $100 = $800\n * // Premium: 8 × $100 × 0.5 (extra) = $400\n * ```\n */\nexport function calculateWeekendPremium(\n hours: number,\n multiplier: number,\n hourlyRate: number,\n day: 'saturday' | 'sunday'\n): { amount: number; hours: number; day: string } {\n const extraMultiplier = multiplier - 1;\n const bonus = roundMoney(hours * hourlyRate * extraMultiplier, 2);\n\n return { amount: bonus, hours, day };\n}\n\n// ============================================================================\n// Night Shift Differential\n// ============================================================================\n\n/**\n * Calculate night shift differential\n *\n * @example\n * ```typescript\n * // Employee worked 8 hours during night shift (10pm-6am)\n * const result = calculateNightShiftDifferential(8, 1.2, 100);\n * // → { amount: 160, hours: 8 }\n * // Differential: 8 × $100 × 0.2 (extra) = $160\n * ```\n */\nexport function calculateNightShiftDifferential(\n hours: number,\n multiplier: number,\n hourlyRate: number\n): { amount: number; hours: number } {\n const extraMultiplier = multiplier - 1;\n const bonus = roundMoney(hours * hourlyRate * extraMultiplier, 2);\n\n return { amount: bonus, hours };\n}\n\n// ============================================================================\n// Main Overtime Calculator\n// ============================================================================\n\n/**\n * Calculate all overtime bonuses based on policy\n *\n * @example\n * ```typescript\n * const policy: OvertimePolicy = {\n * enabled: true,\n * mode: 'daily',\n * dailyThreshold: 8,\n * dailyMultiplier: 1.5,\n * };\n *\n * const occurrences: OvertimeOccurrence[] = [\n * { date: new Date(), type: 'daily', hours: 2, multiplier: 1.5 },\n * { date: new Date(), type: 'weekend-sunday', hours: 8, multiplier: 2.0 },\n * ];\n *\n * const result = calculateOvertimeBonus({\n * policy,\n * occurrences,\n * hourlyRate: 100,\n * });\n * ```\n */\nexport function calculateOvertimeBonus(input: {\n policy: OvertimePolicy;\n occurrences?: OvertimeOccurrence[];\n overtimeHours?: number;\n overtimeDays?: number;\n hourlyRate: number;\n}): OvertimeBonusResult {\n const {\n policy,\n occurrences = [],\n overtimeHours = 0,\n overtimeDays = 0,\n hourlyRate,\n } = input;\n\n // If disabled, return zeros\n if (!policy.enabled) {\n return {\n amount: 0,\n hours: 0,\n breakdown: [],\n };\n }\n\n let totalBonus = 0;\n let totalHours = 0;\n const breakdown: OvertimeBonusResult['breakdown'] = [];\n\n // Process detailed occurrences if provided\n if (occurrences.length > 0) {\n for (const occ of occurrences) {\n let bonus = 0;\n const extraMultiplier = occ.multiplier - 1;\n\n switch (occ.type) {\n case 'daily':\n case 'weekly':\n case 'monthly':\n bonus = roundMoney(occ.hours * hourlyRate * extraMultiplier, 2);\n break;\n\n case 'weekend-saturday':\n case 'weekend-sunday':\n bonus = roundMoney(occ.hours * hourlyRate * extraMultiplier, 2);\n break;\n\n case 'night-shift':\n bonus = roundMoney(occ.hours * hourlyRate * extraMultiplier, 2);\n break;\n }\n\n totalBonus += bonus;\n totalHours += occ.hours;\n\n breakdown.push({\n date: occ.date,\n type: occ.type,\n hours: occ.hours,\n rate: hourlyRate,\n multiplier: occ.multiplier,\n amount: bonus,\n });\n }\n }\n // Fallback to simple hours/days calculation\n else {\n const hours = overtimeHours || 0;\n const days = overtimeDays || 0;\n\n if (policy.mode === 'daily' && policy.dailyThreshold && policy.dailyMultiplier) {\n // Calculate based on days\n const hoursFromDays = days * policy.dailyThreshold;\n const result = calculateDailyOvertime(\n hoursFromDays + hours,\n policy.dailyThreshold,\n policy.dailyMultiplier,\n hourlyRate\n );\n totalBonus = result.amount;\n totalHours = result.overtimeHours;\n } else if (policy.mode === 'weekly' && policy.weeklyThreshold && policy.weeklyMultiplier) {\n const result = calculateWeeklyOvertime(\n hours,\n policy.weeklyThreshold,\n policy.weeklyMultiplier,\n hourlyRate\n );\n totalBonus = result.amount;\n totalHours = result.overtimeHours;\n } else if (policy.mode === 'monthly' && policy.monthlyThreshold && policy.monthlyMultiplier) {\n const result = calculateMonthlyOvertime(\n hours,\n policy.monthlyThreshold,\n policy.monthlyMultiplier,\n hourlyRate\n );\n totalBonus = result.amount;\n totalHours = result.overtimeHours;\n }\n\n // Add to breakdown if we calculated something\n if (totalBonus > 0) {\n breakdown.push({\n date: new Date(),\n type: policy.mode,\n hours: totalHours,\n rate: hourlyRate,\n multiplier: policy.dailyMultiplier || policy.weeklyMultiplier || policy.monthlyMultiplier || 1.5,\n amount: totalBonus,\n });\n }\n }\n\n return {\n amount: roundMoney(totalBonus, 2),\n hours: totalHours,\n breakdown,\n };\n}\n","/**\n * @classytic/payroll - Shift Compliance Calculators\n *\n * Main calculator that orchestrates all shift compliance calculations.\n */\n\nimport type {\n AttendancePolicy,\n ShiftComplianceData,\n ShiftComplianceResult,\n CalculateShiftComplianceInput,\n} from '../types.js';\n\nimport { calculateLatePenalty } from './late-penalty.js';\nimport { calculateOvertimeBonus } from './overtime.js';\n\n// Re-export individual calculators\nexport { calculateLatePenalty } from './late-penalty.js';\nexport { calculateOvertimeBonus } from './overtime.js';\n\n// ============================================================================\n// Main Shift Compliance Calculator\n// ============================================================================\n\n/**\n * Calculate complete shift compliance adjustments.\n *\n * This is the main function users call. It takes attendance data + policy\n * and returns penalties + bonuses.\n *\n * @example\n * ```typescript\n * const attendance: ShiftComplianceData = {\n * lateArrivals: 3,\n * totalLateMinutes: 45,\n * earlyDepartures: 1,\n * totalEarlyMinutes: 20,\n * overtimeHours: 8,\n * };\n *\n * const policy: AttendancePolicy = {\n * name: 'Manufacturing Policy',\n * lateArrival: {\n * enabled: true,\n * gracePeriod: 0,\n * mode: 'flat',\n * flatAmount: 50,\n * },\n * earlyDeparture: {\n * enabled: true,\n * gracePeriod: 0,\n * mode: 'flat',\n * flatAmount: 75,\n * },\n * overtime: {\n * enabled: true,\n * mode: 'daily',\n * dailyThreshold: 8,\n * dailyMultiplier: 1.5,\n * },\n * effectiveFrom: new Date(),\n * active: true,\n * };\n *\n * const result = calculateShiftCompliance({\n * attendance,\n * policy,\n * dailyWage: 1500,\n * hourlyRate: 200,\n * });\n *\n * // result = {\n * // latePenalty: { amount: 150, ... },\n * // earlyDeparturePenalty: { amount: 75, ... },\n * // overtimeBonus: { amount: 800, ... },\n * // totalPenalties: 225,\n * // totalBonuses: 800,\n * // netAdjustment: 575, // +800 - 225\n * // ...\n * // }\n * ```\n */\nexport function calculateShiftCompliance(\n input: CalculateShiftComplianceInput\n): ShiftComplianceResult {\n const {\n attendance,\n policy,\n dailyWage,\n hourlyRate,\n currentOccurrenceCount = 0,\n } = input;\n\n // Calculate late penalties\n const latePenalty = calculateLatePenalty({\n policy: policy.lateArrival,\n occurrences: attendance.lateOccurrences,\n lateCount: attendance.lateArrivals,\n totalLateMinutes: attendance.totalLateMinutes,\n dailyWage,\n currentOccurrenceCount,\n });\n\n // Calculate early departure penalties (same logic as late)\n const earlyDeparturePenalty = calculateLatePenalty({\n policy: policy.earlyDeparture,\n occurrences: attendance.earlyOccurrences?.map((occ) => ({\n date: occ.date,\n scheduledTime: occ.scheduledTime,\n actualTime: occ.actualTime,\n minutesLate: occ.minutesEarly, // Reuse \"late\" logic with \"early\" minutes\n })),\n lateCount: attendance.earlyDepartures,\n totalLateMinutes: attendance.totalEarlyMinutes,\n dailyWage,\n currentOccurrenceCount,\n });\n\n // Calculate overtime bonuses\n const overtimeBonus = calculateOvertimeBonus({\n policy: policy.overtime,\n occurrences: attendance.overtimeOccurrences,\n overtimeHours: attendance.overtimeHours,\n overtimeDays: attendance.overtimeDays,\n hourlyRate,\n });\n\n // Calculate totals\n const totalPenalties = latePenalty.amount + earlyDeparturePenalty.amount;\n const totalBonuses = overtimeBonus.amount;\n const netAdjustment = totalBonuses - totalPenalties;\n\n // Calculate compliance score (0-100)\n const totalOccurrences = latePenalty.occurrences + earlyDeparturePenalty.occurrences;\n const complianceScore = calculateComplianceScore(totalOccurrences, attendance);\n\n // Determine if employee is at risk\n const isAtRisk = determineRiskStatus(totalOccurrences, policy);\n\n return {\n latePenalty,\n earlyDeparturePenalty,\n overtimeBonus,\n totalPenalties,\n totalBonuses,\n netAdjustment,\n complianceScore,\n occurrenceCount: totalOccurrences,\n isAtRisk,\n policyId: policy.id,\n policyName: policy.name,\n };\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Calculate compliance score (0-100)\n *\n * Logic:\n * - 0 occurrences = 100\n * - 1 occurrence = 90\n * - 2 occurrences = 80\n * - 3 occurrences = 70\n * - etc.\n */\nfunction calculateComplianceScore(\n totalOccurrences: number,\n attendance: ShiftComplianceData\n): number {\n if (totalOccurrences === 0) {\n return 100;\n }\n\n // Deduct 10 points per occurrence, min 0\n return Math.max(0, 100 - (totalOccurrences * 10));\n}\n\n/**\n * Determine if employee is at risk of termination\n *\n * Logic:\n * - If policy has tiered penalties, check if at final tier\n * - Otherwise, flag if >7 occurrences (industry standard)\n */\nfunction determineRiskStatus(\n totalOccurrences: number,\n policy: AttendancePolicy\n): boolean {\n // Check tiered policy\n if (policy.lateArrival.mode === 'tiered' && policy.lateArrival.tiers) {\n const lastTier = policy.lateArrival.tiers[policy.lateArrival.tiers.length - 1];\n if (lastTier && lastTier.from && totalOccurrences >= lastTier.from) {\n return true;\n }\n }\n\n // Default threshold: 7 occurrences\n return totalOccurrences >= 7;\n}\n","/**\n * @classytic/payroll - Shift Compliance Configuration\n *\n * Default configurations and industry-standard preset policies.\n */\n\nimport type { AttendancePolicy } from './types.js';\n\n// ============================================================================\n// Default Policy\n// ============================================================================\n\n/**\n * Default attendance policy (moderate, office-friendly)\n */\nexport const DEFAULT_ATTENDANCE_POLICY: Omit<AttendancePolicy, 'name' | 'effectiveFrom' | 'active'> = {\n lateArrival: {\n enabled: true,\n gracePeriod: 10, // 10 minutes grace\n mode: 'tiered',\n tiers: [\n { from: 1, to: 2, penalty: 0, warning: true }, // 1st-2nd: warning\n { from: 3, to: 4, penalty: 25 }, // 3rd-4th: $25\n { from: 5, penalty: 50 }, // 5th+: $50\n ],\n maxPenaltiesPerPeriod: {\n count: 5,\n period: 'monthly',\n },\n resetOccurrenceCount: 'quarterly',\n },\n\n earlyDeparture: {\n enabled: true,\n gracePeriod: 10,\n mode: 'tiered',\n tiers: [\n { from: 1, to: 2, penalty: 0, warning: true },\n { from: 3, to: 4, penalty: 30 },\n { from: 5, penalty: 60 },\n ],\n maxPenaltiesPerPeriod: {\n count: 5,\n period: 'monthly',\n },\n resetOccurrenceCount: 'quarterly',\n },\n\n overtime: {\n enabled: true,\n mode: 'daily',\n dailyThreshold: 8,\n dailyMultiplier: 1.5,\n weeklyThreshold: 40,\n weeklyMultiplier: 1.5,\n },\n\n clockRounding: {\n enabled: false,\n roundTo: 15,\n mode: 'nearest',\n },\n};\n\n// ============================================================================\n// Industry Preset Policies\n// ============================================================================\n\n/**\n * Manufacturing/Factory policy (strict, zero tolerance)\n */\nexport const MANUFACTURING_POLICY: Omit<AttendancePolicy, 'name' | 'effectiveFrom' | 'active'> = {\n lateArrival: {\n enabled: true,\n gracePeriod: 0, // No grace period\n mode: 'flat',\n flatAmount: 100, // $100 per occurrence\n maxPenaltiesPerPeriod: {\n count: 5,\n period: 'monthly',\n },\n resetOccurrenceCount: 'quarterly',\n },\n\n earlyDeparture: {\n enabled: true,\n gracePeriod: 0,\n mode: 'flat',\n flatAmount: 150, // Higher penalty for early departure\n maxPenaltiesPerPeriod: {\n count: 5,\n period: 'monthly',\n },\n resetOccurrenceCount: 'quarterly',\n },\n\n overtime: {\n enabled: true,\n mode: 'daily',\n dailyThreshold: 8,\n dailyMultiplier: 1.5,\n weeklyThreshold: 40,\n weeklyMultiplier: 2.0, // Double time for weekly OT\n },\n\n clockRounding: {\n enabled: true,\n roundTo: 15,\n mode: 'down', // Round down (favor employer)\n },\n};\n\n/**\n * Retail policy (flexible with weekend premiums)\n */\nexport const RETAIL_POLICY: Omit<AttendancePolicy, 'name' | 'effectiveFrom' | 'active'> = {\n lateArrival: {\n enabled: true,\n gracePeriod: 5,\n mode: 'flat',\n flatAmount: 25,\n maxPenaltiesPerPeriod: {\n count: 5,\n period: 'monthly',\n },\n resetOccurrenceCount: 'monthly',\n },\n\n earlyDeparture: {\n enabled: true,\n gracePeriod: 5,\n mode: 'flat',\n flatAmount: 25,\n maxPenaltiesPerPeriod: {\n count: 5,\n period: 'monthly',\n },\n resetOccurrenceCount: 'monthly',\n },\n\n overtime: {\n enabled: true,\n mode: 'weekly',\n weeklyThreshold: 40,\n weeklyMultiplier: 1.5,\n weekendPremium: {\n saturday: 1.5, // Time and half on Saturday\n sunday: 2.0, // Double time on Sunday\n },\n },\n\n clockRounding: {\n enabled: true,\n roundTo: 5,\n mode: 'nearest',\n },\n};\n\n/**\n * Office/Tech policy (very flexible, progressive discipline)\n */\nexport const OFFICE_POLICY: Omit<AttendancePolicy, 'name' | 'effectiveFrom' | 'active'> = {\n lateArrival: {\n enabled: true,\n gracePeriod: 15, // 15 minutes grace\n mode: 'tiered',\n tiers: [\n { from: 1, to: 3, penalty: 0, warning: true }, // 1st-3rd: warning only\n { from: 4, to: 5, penalty: 20 }, // 4th-5th: $20\n { from: 6, penalty: 40 }, // 6th+: $40\n ],\n maxPenaltiesPerPeriod: {\n count: 3,\n period: 'monthly',\n },\n resetOccurrenceCount: 'quarterly',\n },\n\n earlyDeparture: {\n enabled: false, // Often not tracked in office environments\n gracePeriod: 30,\n mode: 'flat',\n flatAmount: 0,\n },\n\n overtime: {\n enabled: true,\n mode: 'weekly',\n weeklyThreshold: 40,\n weeklyMultiplier: 1.5,\n },\n\n clockRounding: {\n enabled: false, // No rounding for office workers\n roundTo: 15,\n mode: 'nearest',\n },\n};\n\n/**\n * Healthcare policy (night shift differential, weekend premiums)\n */\nexport const HEALTHCARE_POLICY: Omit<AttendancePolicy, 'name' | 'effectiveFrom' | 'active'> = {\n lateArrival: {\n enabled: true,\n gracePeriod: 5,\n mode: 'flat',\n flatAmount: 50,\n maxPenaltiesPerPeriod: {\n count: 3,\n period: 'monthly',\n },\n resetOccurrenceCount: 'quarterly',\n },\n\n earlyDeparture: {\n enabled: true,\n gracePeriod: 5,\n mode: 'flat',\n flatAmount: 75, // Higher penalty due to patient care\n maxPenaltiesPerPeriod: {\n count: 3,\n period: 'monthly',\n },\n resetOccurrenceCount: 'quarterly',\n },\n\n overtime: {\n enabled: true,\n mode: 'daily',\n dailyThreshold: 8,\n dailyMultiplier: 1.5,\n weekendPremium: {\n saturday: 1.5,\n sunday: 2.0,\n },\n nightShiftDifferential: {\n startHour: 22, // 10pm\n endHour: 6, // 6am\n multiplier: 1.3, // 30% premium\n },\n },\n\n clockRounding: {\n enabled: true,\n roundTo: 15,\n mode: 'nearest',\n },\n};\n\n/**\n * Hospitality policy (flexible, weekend/night premiums)\n */\nexport const HOSPITALITY_POLICY: Omit<AttendancePolicy, 'name' | 'effectiveFrom' | 'active'> = {\n lateArrival: {\n enabled: true,\n gracePeriod: 5,\n mode: 'percentage',\n percentageRate: 1, // 1% of daily wage per occurrence\n maxPenaltiesPerPeriod: {\n count: 5,\n period: 'monthly',\n },\n resetOccurrenceCount: 'monthly',\n },\n\n earlyDeparture: {\n enabled: true,\n gracePeriod: 5,\n mode: 'percentage',\n percentageRate: 1.5, // 1.5% of daily wage\n maxPenaltiesPerPeriod: {\n count: 5,\n period: 'monthly',\n },\n resetOccurrenceCount: 'monthly',\n },\n\n overtime: {\n enabled: true,\n mode: 'weekly',\n weeklyThreshold: 40,\n weeklyMultiplier: 1.5,\n weekendPremium: {\n saturday: 1.25,\n sunday: 1.5,\n },\n nightShiftDifferential: {\n startHour: 22,\n endHour: 6,\n multiplier: 1.2,\n },\n },\n\n clockRounding: {\n enabled: true,\n roundTo: 10,\n mode: 'nearest',\n },\n};\n\n// ============================================================================\n// Preset Factory\n// ============================================================================\n\n/**\n * Get a complete policy from a preset\n *\n * @example\n * ```typescript\n * const policy = createPolicyFromPreset('manufacturing', {\n * name: 'Factory Floor Policy',\n * organizationId: orgId,\n * });\n * ```\n */\nexport function createPolicyFromPreset(\n preset: 'default' | 'manufacturing' | 'retail' | 'office' | 'healthcare' | 'hospitality',\n overrides?: Partial<AttendancePolicy>\n): AttendancePolicy {\n let basePolicy: Omit<AttendancePolicy, 'name' | 'effectiveFrom' | 'active'>;\n\n switch (preset) {\n case 'manufacturing':\n basePolicy = MANUFACTURING_POLICY;\n break;\n case 'retail':\n basePolicy = RETAIL_POLICY;\n break;\n case 'office':\n basePolicy = OFFICE_POLICY;\n break;\n case 'healthcare':\n basePolicy = HEALTHCARE_POLICY;\n break;\n case 'hospitality':\n basePolicy = HOSPITALITY_POLICY;\n break;\n default:\n basePolicy = DEFAULT_ATTENDANCE_POLICY;\n }\n\n return {\n ...basePolicy,\n name: overrides?.name || `${preset.charAt(0).toUpperCase() + preset.slice(1)} Policy`,\n effectiveFrom: overrides?.effectiveFrom || new Date(),\n active: overrides?.active ?? true,\n ...overrides,\n };\n}\n","/**\n * @classytic/payroll - Shift Compliance Fluent Builders\n *\n * DX-friendly fluent API for creating attendance policies programmatically.\n *\n * @example\n * ```typescript\n * const policy = AttendancePolicyBuilder.create()\n * .named('Tech Department Policy')\n * .description('Flexible policy for tech workers')\n * .lateArrival()\n * .enable()\n * .gracePeriod(15)\n * .tieredPenalty()\n * .tier(1, 3).warning()\n * .tier(4, 5).penalty(20)\n * .tier(6).penalty(40)\n * .end()\n * .maxPenalties(3, 'monthly')\n * .resetOccurrences('quarterly')\n * .end()\n * .overtime()\n * .enable()\n * .mode('weekly')\n * .weeklyThreshold(40, 1.5)\n * .end()\n * .build();\n * ```\n */\n\nimport type {\n AttendancePolicy,\n LateArrivalPolicy,\n EarlyDeparturePolicy,\n OvertimePolicy,\n ClockRoundingPolicy,\n PenaltyTier,\n} from './types.js';\nimport type { ObjectIdLike } from './types.js';\n\n// ============================================================================\n// Late Arrival / Early Departure Policy Builder\n// ============================================================================\n\n/**\n * Builder for late arrival or early departure policies.\n * Uses same structure for both since the logic is identical.\n */\nexport class LatePolicyBuilder<TParent = unknown> {\n private policy: Partial<LateArrivalPolicy> = {\n enabled: true,\n gracePeriod: 0,\n };\n private parent?: TParent;\n\n constructor(parent?: TParent) {\n this.parent = parent;\n }\n\n /**\n * Enable this policy\n */\n enable(): this {\n this.policy.enabled = true;\n return this;\n }\n\n /**\n * Disable this policy\n */\n disable(): this {\n this.policy.enabled = false;\n return this;\n }\n\n /**\n * Set grace period in minutes (how many minutes late before penalty applies)\n */\n gracePeriod(minutes: number): this {\n this.policy.gracePeriod = minutes;\n return this;\n }\n\n /**\n * Use flat penalty mode (same penalty for each occurrence)\n *\n * @param amount - Penalty amount per occurrence\n */\n flatPenalty(amount: number): this {\n this.policy.mode = 'flat';\n this.policy.flatAmount = amount;\n delete this.policy.perMinuteRate;\n delete this.policy.percentageRate;\n delete this.policy.tiers;\n return this;\n }\n\n /**\n * Use per-minute penalty mode (penalty based on minutes late)\n *\n * @param rate - Penalty per minute late\n */\n perMinutePenalty(rate: number): this {\n this.policy.mode = 'per-minute';\n this.policy.perMinuteRate = rate;\n delete this.policy.flatAmount;\n delete this.policy.percentageRate;\n delete this.policy.tiers;\n return this;\n }\n\n /**\n * Use percentage penalty mode (percentage of daily wage)\n *\n * @param percentage - Percentage of daily wage (e.g., 2 for 2%)\n */\n percentagePenalty(percentage: number): this {\n this.policy.mode = 'percentage';\n this.policy.percentageRate = percentage;\n delete this.policy.flatAmount;\n delete this.policy.perMinuteRate;\n delete this.policy.tiers;\n return this;\n }\n\n /**\n * Start building tiered penalty (progressive discipline)\n *\n * @example\n * ```typescript\n * .tieredPenalty()\n * .tier(1, 2).warning()\n * .tier(3, 4).penalty(25)\n * .tier(5).penalty(50)\n * .end()\n * ```\n */\n tieredPenalty(): TieredPenaltyBuilder<this> {\n this.policy.mode = 'tiered';\n this.policy.tiers = [];\n delete this.policy.flatAmount;\n delete this.policy.perMinuteRate;\n delete this.policy.percentageRate;\n return new TieredPenaltyBuilder(this);\n }\n\n /**\n * Set maximum penalties per period (caps total penalties)\n *\n * @param count - Max number of penalties\n * @param period - Period type ('daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly')\n */\n maxPenalties(count: number, period: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'): this {\n this.policy.maxPenaltiesPerPeriod = { count, period };\n return this;\n }\n\n /**\n * Set when to reset occurrence counter\n *\n * @param period - Reset period ('monthly' | 'quarterly' | 'yearly')\n */\n resetOccurrences(period: 'monthly' | 'quarterly' | 'yearly'): this {\n this.policy.resetOccurrenceCount = period;\n return this;\n }\n\n /**\n * Add a custom tier (advanced usage)\n */\n addTier(tier: PenaltyTier): this {\n if (!this.policy.tiers) {\n this.policy.tiers = [];\n }\n this.policy.tiers.push(tier);\n return this;\n }\n\n /**\n * Finish building this policy and return to parent builder\n */\n end(): TParent {\n if (!this.parent) {\n throw new Error('Cannot call end() without parent builder');\n }\n return this.parent;\n }\n\n /**\n * Build the policy (for standalone usage)\n */\n build(): LateArrivalPolicy {\n // Validate required fields\n if (this.policy.mode === undefined) {\n throw new Error('Penalty mode is required. Use flatPenalty(), perMinutePenalty(), percentagePenalty(), or tieredPenalty()');\n }\n\n // Validate mode-specific fields\n if (this.policy.mode === 'flat' && this.policy.flatAmount === undefined) {\n throw new Error('flatAmount is required for flat penalty mode');\n }\n if (this.policy.mode === 'per-minute' && this.policy.perMinuteRate === undefined) {\n throw new Error('perMinuteRate is required for per-minute penalty mode');\n }\n if (this.policy.mode === 'percentage' && this.policy.percentageRate === undefined) {\n throw new Error('percentageRate is required for percentage penalty mode');\n }\n if (this.policy.mode === 'tiered' && (!this.policy.tiers || this.policy.tiers.length === 0)) {\n throw new Error('At least one tier is required for tiered penalty mode');\n }\n\n return this.policy as LateArrivalPolicy;\n }\n\n /** @internal */\n _getPolicy(): Partial<LateArrivalPolicy> {\n return this.policy;\n }\n}\n\n// ============================================================================\n// Tiered Penalty Builder\n// ============================================================================\n\n/**\n * Builder for tiered penalties (progressive discipline)\n */\nexport class TieredPenaltyBuilder<TParent> {\n private tiers: PenaltyTier[] = [];\n private parent: TParent;\n private currentTier: Partial<PenaltyTier> = {};\n\n constructor(parent: TParent) {\n this.parent = parent;\n }\n\n /**\n * Start a new tier\n *\n * @param from - Starting occurrence number (1-indexed)\n * @param to - Ending occurrence number (optional, omit for open-ended tier)\n */\n tier(from: number, to?: number): this {\n // Save previous tier if exists\n if (Object.keys(this.currentTier).length > 0) {\n this.saveTier();\n }\n\n this.currentTier = { from, to };\n return this;\n }\n\n /**\n * Set this tier as warning only (no financial penalty)\n */\n warning(): this {\n this.currentTier.penalty = 0;\n this.currentTier.warning = true;\n return this;\n }\n\n /**\n * Set penalty amount for this tier\n */\n penalty(amount: number): this {\n this.currentTier.penalty = amount;\n this.currentTier.warning = false;\n return this;\n }\n\n /**\n * Finish building tiers and return to parent\n */\n end(): TParent {\n // Save last tier\n if (Object.keys(this.currentTier).length > 0) {\n this.saveTier();\n }\n\n // Update parent's tiers via internal accessor\n if (this.parent instanceof LatePolicyBuilder) {\n this.parent._getPolicy().tiers = this.tiers;\n }\n\n return this.parent;\n }\n\n private saveTier(): void {\n if (this.currentTier.from === undefined) {\n throw new Error('Tier must have a \"from\" value. Use .tier(from, to?)');\n }\n if (this.currentTier.penalty === undefined) {\n throw new Error('Tier must have a penalty or be marked as warning. Use .penalty(amount) or .warning()');\n }\n\n this.tiers.push(this.currentTier as PenaltyTier);\n this.currentTier = {};\n }\n}\n\n// ============================================================================\n// Overtime Policy Builder\n// ============================================================================\n\n/**\n * Builder for overtime policies\n */\nexport class OvertimePolicyBuilder<TParent = unknown> {\n private policy: Partial<OvertimePolicy> = {\n enabled: true,\n };\n private parent?: TParent;\n\n constructor(parent?: TParent) {\n this.parent = parent;\n }\n\n /**\n * Enable overtime calculations\n */\n enable(): this {\n this.policy.enabled = true;\n return this;\n }\n\n /**\n * Disable overtime calculations\n */\n disable(): this {\n this.policy.enabled = false;\n return this;\n }\n\n /**\n * Set overtime calculation mode\n */\n mode(mode: 'daily' | 'weekly' | 'monthly'): this {\n this.policy.mode = mode;\n return this;\n }\n\n /**\n * Set daily overtime threshold and multiplier\n *\n * @param hours - Hours threshold (e.g., 8)\n * @param multiplier - Overtime multiplier (e.g., 1.5 for time-and-a-half)\n */\n dailyThreshold(hours: number, multiplier: number): this {\n this.policy.dailyThreshold = hours;\n this.policy.dailyMultiplier = multiplier;\n return this;\n }\n\n /**\n * Set weekly overtime threshold and multiplier\n *\n * @param hours - Hours threshold (e.g., 40)\n * @param multiplier - Overtime multiplier (e.g., 1.5 for time-and-a-half)\n */\n weeklyThreshold(hours: number, multiplier: number): this {\n this.policy.weeklyThreshold = hours;\n this.policy.weeklyMultiplier = multiplier;\n return this;\n }\n\n /**\n * Set monthly overtime threshold and multiplier\n *\n * @param hours - Hours threshold (e.g., 160)\n * @param multiplier - Overtime multiplier (e.g., 2.0 for double time)\n */\n monthlyThreshold(hours: number, multiplier: number): this {\n this.policy.monthlyThreshold = hours;\n this.policy.monthlyMultiplier = multiplier;\n return this;\n }\n\n /**\n * Set weekend premium rates\n *\n * @param saturday - Saturday multiplier (e.g., 1.5)\n * @param sunday - Sunday multiplier (e.g., 2.0)\n */\n weekendPremium(saturday: number, sunday: number): this {\n this.policy.weekendPremium = { saturday, sunday };\n return this;\n }\n\n /**\n * Set night shift differential\n *\n * @param startHour - Start hour (24-hour format, e.g., 22 for 10pm)\n * @param endHour - End hour (24-hour format, e.g., 6 for 6am)\n * @param multiplier - Night shift multiplier (e.g., 1.3 for 30% premium)\n */\n nightShiftDifferential(startHour: number, endHour: number, multiplier: number): this {\n this.policy.nightShiftDifferential = { startHour, endHour, multiplier };\n return this;\n }\n\n /**\n * Finish building this policy and return to parent builder\n */\n end(): TParent {\n if (!this.parent) {\n throw new Error('Cannot call end() without parent builder');\n }\n return this.parent;\n }\n\n /**\n * Build the policy (for standalone usage)\n */\n build(): OvertimePolicy {\n // Validate required fields\n if (this.policy.mode === undefined) {\n throw new Error('Overtime mode is required. Use .mode(\"daily\" | \"weekly\" | \"monthly\")');\n }\n\n // Validate mode-specific fields\n if (this.policy.mode === 'daily' && (this.policy.dailyThreshold === undefined || this.policy.dailyMultiplier === undefined)) {\n throw new Error('dailyThreshold and dailyMultiplier are required for daily mode. Use .dailyThreshold(hours, multiplier)');\n }\n if (this.policy.mode === 'weekly' && (this.policy.weeklyThreshold === undefined || this.policy.weeklyMultiplier === undefined)) {\n throw new Error('weeklyThreshold and weeklyMultiplier are required for weekly mode. Use .weeklyThreshold(hours, multiplier)');\n }\n if (this.policy.mode === 'monthly' && (this.policy.monthlyThreshold === undefined || this.policy.monthlyMultiplier === undefined)) {\n throw new Error('monthlyThreshold and monthlyMultiplier are required for monthly mode. Use .monthlyThreshold(hours, multiplier)');\n }\n\n return this.policy as OvertimePolicy;\n }\n\n /** @internal */\n _getPolicy(): Partial<OvertimePolicy> {\n return this.policy;\n }\n}\n\n// ============================================================================\n// Clock Rounding Policy Builder\n// ============================================================================\n\n/**\n * Builder for clock rounding policies\n */\nexport class ClockRoundingPolicyBuilder<TParent = unknown> {\n private policy: Partial<ClockRoundingPolicy> = {\n enabled: false,\n };\n private parent?: TParent;\n\n constructor(parent?: TParent) {\n this.parent = parent;\n }\n\n /**\n * Enable clock rounding\n */\n enable(): this {\n this.policy.enabled = true;\n return this;\n }\n\n /**\n * Disable clock rounding\n */\n disable(): this {\n this.policy.enabled = false;\n return this;\n }\n\n /**\n * Set rounding interval in minutes\n *\n * @param minutes - Round to nearest N minutes (e.g., 5, 10, 15)\n */\n roundTo(minutes: 5 | 10 | 15): this {\n this.policy.roundTo = minutes;\n return this;\n }\n\n /**\n * Set rounding mode\n *\n * @param mode - 'up' (favor employee) | 'down' (favor employer) | 'nearest' (neutral)\n */\n roundingMode(mode: 'up' | 'down' | 'nearest'): this {\n this.policy.mode = mode;\n return this;\n }\n\n /**\n * Finish building this policy and return to parent builder\n */\n end(): TParent {\n if (!this.parent) {\n throw new Error('Cannot call end() without parent builder');\n }\n return this.parent;\n }\n\n /**\n * Build the policy (for standalone usage)\n */\n build(): ClockRoundingPolicy {\n if (this.policy.enabled && (this.policy.roundTo === undefined || this.policy.mode === undefined)) {\n throw new Error('roundTo and mode are required when clock rounding is enabled');\n }\n\n return this.policy as ClockRoundingPolicy;\n }\n\n /** @internal */\n _getPolicy(): Partial<ClockRoundingPolicy> {\n return this.policy;\n }\n}\n\n// ============================================================================\n// Main Attendance Policy Builder\n// ============================================================================\n\n/**\n * Main builder for creating complete attendance policies\n *\n * @example\n * ```typescript\n * const policy = AttendancePolicyBuilder.create()\n * .named('Manufacturing Policy')\n * .description('Strict policy for factory floor')\n * .organizationId(orgId)\n * .lateArrival()\n * .enable()\n * .gracePeriod(0)\n * .flatPenalty(100)\n * .maxPenalties(5, 'monthly')\n * .resetOccurrences('quarterly')\n * .end()\n * .earlyDeparture()\n * .enable()\n * .gracePeriod(0)\n * .flatPenalty(150)\n * .end()\n * .overtime()\n * .enable()\n * .mode('daily')\n * .dailyThreshold(8, 1.5)\n * .weeklyThreshold(40, 2.0)\n * .end()\n * .clockRounding()\n * .enable()\n * .roundTo(15)\n * .roundingMode('down')\n * .end()\n * .effectiveFrom(new Date('2025-01-01'))\n * .build();\n * ```\n */\nexport class AttendancePolicyBuilder {\n private policy: Partial<AttendancePolicy> = {\n active: true,\n effectiveFrom: new Date(),\n };\n\n private lateArrivalBuilder?: LatePolicyBuilder<this>;\n private earlyDepartureBuilder?: LatePolicyBuilder<this>;\n private overtimeBuilder?: OvertimePolicyBuilder<this>;\n private clockRoundingBuilder?: ClockRoundingPolicyBuilder<this>;\n\n /**\n * Create a new policy builder\n */\n static create(): AttendancePolicyBuilder {\n return new AttendancePolicyBuilder();\n }\n\n /**\n * Set policy name\n */\n named(name: string): this {\n this.policy.name = name;\n return this;\n }\n\n /**\n * Set policy description\n */\n description(description: string): this {\n this.policy.description = description;\n return this;\n }\n\n /**\n * Set organization ID (for multi-tenant systems)\n */\n organizationId(id: ObjectIdLike): this {\n this.policy.organizationId = id;\n return this;\n }\n\n /**\n * Set policy ID (for updates)\n */\n id(id: string): this {\n this.policy.id = id;\n return this;\n }\n\n /**\n * Set effective from date\n */\n effectiveFrom(date: Date): this {\n this.policy.effectiveFrom = date;\n return this;\n }\n\n /**\n * Set effective to date (when policy expires)\n */\n effectiveTo(date: Date | null): this {\n this.policy.effectiveTo = date;\n return this;\n }\n\n /**\n * Set policy active status\n */\n active(active: boolean): this {\n this.policy.active = active;\n return this;\n }\n\n /**\n * Start building late arrival policy\n */\n lateArrival(): LatePolicyBuilder<this> {\n if (!this.lateArrivalBuilder) {\n this.lateArrivalBuilder = new LatePolicyBuilder<this>(this);\n }\n return this.lateArrivalBuilder;\n }\n\n /**\n * Start building early departure policy\n */\n earlyDeparture(): LatePolicyBuilder<this> {\n if (!this.earlyDepartureBuilder) {\n this.earlyDepartureBuilder = new LatePolicyBuilder<this>(this);\n }\n return this.earlyDepartureBuilder;\n }\n\n /**\n * Start building overtime policy\n */\n overtime(): OvertimePolicyBuilder<this> {\n if (!this.overtimeBuilder) {\n this.overtimeBuilder = new OvertimePolicyBuilder<this>(this);\n }\n return this.overtimeBuilder;\n }\n\n /**\n * Start building clock rounding policy\n */\n clockRounding(): ClockRoundingPolicyBuilder<this> {\n if (!this.clockRoundingBuilder) {\n this.clockRoundingBuilder = new ClockRoundingPolicyBuilder<this>(this);\n }\n return this.clockRoundingBuilder;\n }\n\n /**\n * Build the complete attendance policy\n */\n build(): AttendancePolicy {\n // Validate required fields\n if (!this.policy.name) {\n throw new Error('Policy name is required. Use .named(name)');\n }\n\n // Build sub-policies\n if (this.lateArrivalBuilder) {\n this.policy.lateArrival = this.lateArrivalBuilder.build();\n } else {\n throw new Error('Late arrival policy is required. Use .lateArrival()...end()');\n }\n\n if (this.earlyDepartureBuilder) {\n this.policy.earlyDeparture = this.earlyDepartureBuilder.build();\n } else {\n throw new Error('Early departure policy is required. Use .earlyDeparture()...end()');\n }\n\n if (this.overtimeBuilder) {\n this.policy.overtime = this.overtimeBuilder.build();\n } else {\n throw new Error('Overtime policy is required. Use .overtime()...end()');\n }\n\n // Clock rounding is optional\n if (this.clockRoundingBuilder) {\n this.policy.clockRounding = this.clockRoundingBuilder.build();\n }\n\n return this.policy as AttendancePolicy;\n }\n}\n\n// ============================================================================\n// Standalone Builder Exports\n// ============================================================================\n\n/**\n * Create a standalone late arrival policy builder\n */\nexport function createLatePolicyBuilder(): LatePolicyBuilder<void> {\n return new LatePolicyBuilder<void>();\n}\n\n/**\n * Create a standalone overtime policy builder\n */\nexport function createOvertimePolicyBuilder(): OvertimePolicyBuilder<void> {\n return new OvertimePolicyBuilder<void>();\n}\n\n/**\n * Create a standalone clock rounding policy builder\n */\nexport function createClockRoundingPolicyBuilder(): ClockRoundingPolicyBuilder<void> {\n return new ClockRoundingPolicyBuilder<void>();\n}\n","/**\n * @classytic/payroll - Shift Compliance Mongoose Schemas\n *\n * OPTIONAL schemas for users who want to store attendance policies in MongoDB.\n *\n * These schemas are NOT required to use the shift compliance calculators.\n * The calculators work with plain objects. Use these schemas only if you\n * want to persist policies in your database.\n *\n * @example\n * ```typescript\n * import { AttendancePolicySchema } from '@classytic/payroll';\n * import { Schema, model } from 'mongoose';\n *\n * // Use as-is\n * const AttendancePolicy = model('AttendancePolicy', AttendancePolicySchema);\n *\n * // Or extend with your own fields\n * const CustomPolicySchema = new Schema({\n * ...AttendancePolicySchema.obj,\n * customField: String,\n * approvedBy: { type: Schema.Types.ObjectId, ref: 'User' },\n * });\n * ```\n */\n\nimport { Schema, type SchemaDefinition, type Document, type Model, type Types } from 'mongoose';\n\n// ============================================================================\n// Sub-Schema Definitions\n// ============================================================================\n\n/**\n * Schema definition for penalty tiers (progressive discipline)\n */\nexport const PenaltyTierSchemaDefinition: SchemaDefinition = {\n from: {\n type: Number,\n required: true,\n min: 1,\n description: 'Starting occurrence number (1-indexed)',\n },\n to: {\n type: Number,\n min: 1,\n description: 'Ending occurrence number (optional for open-ended tier)',\n },\n penalty: {\n type: Number,\n required: true,\n min: 0,\n description: 'Penalty amount (0 for warnings)',\n },\n warning: {\n type: Boolean,\n default: false,\n description: 'Whether this is a warning-only tier',\n },\n};\n\n/**\n * Schema for penalty tiers\n */\nexport const PenaltyTierSchema: Schema = new Schema(PenaltyTierSchemaDefinition, {\n _id: false,\n timestamps: false,\n});\n\n/**\n * Schema definition for max penalties per period\n */\nexport const MaxPenaltiesSchemaDefinition: SchemaDefinition = {\n count: {\n type: Number,\n required: true,\n min: 1,\n description: 'Maximum number of penalties allowed in period',\n },\n period: {\n type: String,\n enum: ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'],\n required: true,\n description: 'Period type',\n },\n};\n\n/**\n * Schema for max penalties per period\n */\nexport const MaxPenaltiesSchema: Schema = new Schema(MaxPenaltiesSchemaDefinition, {\n _id: false,\n timestamps: false,\n});\n\n/**\n * Schema definition for late arrival policy\n */\nexport const LateArrivalPolicySchemaDefinition: SchemaDefinition = {\n enabled: {\n type: Boolean,\n required: true,\n default: true,\n description: 'Whether late arrival penalties are enabled',\n },\n gracePeriod: {\n type: Number,\n required: true,\n min: 0,\n max: 60,\n default: 0,\n description: 'Grace period in minutes before penalty applies',\n },\n mode: {\n type: String,\n enum: ['flat', 'per-minute', 'percentage', 'tiered'],\n required: true,\n description: 'Penalty calculation mode',\n },\n flatAmount: {\n type: Number,\n min: 0,\n description: 'Flat penalty amount per occurrence (for flat mode)',\n },\n perMinuteRate: {\n type: Number,\n min: 0,\n description: 'Penalty per minute late (for per-minute mode)',\n },\n percentageRate: {\n type: Number,\n min: 0,\n max: 100,\n description: 'Percentage of daily wage (for percentage mode)',\n },\n tiers: {\n type: [PenaltyTierSchema],\n description: 'Penalty tiers for progressive discipline (for tiered mode)',\n },\n maxPenaltiesPerPeriod: {\n type: MaxPenaltiesSchema,\n description: 'Maximum penalties allowed per period',\n },\n resetOccurrenceCount: {\n type: String,\n enum: ['monthly', 'quarterly', 'yearly'],\n description: 'When to reset occurrence counter',\n },\n};\n\n/**\n * Schema for late arrival policy\n */\nexport const LateArrivalPolicySchema: Schema = new Schema(LateArrivalPolicySchemaDefinition, {\n _id: false,\n timestamps: false,\n});\n\n/**\n * Schema definition for early departure policy\n * (Same structure as late arrival policy)\n */\nexport const EarlyDeparturePolicySchemaDefinition = LateArrivalPolicySchemaDefinition;\n\n/**\n * Schema for early departure policy\n */\nexport const EarlyDeparturePolicySchema: Schema = new Schema(EarlyDeparturePolicySchemaDefinition, {\n _id: false,\n timestamps: false,\n});\n\n/**\n * Schema definition for weekend premium\n */\nexport const WeekendPremiumSchemaDefinition: SchemaDefinition = {\n saturday: {\n type: Number,\n required: true,\n min: 1,\n description: 'Saturday premium multiplier (e.g., 1.5 for time-and-a-half)',\n },\n sunday: {\n type: Number,\n required: true,\n min: 1,\n description: 'Sunday premium multiplier (e.g., 2.0 for double time)',\n },\n};\n\n/**\n * Schema for weekend premium\n */\nexport const WeekendPremiumSchema: Schema = new Schema(WeekendPremiumSchemaDefinition, {\n _id: false,\n timestamps: false,\n});\n\n/**\n * Schema definition for night shift differential\n */\nexport const NightShiftDifferentialSchemaDefinition: SchemaDefinition = {\n startHour: {\n type: Number,\n required: true,\n min: 0,\n max: 23,\n description: 'Night shift start hour (24-hour format, e.g., 22 for 10pm)',\n },\n endHour: {\n type: Number,\n required: true,\n min: 0,\n max: 23,\n description: 'Night shift end hour (24-hour format, e.g., 6 for 6am)',\n },\n multiplier: {\n type: Number,\n required: true,\n min: 1,\n description: 'Night shift premium multiplier (e.g., 1.3 for 30% premium)',\n },\n};\n\n/**\n * Schema for night shift differential\n */\nexport const NightShiftDifferentialSchema: Schema = new Schema(NightShiftDifferentialSchemaDefinition, {\n _id: false,\n timestamps: false,\n});\n\n/**\n * Schema definition for overtime policy\n */\nexport const OvertimePolicySchemaDefinition: SchemaDefinition = {\n enabled: {\n type: Boolean,\n required: true,\n default: true,\n description: 'Whether overtime bonuses are enabled',\n },\n mode: {\n type: String,\n enum: ['daily', 'weekly', 'monthly'],\n required: true,\n description: 'Overtime calculation mode',\n },\n dailyThreshold: {\n type: Number,\n min: 0,\n description: 'Daily overtime threshold in hours (for daily mode)',\n },\n dailyMultiplier: {\n type: Number,\n min: 1,\n description: 'Daily overtime pay multiplier (e.g., 1.5 for time-and-a-half)',\n },\n weeklyThreshold: {\n type: Number,\n min: 0,\n description: 'Weekly overtime threshold in hours (for weekly mode)',\n },\n weeklyMultiplier: {\n type: Number,\n min: 1,\n description: 'Weekly overtime pay multiplier',\n },\n monthlyThreshold: {\n type: Number,\n min: 0,\n description: 'Monthly overtime threshold in hours (for monthly mode)',\n },\n monthlyMultiplier: {\n type: Number,\n min: 1,\n description: 'Monthly overtime pay multiplier',\n },\n weekendPremium: {\n type: WeekendPremiumSchema,\n description: 'Weekend premium rates',\n },\n nightShiftDifferential: {\n type: NightShiftDifferentialSchema,\n description: 'Night shift differential rates',\n },\n};\n\n/**\n * Schema for overtime policy\n */\nexport const OvertimePolicySchema: Schema = new Schema(OvertimePolicySchemaDefinition, {\n _id: false,\n timestamps: false,\n});\n\n/**\n * Schema definition for clock rounding policy\n */\nexport const ClockRoundingPolicySchemaDefinition: SchemaDefinition = {\n enabled: {\n type: Boolean,\n required: true,\n default: false,\n description: 'Whether clock rounding is enabled',\n },\n roundTo: {\n type: Number,\n enum: [5, 10, 15],\n description: 'Round to nearest N minutes',\n },\n mode: {\n type: String,\n enum: ['up', 'down', 'nearest'],\n description: 'Rounding mode: up (favor employee), down (favor employer), nearest (neutral)',\n },\n};\n\n/**\n * Schema for clock rounding policy\n */\nexport const ClockRoundingPolicySchema: Schema = new Schema(ClockRoundingPolicySchemaDefinition, {\n _id: false,\n timestamps: false,\n});\n\n// ============================================================================\n// Main Attendance Policy Schema\n// ============================================================================\n\n/**\n * Schema definition for attendance policy\n *\n * Users can extend this with their own fields:\n * ```typescript\n * const CustomPolicySchema = new Schema({\n * ...AttendancePolicySchemaDefinition,\n * approvedBy: { type: Schema.Types.ObjectId, ref: 'User' },\n * department: String,\n * });\n * ```\n */\nexport const AttendancePolicySchemaDefinition: SchemaDefinition = {\n organizationId: {\n type: Schema.Types.ObjectId,\n index: true,\n description: 'Organization this policy belongs to (for multi-tenant)',\n },\n name: {\n type: String,\n required: true,\n trim: true,\n maxlength: 200,\n description: 'Policy name',\n },\n description: {\n type: String,\n trim: true,\n maxlength: 1000,\n description: 'Policy description',\n },\n lateArrival: {\n type: LateArrivalPolicySchema,\n required: true,\n description: 'Late arrival penalty policy',\n },\n earlyDeparture: {\n type: EarlyDeparturePolicySchema,\n required: true,\n description: 'Early departure penalty policy',\n },\n overtime: {\n type: OvertimePolicySchema,\n required: true,\n description: 'Overtime bonus policy',\n },\n clockRounding: {\n type: ClockRoundingPolicySchema,\n description: 'Clock rounding policy (optional)',\n },\n effectiveFrom: {\n type: Date,\n required: true,\n default: Date.now,\n description: 'When this policy becomes effective',\n },\n effectiveTo: {\n type: Date,\n default: null,\n description: 'When this policy expires (null for no expiration)',\n },\n active: {\n type: Boolean,\n required: true,\n default: true,\n index: true,\n description: 'Whether this policy is currently active',\n },\n};\n\n/**\n * Main Attendance Policy Schema\n *\n * @example\n * ```typescript\n * import { AttendancePolicySchema } from '@classytic/payroll';\n * import { model } from 'mongoose';\n *\n * const AttendancePolicy = model('AttendancePolicy', AttendancePolicySchema);\n *\n * // Create a new policy\n * const policy = new AttendancePolicy({\n * name: 'Tech Department Policy',\n * lateArrival: { ... },\n * earlyDeparture: { ... },\n * overtime: { ... },\n * });\n * await policy.save();\n * ```\n */\nexport const AttendancePolicySchema: Schema = new Schema(AttendancePolicySchemaDefinition, {\n timestamps: true,\n collection: 'attendance_policies',\n});\n\n// ============================================================================\n// Indexes\n// ============================================================================\n\n// Compound index for finding active policies by organization\nAttendancePolicySchema.index({ organizationId: 1, active: 1, effectiveFrom: -1 });\n\n// Index for finding policies by effective date range\nAttendancePolicySchema.index({ effectiveFrom: 1, effectiveTo: 1 });\n\n// ============================================================================\n// Helper Methods\n// ============================================================================\n\n/**\n * Instance method: Check if policy is currently active\n */\nAttendancePolicySchema.methods.isCurrentlyActive = function (this: Document & { active: boolean; effectiveFrom: Date; effectiveTo?: Date | null }): boolean {\n if (!this.active) return false;\n\n const now = new Date();\n if (this.effectiveFrom > now) return false;\n if (this.effectiveTo && this.effectiveTo < now) return false;\n\n return true;\n};\n\n/**\n * Static method: Find active policy for an organization\n */\nAttendancePolicySchema.statics.findActiveForOrganization = function (\n this: Model<Document>,\n organizationId: Types.ObjectId,\n date: Date = new Date()\n) {\n return this.findOne({\n organizationId,\n active: true,\n effectiveFrom: { $lte: date },\n $or: [\n { effectiveTo: null },\n { effectiveTo: { $gt: date } },\n ],\n }).sort({ effectiveFrom: -1 });\n};\n\n// ============================================================================\n// Type Augmentation (for TypeScript users)\n// ============================================================================\n\n/**\n * Instance methods interface\n */\nexport interface AttendancePolicyDocument {\n isCurrentlyActive(): boolean;\n}\n\n/**\n * Static methods interface\n */\nexport interface AttendancePolicyModel {\n findActiveForOrganization(organizationId: Types.ObjectId, date?: Date): Promise<Document | null>;\n}\n\n// ============================================================================\n// Export All\n// ============================================================================\n\nexport default AttendancePolicySchema;\n","/**\r\n * @classytic/payroll - Payroll Audit Plugin\r\n *\r\n * Mongokit plugin for automatic audit trail capture on all payroll operations.\r\n * Auto-captures who/when/where for creates and updates.\r\n *\r\n * @module @classytic/payroll/core/mongokit-plugins/payroll-audit\r\n */\r\n\r\nimport type { Repository } from '@classytic/mongokit';\r\nimport type { ObjectId } from '../../types.js';\r\n\r\n/**\r\n * Audit context configuration\r\n */\r\nexport interface AuditContext {\r\n /** User ID performing the operation */\r\n userId?: ObjectId;\r\n /** User name (optional, for logging) */\r\n userName?: string;\r\n /** Organization ID (for multi-tenant operations) */\r\n organizationId?: ObjectId;\r\n}\r\n\r\n/**\r\n * Payroll audit trail plugin\r\n *\r\n * Automatically captures audit information on create and update operations:\r\n * - Creates: Sets createdBy, createdAt, organizationId\r\n * - Updates: Sets updatedBy, updatedAt\r\n *\r\n * @param context - Audit context with user and organization info\r\n * @returns Mongokit plugin function\r\n *\r\n * @example\r\n * ```typescript\r\n * // Single-tenant mode with audit\r\n * const repos = {\r\n * payrollRecord: new Repository(PayrollRecordModel, [\r\n * payrollAuditPlugin({ userId: admin._id, organizationId: org._id }),\r\n * ]),\r\n * };\r\n *\r\n * // Create will automatically set createdBy and createdAt\r\n * const record = await repos.payrollRecord.create({\r\n * employeeId: emp._id,\r\n * // ... other fields\r\n * // createdBy and createdAt will be auto-added\r\n * });\r\n * ```\r\n *\r\n * @example\r\n * ```typescript\r\n * // Multi-tenant mode with audit and multi-tenant plugin\r\n * import { multiTenantPlugin } from '../repository-plugins.js';\r\n *\r\n * const repos = {\r\n * employee: new Repository(EmployeeModel, [\r\n * multiTenantPlugin(orgId), // First: enforce multi-tenancy\r\n * payrollAuditPlugin({ userId, organizationId: orgId }), // Second: audit trail\r\n * ]),\r\n * };\r\n * ```\r\n *\r\n * @example\r\n * ```typescript\r\n * // Per-request audit context\r\n * function createAuditedRepos(req: Request) {\r\n * const context = {\r\n * userId: req.user._id,\r\n * userName: req.user.name,\r\n * organizationId: req.organization._id,\r\n * };\r\n *\r\n * return {\r\n * payrollRecord: new Repository(PayrollRecordModel, [\r\n * payrollAuditPlugin(context),\r\n * ]),\r\n * };\r\n * }\r\n * ```\r\n */\r\nexport function payrollAuditPlugin(context: AuditContext) {\r\n return (repo: Repository) => {\r\n // Hook: before create operation\r\n repo.on('before:create', async (ctx) => {\r\n // Set createdBy if userId is available\r\n if (context.userId) {\r\n ctx.data.createdBy = context.userId;\r\n }\r\n\r\n // Always set createdAt timestamp\r\n ctx.data.createdAt = new Date();\r\n\r\n // Set organizationId if provided and not already set\r\n if (context.organizationId && !ctx.data.organizationId) {\r\n ctx.data.organizationId = context.organizationId;\r\n }\r\n });\r\n\r\n // Hook: before update operation\r\n repo.on('before:update', async (ctx) => {\r\n // Initialize $set if not present\r\n if (!ctx.data.$set) {\r\n ctx.data.$set = {};\r\n }\r\n\r\n // Set updatedBy if userId is available\r\n if (context.userId) {\r\n ctx.data.$set.updatedBy = context.userId;\r\n }\r\n\r\n // Always set updatedAt timestamp\r\n ctx.data.$set.updatedAt = new Date();\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Read-only audit plugin (tracks access without modification)\r\n *\r\n * Logs who accessed what data, useful for compliance and security auditing.\r\n *\r\n * @param context - Audit context\r\n * @param logger - Optional logger function\r\n * @returns Mongokit plugin function\r\n *\r\n * @example\r\n * ```typescript\r\n * const repos = {\r\n * employee: new Repository(EmployeeModel, [\r\n * readAuditPlugin(\r\n * { userId: user._id, organizationId: org._id },\r\n * (event) => console.log('Access log:', event)\r\n * ),\r\n * ]),\r\n * };\r\n *\r\n * // This will log the access\r\n * await repos.employee.getById(employeeId);\r\n * ```\r\n */\r\nexport function readAuditPlugin(\r\n context: AuditContext,\r\n logger?: (event: AuditEvent) => void\r\n) {\r\n return (repo: Repository) => {\r\n // Hook: after read operations\r\n repo.on('after:read', async (ctx) => {\r\n const event: AuditEvent = {\r\n operation: 'read',\r\n model: repo.model,\r\n userId: context.userId,\r\n organizationId: context.organizationId,\r\n timestamp: new Date(),\r\n query: ctx.query,\r\n };\r\n\r\n if (logger) {\r\n logger(event);\r\n }\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Audit event structure\r\n */\r\nexport interface AuditEvent {\r\n /** Operation type */\r\n operation: 'create' | 'read' | 'update' | 'delete';\r\n /** Model name */\r\n model: string;\r\n /** User performing operation */\r\n userId?: ObjectId;\r\n /** Organization context */\r\n organizationId?: ObjectId;\r\n /** When the operation occurred */\r\n timestamp: Date;\r\n /** Query or data involved */\r\n query?: Record<string, unknown>;\r\n /** Additional metadata */\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Full audit trail plugin (create/read/update/delete)\r\n *\r\n * Combines both modification and access audit trails.\r\n *\r\n * @param context - Audit context\r\n * @param onEvent - Event handler for all audit events\r\n * @returns Mongokit plugin function\r\n *\r\n * @example\r\n * ```typescript\r\n * const auditLog: AuditEvent[] = [];\r\n *\r\n * const repos = {\r\n * payrollRecord: new Repository(PayrollRecordModel, [\r\n * fullAuditPlugin(\r\n * { userId: admin._id, organizationId: org._id },\r\n * (event) => auditLog.push(event)\r\n * ),\r\n * ]),\r\n * };\r\n * ```\r\n */\r\nexport function fullAuditPlugin(\r\n context: AuditContext,\r\n onEvent: (event: AuditEvent) => void | Promise<void>\r\n) {\r\n return (repo: Repository) => {\r\n // Use payroll audit for modification tracking\r\n payrollAuditPlugin(context)(repo);\r\n\r\n // Add access logging\r\n (['after:read', 'after:create', 'after:update', 'after:delete'] as const).forEach(\r\n (hookName) => {\r\n repo.on(hookName, async (ctx) => {\r\n const operation = hookName.split(':')[1] as AuditEvent['operation'];\r\n\r\n const event: AuditEvent = {\r\n operation,\r\n model: repo.model,\r\n userId: context.userId,\r\n organizationId: context.organizationId,\r\n timestamp: new Date(),\r\n query: ctx.query || ctx.data,\r\n };\r\n\r\n await onEvent(event);\r\n });\r\n }\r\n );\r\n };\r\n}\r\n"]}
|