@classytic/payroll 1.0.2 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @classytic/payroll might be problematic. Click here for more details.

Files changed (78) hide show
  1. package/README.md +2599 -574
  2. package/dist/calculators/index.d.ts +433 -0
  3. package/dist/calculators/index.js +283 -0
  4. package/dist/calculators/index.js.map +1 -0
  5. package/dist/core/index.d.ts +314 -0
  6. package/dist/core/index.js +1166 -0
  7. package/dist/core/index.js.map +1 -0
  8. package/dist/employee-identity-DXhgOgXE.d.ts +473 -0
  9. package/dist/employee.factory-BlZqhiCk.d.ts +189 -0
  10. package/dist/idempotency-Cw2CWicb.d.ts +52 -0
  11. package/dist/index.d.ts +902 -0
  12. package/dist/index.js +9108 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/jurisdiction/index.d.ts +660 -0
  15. package/dist/jurisdiction/index.js +533 -0
  16. package/dist/jurisdiction/index.js.map +1 -0
  17. package/dist/payroll.d.ts +429 -0
  18. package/dist/payroll.js +5192 -0
  19. package/dist/payroll.js.map +1 -0
  20. package/dist/schemas/index.d.ts +3262 -0
  21. package/dist/schemas/index.js +780 -0
  22. package/dist/schemas/index.js.map +1 -0
  23. package/dist/services/index.d.ts +582 -0
  24. package/dist/services/index.js +2172 -0
  25. package/dist/services/index.js.map +1 -0
  26. package/dist/shift-compliance/index.d.ts +1171 -0
  27. package/dist/shift-compliance/index.js +1479 -0
  28. package/dist/shift-compliance/index.js.map +1 -0
  29. package/dist/types-BN3K_Uhr.d.ts +1842 -0
  30. package/dist/utils/index.d.ts +893 -0
  31. package/dist/utils/index.js +1515 -0
  32. package/dist/utils/index.js.map +1 -0
  33. package/package.json +72 -37
  34. package/dist/types/config.d.ts +0 -162
  35. package/dist/types/core/compensation.manager.d.ts +0 -54
  36. package/dist/types/core/employment.manager.d.ts +0 -49
  37. package/dist/types/core/payroll.manager.d.ts +0 -60
  38. package/dist/types/enums.d.ts +0 -117
  39. package/dist/types/factories/compensation.factory.d.ts +0 -196
  40. package/dist/types/factories/employee.factory.d.ts +0 -149
  41. package/dist/types/factories/payroll.factory.d.ts +0 -319
  42. package/dist/types/hrm.orchestrator.d.ts +0 -47
  43. package/dist/types/index.d.ts +0 -20
  44. package/dist/types/init.d.ts +0 -30
  45. package/dist/types/models/payroll-record.model.d.ts +0 -3
  46. package/dist/types/plugins/employee.plugin.d.ts +0 -2
  47. package/dist/types/schemas/employment.schema.d.ts +0 -959
  48. package/dist/types/services/compensation.service.d.ts +0 -94
  49. package/dist/types/services/employee.service.d.ts +0 -28
  50. package/dist/types/services/payroll.service.d.ts +0 -30
  51. package/dist/types/utils/calculation.utils.d.ts +0 -26
  52. package/dist/types/utils/date.utils.d.ts +0 -35
  53. package/dist/types/utils/logger.d.ts +0 -12
  54. package/dist/types/utils/query-builders.d.ts +0 -83
  55. package/dist/types/utils/validation.utils.d.ts +0 -33
  56. package/payroll.d.ts +0 -241
  57. package/src/config.js +0 -177
  58. package/src/core/compensation.manager.js +0 -242
  59. package/src/core/employment.manager.js +0 -224
  60. package/src/core/payroll.manager.js +0 -499
  61. package/src/enums.js +0 -141
  62. package/src/factories/compensation.factory.js +0 -198
  63. package/src/factories/employee.factory.js +0 -173
  64. package/src/factories/payroll.factory.js +0 -413
  65. package/src/hrm.orchestrator.js +0 -139
  66. package/src/index.js +0 -172
  67. package/src/init.js +0 -62
  68. package/src/models/payroll-record.model.js +0 -126
  69. package/src/plugins/employee.plugin.js +0 -164
  70. package/src/schemas/employment.schema.js +0 -126
  71. package/src/services/compensation.service.js +0 -231
  72. package/src/services/employee.service.js +0 -162
  73. package/src/services/payroll.service.js +0 -213
  74. package/src/utils/calculation.utils.js +0 -91
  75. package/src/utils/date.utils.js +0 -120
  76. package/src/utils/logger.js +0 -36
  77. package/src/utils/query-builders.js +0 -185
  78. package/src/utils/validation.utils.js +0 -122
@@ -0,0 +1,429 @@
1
+ import { E as EmployeeDocument, P as PayrollRecordDocument, A as AnyDocument, a as PayrollInstance, b as PayrollInitConfig, c as PayrollPluginDefinition, d as PayrollEventMap, W as WebhookConfig, e as PayrollEventType, f as WebhookDelivery, H as HireEmployeeParams, U as UpdateEmploymentParams, T as TerminateEmployeeParams, R as ReHireEmployeeParams, O as ObjectIdLike, g as OperationContext, h as EmployeeIdentityMode, L as ListEmployeesParams, i as UpdateSalaryParams, j as AddAllowanceParams, k as RemoveAllowanceParams, l as AddDeductionParams, m as RemoveDeductionParams, n as UpdateBankDetailsParams, o as ProcessSalaryParams, p as ProcessSalaryResult, q as ProcessBulkPayrollParams, B as BulkPayrollResult, r as PayrollHistoryParams, s as PayrollSummaryParams, t as PayrollSummaryResult, u as ExportPayrollParams, G as GetPendingTaxParams, v as TaxWithholdingDocument, w as TaxSummaryParams, x as TaxSummaryResult, M as MarkTaxPaidParams, y as LeaveRequestDocument, D as DeepPartial, z as HRMConfig, S as SingleTenantConfig, C as Logger } from './types-BN3K_Uhr.js';
2
+ import { ClientSession, Model } from 'mongoose';
3
+
4
+ /**
5
+ * Fully generic Payroll class for best-in-class TypeScript DX.
6
+ *
7
+ * Type parameters flow through to all methods, providing complete type inference.
8
+ *
9
+ * @typeParam TEmployee - Your Employee document type (extends EmployeeDocument)
10
+ * @typeParam TPayrollRecord - Your PayrollRecord document type (extends PayrollRecordDocument)
11
+ * @typeParam TTransaction - Your Transaction document type
12
+ * @typeParam TAttendance - Your Attendance document type (optional)
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // Full type inference
17
+ * const payroll = createPayrollInstance()
18
+ * .withModels({
19
+ * EmployeeModel, // Model<MyEmployeeDoc>
20
+ * PayrollRecordModel, // Model<MyPayrollDoc>
21
+ * TransactionModel, // Model<MyTransactionDoc>
22
+ * })
23
+ * .build();
24
+ *
25
+ * // employee is typed as MyEmployeeDoc
26
+ * const employee = await payroll.hire({ ... });
27
+ * ```
28
+ */
29
+ declare class Payroll<TEmployee extends EmployeeDocument = EmployeeDocument, TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument, TTransaction extends AnyDocument = AnyDocument, TAttendance extends AnyDocument = AnyDocument> implements PayrollInstance<TEmployee, TPayrollRecord, TTransaction, TAttendance> {
30
+ [key: string]: unknown;
31
+ private _container;
32
+ private _events;
33
+ private _plugins;
34
+ private _initialized;
35
+ private _employeeService?;
36
+ private _payrollService?;
37
+ private _compensationService?;
38
+ private _idempotency;
39
+ private _webhooks;
40
+ /**
41
+ * Create a new Payroll instance with its own container.
42
+ * Each instance is isolated - no shared global state.
43
+ */
44
+ constructor();
45
+ /**
46
+ * Initialize Payroll with models and configuration
47
+ */
48
+ initialize(config: PayrollInitConfig<TEmployee, TPayrollRecord, TTransaction, TAttendance>): this;
49
+ /**
50
+ * Check if initialized
51
+ */
52
+ isInitialized(): boolean;
53
+ /**
54
+ * Ensure initialized
55
+ */
56
+ private ensureInitialized;
57
+ /**
58
+ * Resolve employeeId to ObjectId _id (respects explicit mode)
59
+ *
60
+ * Mode priority:
61
+ * - 'objectId': Always treat as MongoDB ObjectId (direct _id lookup)
62
+ * - 'businessId': Always treat as business ID (lookup by employeeId field)
63
+ * - 'auto': Smart detection (ObjectId-like → _id, otherwise → businessId)
64
+ */
65
+ private resolveEmployeeId;
66
+ /**
67
+ * Get EmployeeService (lazy initialization)
68
+ */
69
+ private get employeeService();
70
+ /**
71
+ * Get PayrollService (lazy initialization)
72
+ */
73
+ private get payrollService();
74
+ /**
75
+ * Get CompensationService (lazy initialization)
76
+ */
77
+ private get compensationService();
78
+ /**
79
+ * Get models (strongly typed)
80
+ */
81
+ private get models();
82
+ /**
83
+ * Get config
84
+ */
85
+ private get config();
86
+ /**
87
+ * Get container (for org resolution and single-tenant detection)
88
+ */
89
+ private get container();
90
+ /**
91
+ * Register a plugin
92
+ */
93
+ use(plugin: PayrollPluginDefinition): Promise<this>;
94
+ /**
95
+ * Subscribe to events
96
+ */
97
+ on<K extends keyof PayrollEventMap>(event: K, handler: (payload: PayrollEventMap[K]) => void | Promise<void>): () => void;
98
+ /**
99
+ * Register webhook URL for events (Stripe-style)
100
+ */
101
+ registerWebhook(config: WebhookConfig): void;
102
+ /**
103
+ * Unregister webhook URL
104
+ */
105
+ unregisterWebhook(url: string): void;
106
+ /**
107
+ * Get webhook delivery log
108
+ */
109
+ getWebhookDeliveries(options?: {
110
+ event?: PayrollEventType;
111
+ status?: 'pending' | 'sent' | 'failed';
112
+ limit?: number;
113
+ }): WebhookDelivery[];
114
+ /**
115
+ * Setup webhook bridge (connects event bus to webhook manager)
116
+ */
117
+ private setupWebhookBridge;
118
+ /**
119
+ * Hire a new employee
120
+ */
121
+ hire(params: HireEmployeeParams): Promise<TEmployee>;
122
+ /**
123
+ * Update employment details
124
+ * NOTE: Status changes to 'terminated' must use terminate() method
125
+ */
126
+ updateEmployment(params: UpdateEmploymentParams): Promise<TEmployee>;
127
+ /**
128
+ * Terminate employee
129
+ */
130
+ terminate(params: TerminateEmployeeParams): Promise<TEmployee>;
131
+ /**
132
+ * Re-hire terminated employee
133
+ */
134
+ reHire(params: ReHireEmployeeParams): Promise<TEmployee>;
135
+ /**
136
+ * Get employee by ID
137
+ */
138
+ getEmployee(params: {
139
+ employeeId: ObjectIdLike | string;
140
+ employeeIdMode?: 'auto' | 'objectId' | 'businessId';
141
+ organizationId?: ObjectIdLike;
142
+ populateUser?: boolean;
143
+ session?: ClientSession;
144
+ context?: OperationContext;
145
+ }): Promise<TEmployee>;
146
+ /**
147
+ * Get employee by flexible identity (userId, employeeId, or email)
148
+ *
149
+ * Supports multiple identity modes with automatic fallback:
150
+ * - 'userId': Lookup by user account ID (traditional)
151
+ * - 'employeeId': Lookup by human-readable employee ID (e.g., "EMP-001")
152
+ * - 'email': Lookup by email address (for guest employees)
153
+ * - 'any': Try all modes until found
154
+ *
155
+ * @example
156
+ * // By user ID (traditional)
157
+ * const emp = await payroll.getEmployeeByIdentity({
158
+ * identity: userId,
159
+ * organizationId,
160
+ * mode: 'userId'
161
+ * });
162
+ *
163
+ * // By employee ID (human-readable)
164
+ * const emp = await payroll.getEmployeeByIdentity({
165
+ * identity: 'EMP-001',
166
+ * organizationId,
167
+ * mode: 'employeeId'
168
+ * });
169
+ *
170
+ * // By email (guest employees)
171
+ * const emp = await payroll.getEmployeeByIdentity({
172
+ * identity: 'driver@example.com',
173
+ * organizationId,
174
+ * mode: 'email'
175
+ * });
176
+ *
177
+ * // Auto-detect (uses config.identityMode + fallbacks)
178
+ * const emp = await payroll.getEmployeeByIdentity({
179
+ * identity: 'EMP-001',
180
+ * organizationId
181
+ * });
182
+ */
183
+ getEmployeeByIdentity(params: {
184
+ identity: ObjectIdLike | string;
185
+ organizationId?: ObjectIdLike;
186
+ mode?: EmployeeIdentityMode;
187
+ populateUser?: boolean;
188
+ session?: ClientSession;
189
+ }): Promise<TEmployee>;
190
+ /**
191
+ * List employees
192
+ */
193
+ listEmployees(params: ListEmployeesParams): Promise<{
194
+ docs: TEmployee[];
195
+ totalDocs: number;
196
+ page: number;
197
+ limit: number;
198
+ }>;
199
+ /**
200
+ * Update employee salary
201
+ */
202
+ updateSalary(params: UpdateSalaryParams): Promise<TEmployee>;
203
+ /**
204
+ * Add allowance to employee
205
+ */
206
+ addAllowance(params: AddAllowanceParams): Promise<TEmployee>;
207
+ /**
208
+ * Remove allowance from employee
209
+ */
210
+ removeAllowance(params: RemoveAllowanceParams): Promise<TEmployee>;
211
+ /**
212
+ * Add deduction to employee
213
+ */
214
+ addDeduction(params: AddDeductionParams): Promise<TEmployee>;
215
+ /**
216
+ * Remove deduction from employee
217
+ */
218
+ removeDeduction(params: RemoveDeductionParams): Promise<TEmployee>;
219
+ /**
220
+ * Update bank details
221
+ */
222
+ updateBankDetails(params: UpdateBankDetailsParams): Promise<TEmployee>;
223
+ /**
224
+ * Process salary for single employee
225
+ *
226
+ * ATOMICITY: This method creates its own transaction if none provided.
227
+ * All database operations (PayrollRecord, Transaction, Employee stats)
228
+ * are atomic - either all succeed or all fail.
229
+ */
230
+ processSalary(params: ProcessSalaryParams): Promise<ProcessSalaryResult<TEmployee, TPayrollRecord, TTransaction>>;
231
+ /**
232
+ * Process bulk payroll for multiple employees
233
+ *
234
+ * ATOMICITY STRATEGY: Each employee is processed in its own transaction.
235
+ * This allows partial success - some employees can succeed while others fail.
236
+ * Failed employees don't affect successful ones.
237
+ *
238
+ * NEW FEATURES (all optional, backward compatible):
239
+ * - Progress tracking via onProgress callback
240
+ * - Cancellation support via AbortSignal
241
+ * - Batch processing to prevent resource exhaustion
242
+ * - Concurrency control for parallel processing
243
+ *
244
+ * @example Basic usage (unchanged)
245
+ * ```typescript
246
+ * const result = await payroll.processBulkPayroll({
247
+ * organizationId, month, year
248
+ * });
249
+ * ```
250
+ *
251
+ * @example With progress tracking
252
+ * ```typescript
253
+ * await payroll.processBulkPayroll({
254
+ * organizationId, month, year,
255
+ * onProgress: (p) => console.log(`${p.percentage}% done`)
256
+ * });
257
+ * ```
258
+ *
259
+ * @example With job queue integration
260
+ * ```typescript
261
+ * await payroll.processBulkPayroll({
262
+ * organizationId, month, year,
263
+ * batchSize: 10,
264
+ * onProgress: async (p) => {
265
+ * await Job.findByIdAndUpdate(jobId, { progress: p });
266
+ * }
267
+ * });
268
+ * ```
269
+ *
270
+ * @example With cancellation
271
+ * ```typescript
272
+ * const controller = new AbortController();
273
+ * payroll.processBulkPayroll({ signal: controller.signal });
274
+ * // Later: controller.abort();
275
+ * ```
276
+ */
277
+ processBulkPayroll(params: ProcessBulkPayrollParams): Promise<BulkPayrollResult>;
278
+ /**
279
+ * Stream-based bulk payroll processing for millions of employees.
280
+ * Uses MongoDB cursors to avoid loading everything into memory.
281
+ *
282
+ * @private
283
+ */
284
+ private processBulkPayrollStreaming;
285
+ /**
286
+ * Get payroll history
287
+ */
288
+ payrollHistory(params: PayrollHistoryParams): Promise<TPayrollRecord[]>;
289
+ /**
290
+ * Get payroll summary
291
+ */
292
+ payrollSummary(params: PayrollSummaryParams): Promise<PayrollSummaryResult>;
293
+ /**
294
+ * Export payroll data
295
+ */
296
+ exportPayroll(params: ExportPayrollParams): Promise<TPayrollRecord[]>;
297
+ /**
298
+ * Get pending tax withholdings with optional filters
299
+ */
300
+ getPendingTaxWithholdings(params: GetPendingTaxParams): Promise<TaxWithholdingDocument[]>;
301
+ /**
302
+ * Get tax summary aggregated by type, period, or employee
303
+ */
304
+ getTaxSummary(params: TaxSummaryParams): Promise<TaxSummaryResult>;
305
+ /**
306
+ * Mark tax withholdings as paid
307
+ *
308
+ * Updates status, optionally creates government payment transaction,
309
+ * and emits tax:paid event
310
+ */
311
+ markTaxWithholdingsPaid(params: MarkTaxPaidParams): Promise<{
312
+ withholdings: TaxWithholdingDocument[];
313
+ transaction?: any;
314
+ }>;
315
+ /**
316
+ * Calculate salary breakdown
317
+ *
318
+ * Delegates to pure calculator for testability and reusability
319
+ */
320
+ private calculateSalaryBreakdown;
321
+ /**
322
+ * Calculate attendance deduction using working days (not calendar days)
323
+ */
324
+ private calculateAttendanceDeduction;
325
+ private updatePayrollStats;
326
+ /**
327
+ * Create a new Payroll instance with default types
328
+ */
329
+ static create<E extends EmployeeDocument = EmployeeDocument, P extends PayrollRecordDocument = PayrollRecordDocument, T extends AnyDocument = AnyDocument, A extends AnyDocument = AnyDocument>(): Payroll<E, P, T, A>;
330
+ }
331
+ /**
332
+ * Generic models configuration - infers types from your models
333
+ */
334
+ interface ModelsConfig<TEmployee extends EmployeeDocument = EmployeeDocument, TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument, TTransaction extends AnyDocument = AnyDocument, TAttendance extends AnyDocument = AnyDocument, TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument, TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument> {
335
+ EmployeeModel: Model<TEmployee>;
336
+ PayrollRecordModel: Model<TPayrollRecord>;
337
+ TransactionModel: Model<TTransaction>;
338
+ AttendanceModel?: Model<TAttendance> | null;
339
+ LeaveRequestModel?: Model<TLeaveRequest> | null;
340
+ TaxWithholdingModel?: Model<TTaxWithholding> | null;
341
+ }
342
+ /**
343
+ * Generic Payroll Builder with full type inference.
344
+ *
345
+ * Types flow from withModels() through to build(), giving you a fully typed Payroll instance.
346
+ *
347
+ * @typeParam TEmployee - Inferred from EmployeeModel
348
+ * @typeParam TPayrollRecord - Inferred from PayrollRecordModel
349
+ * @typeParam TTransaction - Inferred from TransactionModel
350
+ * @typeParam TAttendance - Inferred from AttendanceModel
351
+ *
352
+ * @example
353
+ * ```typescript
354
+ * // Types are automatically inferred!
355
+ * const payroll = createPayrollInstance()
356
+ * .withModels({
357
+ * EmployeeModel, // Model<MyEmployee>
358
+ * PayrollRecordModel, // Model<MyPayroll>
359
+ * TransactionModel, // Model<MyTransaction>
360
+ * })
361
+ * .build(); // Returns PayrollInstance<MyEmployee, MyPayroll, MyTransaction, AnyDocument>
362
+ * ```
363
+ */
364
+ declare class PayrollBuilder<TEmployee extends EmployeeDocument = EmployeeDocument, TPayrollRecord extends PayrollRecordDocument = PayrollRecordDocument, TTransaction extends AnyDocument = AnyDocument, TAttendance extends AnyDocument = AnyDocument, TLeaveRequest extends LeaveRequestDocument = LeaveRequestDocument, TTaxWithholding extends TaxWithholdingDocument = TaxWithholdingDocument> {
365
+ private _models;
366
+ private _config;
367
+ private _singleTenant;
368
+ private _logger;
369
+ /**
370
+ * Set models - types are inferred automatically
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * .withModels({
375
+ * EmployeeModel, // Your typed model
376
+ * PayrollRecordModel,
377
+ * TransactionModel,
378
+ * AttendanceModel, // Optional
379
+ * })
380
+ * ```
381
+ */
382
+ withModels<E extends EmployeeDocument, P extends PayrollRecordDocument, T extends AnyDocument, A extends AnyDocument = AnyDocument, L extends LeaveRequestDocument = LeaveRequestDocument, TW extends TaxWithholdingDocument = TaxWithholdingDocument>(models: ModelsConfig<E, P, T, A, L, TW>): PayrollBuilder<E, P, T, A, L, TW>;
383
+ /**
384
+ * Set config overrides
385
+ */
386
+ withConfig(config: DeepPartial<HRMConfig>): this;
387
+ /**
388
+ * Enable single-tenant mode
389
+ *
390
+ * Use this when building a single-organization HRM (no organizationId needed)
391
+ *
392
+ * @example
393
+ * ```typescript
394
+ * const payroll = createPayrollInstance()
395
+ * .withModels({ EmployeeModel, PayrollRecordModel, TransactionModel })
396
+ * .withSingleTenant({ organizationId: 'my-company' })
397
+ * .build();
398
+ * ```
399
+ */
400
+ withSingleTenant(config: SingleTenantConfig): this;
401
+ /**
402
+ * Enable single-tenant mode (shorthand)
403
+ *
404
+ * Alias for withSingleTenant() - consistent with @classytic/clockin API
405
+ *
406
+ * @example
407
+ * ```typescript
408
+ * const payroll = createPayrollInstance()
409
+ * .withModels({ ... })
410
+ * .forSingleTenant() // ← No organizationId needed!
411
+ * .build();
412
+ * ```
413
+ */
414
+ forSingleTenant(config?: SingleTenantConfig): this;
415
+ /**
416
+ * Set custom logger
417
+ */
418
+ withLogger(logger: Logger): this;
419
+ /**
420
+ * Build and initialize Payroll instance with inferred types
421
+ */
422
+ build(): PayrollInstance<TEmployee, TPayrollRecord, TTransaction, TAttendance>;
423
+ }
424
+ /**
425
+ * Create a new Payroll builder
426
+ */
427
+ declare function createPayrollInstance(): PayrollBuilder;
428
+
429
+ export { type ModelsConfig, Payroll, PayrollBuilder, createPayrollInstance };