@classytic/payroll 2.7.5 → 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 +333 -323
- package/dist/attendance.calculator-BZcv2iii.d.ts +336 -0
- package/dist/calculators/index.d.ts +3 -299
- package/dist/calculators/index.js +154 -19
- package/dist/calculators/index.js.map +1 -1
- 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/{employee-identity-Cq2wo9-2.d.ts → error-helpers-Bm6lMny2.d.ts} +257 -7
- package/dist/{index-DjB72l6e.d.ts → index-BKLkuSAs.d.ts} +248 -132
- package/dist/index.d.ts +418 -658
- package/dist/index.js +1179 -373
- package/dist/index.js.map +1 -1
- package/dist/payroll-states-DBt0XVm-.d.ts +598 -0
- package/dist/{prorating.calculator-C7sdFiG2.d.ts → prorating.calculator-C33fWBQf.d.ts} +2 -2
- package/dist/schemas/index.d.ts +2 -2
- package/dist/schemas/index.js +95 -75
- package/dist/schemas/index.js.map +1 -1
- package/dist/{types-BVDjiVGS.d.ts → types-bZdAJueH.d.ts} +427 -12
- package/dist/utils/index.d.ts +17 -5
- package/dist/utils/index.js +185 -25
- package/dist/utils/index.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
import { a2 as ObjectIdLike, a3 as ObjectId } from './types-bZdAJueH.js';
|
|
2
|
+
import { Plugin } from '@classytic/mongokit';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Idempotency Manager
|
|
6
|
+
*
|
|
7
|
+
* Ensures operations are not duplicated when called with the same key.
|
|
8
|
+
* Uses Stripe-style idempotency pattern for payroll operations.
|
|
9
|
+
*
|
|
10
|
+
* ## Key Format (v2.9.0+)
|
|
11
|
+
*
|
|
12
|
+
* Idempotency keys support multiple payroll frequencies:
|
|
13
|
+
*
|
|
14
|
+
* **Monthly frequency:**
|
|
15
|
+
* ```
|
|
16
|
+
* payroll:{organizationId}:{employeeId}:{year}-{month}:{payrollRunType}
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* **Non-monthly frequencies (weekly, bi_weekly, daily, hourly):**
|
|
20
|
+
* ```
|
|
21
|
+
* payroll:{organizationId}:{employeeId}:{year}-{month}:{startDate}:{payrollRunType}
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* This allows:
|
|
25
|
+
* - Different payroll types (regular, supplemental, retroactive) in the same period
|
|
26
|
+
* - Multiple weekly/bi-weekly/daily payroll runs within the same calendar month
|
|
27
|
+
*
|
|
28
|
+
* ## Important: In-Memory Cache Limitations
|
|
29
|
+
*
|
|
30
|
+
* This implementation uses an **in-memory LRU cache** which has the following limitations:
|
|
31
|
+
*
|
|
32
|
+
* - **Does NOT persist across server restarts** - cache is lost on restart
|
|
33
|
+
* - **Does NOT work across multiple server instances** - each instance has its own cache
|
|
34
|
+
* - **Only prevents duplicates within the same process lifetime**
|
|
35
|
+
*
|
|
36
|
+
* For production deployments with horizontal scaling or high availability requirements,
|
|
37
|
+
* you should implement database-backed idempotency. See the Payroll class documentation
|
|
38
|
+
* for implementation examples.
|
|
39
|
+
*
|
|
40
|
+
* ## Duplicate Protection (v2.9.0+)
|
|
41
|
+
*
|
|
42
|
+
* Primary duplicate protection is via **database unique compound index**:
|
|
43
|
+
* `{ organizationId, employeeId, period.month, period.year, period.startDate, payrollRunType }`
|
|
44
|
+
*
|
|
45
|
+
* This prevents race conditions under concurrent load. The partial filter
|
|
46
|
+
* excludes voided records to allow re-processing after restoration.
|
|
47
|
+
*
|
|
48
|
+
* The in-memory cache is a secondary optimization layer, not the primary protection.
|
|
49
|
+
*
|
|
50
|
+
* @see https://stripe.com/docs/api/idempotent_requests
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
interface IdempotentResult<T = unknown> {
|
|
54
|
+
value: T;
|
|
55
|
+
cached: boolean;
|
|
56
|
+
createdAt: Date;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* In-memory idempotency manager for preventing duplicate operations.
|
|
60
|
+
*
|
|
61
|
+
* @warning This is an in-memory cache. For production horizontal scaling,
|
|
62
|
+
* implement database-backed idempotency instead.
|
|
63
|
+
*/
|
|
64
|
+
declare class IdempotencyManager {
|
|
65
|
+
private cache;
|
|
66
|
+
private static hasLoggedWarning;
|
|
67
|
+
constructor(options?: {
|
|
68
|
+
max?: number;
|
|
69
|
+
ttl?: number;
|
|
70
|
+
suppressWarning?: boolean;
|
|
71
|
+
});
|
|
72
|
+
/**
|
|
73
|
+
* Check if key exists and return cached result
|
|
74
|
+
*/
|
|
75
|
+
get<T>(key: string): IdempotentResult<T> | null;
|
|
76
|
+
/**
|
|
77
|
+
* Store result for idempotency key
|
|
78
|
+
*/
|
|
79
|
+
set<T>(key: string, value: T): void;
|
|
80
|
+
/**
|
|
81
|
+
* Execute function with idempotency protection
|
|
82
|
+
*/
|
|
83
|
+
execute<T>(key: string, fn: () => Promise<T>): Promise<IdempotentResult<T>>;
|
|
84
|
+
/**
|
|
85
|
+
* Clear a specific key
|
|
86
|
+
*/
|
|
87
|
+
delete(key: string): void;
|
|
88
|
+
/**
|
|
89
|
+
* Clear all keys
|
|
90
|
+
*/
|
|
91
|
+
clear(): void;
|
|
92
|
+
/**
|
|
93
|
+
* Get cache stats
|
|
94
|
+
*/
|
|
95
|
+
stats(): {
|
|
96
|
+
size: number;
|
|
97
|
+
max: number;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Payroll run types for idempotency key generation
|
|
102
|
+
*/
|
|
103
|
+
type PayrollRunType = 'regular' | 'off-cycle' | 'supplemental' | 'retroactive';
|
|
104
|
+
/**
|
|
105
|
+
* Generate idempotency key for payroll operations
|
|
106
|
+
*
|
|
107
|
+
* Includes payrollRunType to allow multiple payroll runs per period
|
|
108
|
+
* (e.g., regular + supplemental bonus + retroactive adjustment)
|
|
109
|
+
*
|
|
110
|
+
* For non-monthly frequencies (weekly, bi_weekly, daily, hourly), the periodStartDate
|
|
111
|
+
* is included to differentiate multiple runs within the same calendar month.
|
|
112
|
+
*
|
|
113
|
+
* @param organizationId - Organization ID
|
|
114
|
+
* @param employeeId - Employee ID
|
|
115
|
+
* @param month - Payroll month (1-12)
|
|
116
|
+
* @param year - Payroll year
|
|
117
|
+
* @param payrollRunType - Type of payroll run (default: 'regular')
|
|
118
|
+
* @param periodStartDate - Period start date (required for non-monthly frequencies)
|
|
119
|
+
*/
|
|
120
|
+
declare function generatePayrollIdempotencyKey(organizationId: ObjectIdLike, employeeId: ObjectIdLike, month: number, year: number, payrollRunType?: PayrollRunType, periodStartDate?: Date): string;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Repository plugins for mongokit integration
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Multi-tenant plugin - automatically injects organizationId into all repository operations.
|
|
128
|
+
*
|
|
129
|
+
* Hooks into create, getAll, getById, getByQuery, update, and delete operations
|
|
130
|
+
* to enforce organizational isolation. The organizationId is force-set on creates
|
|
131
|
+
* (cannot be overridden by caller) and added as a filter on all read/write operations.
|
|
132
|
+
*
|
|
133
|
+
* @param organizationId - Organization ID to scope all operations to. If undefined, plugin is a no-op.
|
|
134
|
+
* @returns Mongokit Plugin instance
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* import { multiTenantPlugin } from '@classytic/payroll';
|
|
139
|
+
* import { Repository } from '@classytic/mongokit';
|
|
140
|
+
*
|
|
141
|
+
* const repo = new Repository(EmployeeModel, [
|
|
142
|
+
* multiTenantPlugin(organizationId),
|
|
143
|
+
* ]);
|
|
144
|
+
*
|
|
145
|
+
* // All operations auto-scoped to organizationId
|
|
146
|
+
* await repo.getAll({ filters: { status: 'active' } });
|
|
147
|
+
* // Executes: { organizationId, status: 'active' }
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
declare function multiTenantPlugin(organizationId?: ObjectId): Plugin;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @classytic/payroll - Timeline Audit Integration
|
|
154
|
+
*
|
|
155
|
+
* Integration with @classytic/mongoose-timeline-audit for comprehensive audit trails.
|
|
156
|
+
* Provides automatic tracking of WHO performed WHAT action and WHEN.
|
|
157
|
+
*
|
|
158
|
+
* ## Setup
|
|
159
|
+
*
|
|
160
|
+
* 1. Install mongoose-timeline-audit:
|
|
161
|
+
* ```bash
|
|
162
|
+
* npm install @classytic/mongoose-timeline-audit
|
|
163
|
+
* ```
|
|
164
|
+
*
|
|
165
|
+
* 2. Apply to your schemas BEFORE registering with Mongoose:
|
|
166
|
+
* ```typescript
|
|
167
|
+
* import timelineAuditPlugin from '@classytic/mongoose-timeline-audit';
|
|
168
|
+
* import { PAYROLL_EVENTS } from '@classytic/payroll';
|
|
169
|
+
*
|
|
170
|
+
* // Apply to Employee schema
|
|
171
|
+
* employeeSchema.plugin(timelineAuditPlugin, {
|
|
172
|
+
* ownerField: 'organizationId',
|
|
173
|
+
* eventLimits: PAYROLL_EVENTS.EMPLOYEE.limits,
|
|
174
|
+
* });
|
|
175
|
+
*
|
|
176
|
+
* // Apply to PayrollRecord schema
|
|
177
|
+
* payrollRecordSchema.plugin(timelineAuditPlugin, {
|
|
178
|
+
* ownerField: 'organizationId',
|
|
179
|
+
* eventLimits: PAYROLL_EVENTS.PAYROLL.limits,
|
|
180
|
+
* });
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* 3. Use the Payroll events to add timeline entries:
|
|
184
|
+
* ```typescript
|
|
185
|
+
* payroll.on('employee:hired', async ({ data }) => {
|
|
186
|
+
* const employee = await Employee.findById(data.employee.id);
|
|
187
|
+
* employee.addTimelineEvent(
|
|
188
|
+
* PAYROLL_EVENTS.EMPLOYEE.HIRED,
|
|
189
|
+
* `Hired as ${data.employee.position}`,
|
|
190
|
+
* request, // Express request for actor tracking
|
|
191
|
+
* { department: data.employee.department }
|
|
192
|
+
* );
|
|
193
|
+
* await employee.save();
|
|
194
|
+
* });
|
|
195
|
+
* ```
|
|
196
|
+
*
|
|
197
|
+
* @module @classytic/payroll/timeline-audit
|
|
198
|
+
*/
|
|
199
|
+
/**
|
|
200
|
+
* Standard payroll events for timeline tracking
|
|
201
|
+
*
|
|
202
|
+
* Use these constants with mongoose-timeline-audit's addTimelineEvent()
|
|
203
|
+
* to maintain consistent event naming across your application.
|
|
204
|
+
*/
|
|
205
|
+
declare const PAYROLL_EVENTS: {
|
|
206
|
+
/**
|
|
207
|
+
* Employee lifecycle events
|
|
208
|
+
*/
|
|
209
|
+
readonly EMPLOYEE: {
|
|
210
|
+
/** Employee was hired */
|
|
211
|
+
readonly HIRED: "employee.hired";
|
|
212
|
+
/** Employee was terminated */
|
|
213
|
+
readonly TERMINATED: "employee.terminated";
|
|
214
|
+
/** Employee was re-hired after termination */
|
|
215
|
+
readonly REHIRED: "employee.rehired";
|
|
216
|
+
/** Employee status changed (active, on_leave, suspended) */
|
|
217
|
+
readonly STATUS_CHANGED: "employee.status_changed";
|
|
218
|
+
/** Employee department/position changed */
|
|
219
|
+
readonly ROLE_CHANGED: "employee.role_changed";
|
|
220
|
+
/** Employee probation ended */
|
|
221
|
+
readonly PROBATION_ENDED: "employee.probation_ended";
|
|
222
|
+
/** Recommended event limits for employee timeline */
|
|
223
|
+
readonly limits: {
|
|
224
|
+
readonly 'employee.status_changed': 50;
|
|
225
|
+
readonly 'employee.role_changed': 20;
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Compensation events
|
|
230
|
+
*/
|
|
231
|
+
readonly COMPENSATION: {
|
|
232
|
+
/** Base salary was updated */
|
|
233
|
+
readonly SALARY_UPDATED: "compensation.salary_updated";
|
|
234
|
+
/** Allowance was added */
|
|
235
|
+
readonly ALLOWANCE_ADDED: "compensation.allowance_added";
|
|
236
|
+
/** Allowance was removed */
|
|
237
|
+
readonly ALLOWANCE_REMOVED: "compensation.allowance_removed";
|
|
238
|
+
/** Deduction was added */
|
|
239
|
+
readonly DEDUCTION_ADDED: "compensation.deduction_added";
|
|
240
|
+
/** Deduction was removed */
|
|
241
|
+
readonly DEDUCTION_REMOVED: "compensation.deduction_removed";
|
|
242
|
+
/** Bank details were updated */
|
|
243
|
+
readonly BANK_UPDATED: "compensation.bank_updated";
|
|
244
|
+
/** Recommended event limits */
|
|
245
|
+
readonly limits: {
|
|
246
|
+
readonly 'compensation.salary_updated': 24;
|
|
247
|
+
readonly 'compensation.allowance_added': 20;
|
|
248
|
+
readonly 'compensation.allowance_removed': 20;
|
|
249
|
+
readonly 'compensation.deduction_added': 20;
|
|
250
|
+
readonly 'compensation.deduction_removed': 20;
|
|
251
|
+
readonly 'compensation.bank_updated': 10;
|
|
252
|
+
};
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* Payroll processing events
|
|
256
|
+
*/
|
|
257
|
+
readonly PAYROLL: {
|
|
258
|
+
/** Salary was processed */
|
|
259
|
+
readonly PROCESSED: "payroll.processed";
|
|
260
|
+
/** Payroll was voided (before payment) */
|
|
261
|
+
readonly VOIDED: "payroll.voided";
|
|
262
|
+
/** Payroll was reversed (after payment) */
|
|
263
|
+
readonly REVERSED: "payroll.reversed";
|
|
264
|
+
/** Payroll was restored from voided state */
|
|
265
|
+
readonly RESTORED: "payroll.restored";
|
|
266
|
+
/** Payroll export was generated */
|
|
267
|
+
readonly EXPORTED: "payroll.exported";
|
|
268
|
+
/** Recommended event limits */
|
|
269
|
+
readonly limits: {
|
|
270
|
+
readonly 'payroll.processed': 36;
|
|
271
|
+
readonly 'payroll.voided': 10;
|
|
272
|
+
readonly 'payroll.reversed': 10;
|
|
273
|
+
readonly 'payroll.restored': 5;
|
|
274
|
+
readonly 'payroll.exported': 20;
|
|
275
|
+
};
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Tax withholding events
|
|
279
|
+
*/
|
|
280
|
+
readonly TAX: {
|
|
281
|
+
/** Tax was withheld */
|
|
282
|
+
readonly WITHHELD: "tax.withheld";
|
|
283
|
+
/** Tax was submitted to authorities */
|
|
284
|
+
readonly SUBMITTED: "tax.submitted";
|
|
285
|
+
/** Tax payment was made */
|
|
286
|
+
readonly PAID: "tax.paid";
|
|
287
|
+
/** Tax withholding was cancelled */
|
|
288
|
+
readonly CANCELLED: "tax.cancelled";
|
|
289
|
+
/** Recommended event limits */
|
|
290
|
+
readonly limits: {
|
|
291
|
+
readonly 'tax.withheld': 36;
|
|
292
|
+
readonly 'tax.submitted': 12;
|
|
293
|
+
readonly 'tax.paid': 12;
|
|
294
|
+
readonly 'tax.cancelled': 10;
|
|
295
|
+
};
|
|
296
|
+
};
|
|
297
|
+
/**
|
|
298
|
+
* Leave management events
|
|
299
|
+
*/
|
|
300
|
+
readonly LEAVE: {
|
|
301
|
+
/** Leave was requested */
|
|
302
|
+
readonly REQUESTED: "leave.requested";
|
|
303
|
+
/** Leave was approved */
|
|
304
|
+
readonly APPROVED: "leave.approved";
|
|
305
|
+
/** Leave was rejected */
|
|
306
|
+
readonly REJECTED: "leave.rejected";
|
|
307
|
+
/** Leave was cancelled */
|
|
308
|
+
readonly CANCELLED: "leave.cancelled";
|
|
309
|
+
/** Leave balance was accrued */
|
|
310
|
+
readonly ACCRUED: "leave.accrued";
|
|
311
|
+
/** Annual leave was reset */
|
|
312
|
+
readonly RESET: "leave.reset";
|
|
313
|
+
/** Recommended event limits */
|
|
314
|
+
readonly limits: {
|
|
315
|
+
readonly 'leave.requested': 50;
|
|
316
|
+
readonly 'leave.approved': 50;
|
|
317
|
+
readonly 'leave.rejected': 20;
|
|
318
|
+
readonly 'leave.cancelled': 20;
|
|
319
|
+
readonly 'leave.accrued': 12;
|
|
320
|
+
readonly 'leave.reset': 5;
|
|
321
|
+
};
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
/**
|
|
325
|
+
* All payroll event types (for TypeScript)
|
|
326
|
+
*/
|
|
327
|
+
type PayrollTimelineEvent = typeof PAYROLL_EVENTS.EMPLOYEE[keyof typeof PAYROLL_EVENTS.EMPLOYEE] | typeof PAYROLL_EVENTS.COMPENSATION[keyof typeof PAYROLL_EVENTS.COMPENSATION] | typeof PAYROLL_EVENTS.PAYROLL[keyof typeof PAYROLL_EVENTS.PAYROLL] | typeof PAYROLL_EVENTS.TAX[keyof typeof PAYROLL_EVENTS.TAX] | typeof PAYROLL_EVENTS.LEAVE[keyof typeof PAYROLL_EVENTS.LEAVE];
|
|
328
|
+
/**
|
|
329
|
+
* Recommended timeline audit configuration for Employee model
|
|
330
|
+
*/
|
|
331
|
+
declare const EMPLOYEE_TIMELINE_CONFIG: {
|
|
332
|
+
ownerField: string;
|
|
333
|
+
fieldName: string;
|
|
334
|
+
hideByDefault: boolean;
|
|
335
|
+
eventLimits: {
|
|
336
|
+
'compensation.salary_updated': 24;
|
|
337
|
+
'compensation.allowance_added': 20;
|
|
338
|
+
'compensation.allowance_removed': 20;
|
|
339
|
+
'compensation.deduction_added': 20;
|
|
340
|
+
'compensation.deduction_removed': 20;
|
|
341
|
+
'compensation.bank_updated': 10;
|
|
342
|
+
'employee.status_changed': 50;
|
|
343
|
+
'employee.role_changed': 20;
|
|
344
|
+
};
|
|
345
|
+
};
|
|
346
|
+
/**
|
|
347
|
+
* Recommended timeline audit configuration for PayrollRecord model
|
|
348
|
+
*/
|
|
349
|
+
declare const PAYROLL_RECORD_TIMELINE_CONFIG: {
|
|
350
|
+
ownerField: string;
|
|
351
|
+
fieldName: string;
|
|
352
|
+
hideByDefault: boolean;
|
|
353
|
+
eventLimits: {
|
|
354
|
+
readonly 'payroll.processed': 36;
|
|
355
|
+
readonly 'payroll.voided': 10;
|
|
356
|
+
readonly 'payroll.reversed': 10;
|
|
357
|
+
readonly 'payroll.restored': 5;
|
|
358
|
+
readonly 'payroll.exported': 20;
|
|
359
|
+
};
|
|
360
|
+
};
|
|
361
|
+
/**
|
|
362
|
+
* Recommended timeline audit configuration for LeaveRequest model
|
|
363
|
+
*/
|
|
364
|
+
declare const LEAVE_REQUEST_TIMELINE_CONFIG: {
|
|
365
|
+
ownerField: string;
|
|
366
|
+
fieldName: string;
|
|
367
|
+
hideByDefault: boolean;
|
|
368
|
+
eventLimits: {
|
|
369
|
+
readonly 'leave.requested': 50;
|
|
370
|
+
readonly 'leave.approved': 50;
|
|
371
|
+
readonly 'leave.rejected': 20;
|
|
372
|
+
readonly 'leave.cancelled': 20;
|
|
373
|
+
readonly 'leave.accrued': 12;
|
|
374
|
+
readonly 'leave.reset': 5;
|
|
375
|
+
};
|
|
376
|
+
};
|
|
377
|
+
/**
|
|
378
|
+
* Build timeline event metadata from payroll context
|
|
379
|
+
*
|
|
380
|
+
* @param context - Operation context from payroll methods
|
|
381
|
+
* @returns Metadata object for timeline event
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* ```typescript
|
|
385
|
+
* employee.addTimelineEvent(
|
|
386
|
+
* PAYROLL_EVENTS.EMPLOYEE.HIRED,
|
|
387
|
+
* 'Hired as Software Engineer',
|
|
388
|
+
* request,
|
|
389
|
+
* buildTimelineMetadata(params.context)
|
|
390
|
+
* );
|
|
391
|
+
* ```
|
|
392
|
+
*/
|
|
393
|
+
declare function buildTimelineMetadata(context?: {
|
|
394
|
+
userId?: unknown;
|
|
395
|
+
userName?: string;
|
|
396
|
+
userRole?: string;
|
|
397
|
+
organizationId?: unknown;
|
|
398
|
+
}): Record<string, unknown>;
|
|
399
|
+
/**
|
|
400
|
+
* Build context object for timeline event (IP, user agent, etc.)
|
|
401
|
+
*
|
|
402
|
+
* @param request - Express/Fastify request object
|
|
403
|
+
* @returns Context object for timeline event
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* ```typescript
|
|
407
|
+
* employee.addTimelineEvent(
|
|
408
|
+
* PAYROLL_EVENTS.COMPENSATION.SALARY_UPDATED,
|
|
409
|
+
* `Salary updated to ${newSalary}`,
|
|
410
|
+
* request,
|
|
411
|
+
* { previousSalary, newSalary },
|
|
412
|
+
* buildRequestContext(request)
|
|
413
|
+
* );
|
|
414
|
+
* ```
|
|
415
|
+
*/
|
|
416
|
+
declare function buildRequestContext(request?: {
|
|
417
|
+
ip?: string;
|
|
418
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
419
|
+
get?: (header: string) => string | undefined;
|
|
420
|
+
}): Record<string, unknown> | undefined;
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* @classytic/payroll - State Machine
|
|
424
|
+
*
|
|
425
|
+
* Minimal state machine implementation for status management.
|
|
426
|
+
* Enforces valid transitions and provides clear error messages.
|
|
427
|
+
*/
|
|
428
|
+
/**
|
|
429
|
+
* State transition definition
|
|
430
|
+
*/
|
|
431
|
+
interface StateTransition<TState extends string> {
|
|
432
|
+
from: TState | TState[];
|
|
433
|
+
to: TState;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* State machine configuration
|
|
437
|
+
*/
|
|
438
|
+
interface StateMachineConfig<TState extends string> {
|
|
439
|
+
/** All valid states */
|
|
440
|
+
states: readonly TState[];
|
|
441
|
+
/** Initial state */
|
|
442
|
+
initial: TState;
|
|
443
|
+
/** Valid transitions */
|
|
444
|
+
transitions: StateTransition<TState>[];
|
|
445
|
+
/** Terminal states (no outgoing transitions) */
|
|
446
|
+
terminal?: TState[];
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Transition result
|
|
450
|
+
*/
|
|
451
|
+
type TransitionResult<TState extends string> = {
|
|
452
|
+
success: true;
|
|
453
|
+
from: TState;
|
|
454
|
+
to: TState;
|
|
455
|
+
} | {
|
|
456
|
+
success: false;
|
|
457
|
+
from: TState;
|
|
458
|
+
to: TState;
|
|
459
|
+
error: string;
|
|
460
|
+
};
|
|
461
|
+
/**
|
|
462
|
+
* Minimal state machine for status management
|
|
463
|
+
*
|
|
464
|
+
* @example
|
|
465
|
+
* const machine = new StateMachine({
|
|
466
|
+
* states: ['pending', 'processing', 'paid', 'voided'] as const,
|
|
467
|
+
* initial: 'pending',
|
|
468
|
+
* transitions: [
|
|
469
|
+
* { from: 'pending', to: 'processing' },
|
|
470
|
+
* { from: 'pending', to: 'voided' },
|
|
471
|
+
* { from: 'processing', to: 'paid' },
|
|
472
|
+
* ],
|
|
473
|
+
* terminal: ['paid', 'voided'],
|
|
474
|
+
* });
|
|
475
|
+
*
|
|
476
|
+
* machine.canTransition('pending', 'processing'); // true
|
|
477
|
+
* machine.canTransition('paid', 'pending'); // false
|
|
478
|
+
*/
|
|
479
|
+
declare class StateMachine<TState extends string> {
|
|
480
|
+
private readonly config;
|
|
481
|
+
private readonly validTransitions;
|
|
482
|
+
private readonly terminalStates;
|
|
483
|
+
constructor(config: StateMachineConfig<TState>);
|
|
484
|
+
/**
|
|
485
|
+
* Get the initial state
|
|
486
|
+
*/
|
|
487
|
+
get initial(): TState;
|
|
488
|
+
/**
|
|
489
|
+
* Get all valid states
|
|
490
|
+
*/
|
|
491
|
+
get states(): readonly TState[];
|
|
492
|
+
/**
|
|
493
|
+
* Check if a state is valid
|
|
494
|
+
*/
|
|
495
|
+
isValidState(state: string): state is TState;
|
|
496
|
+
/**
|
|
497
|
+
* Check if a state is terminal (no outgoing transitions)
|
|
498
|
+
*/
|
|
499
|
+
isTerminal(state: TState): boolean;
|
|
500
|
+
/**
|
|
501
|
+
* Check if transition from one state to another is valid
|
|
502
|
+
*/
|
|
503
|
+
canTransition(from: TState, to: TState): boolean;
|
|
504
|
+
/**
|
|
505
|
+
* Get all valid next states from current state
|
|
506
|
+
*/
|
|
507
|
+
getNextStates(from: TState): TState[];
|
|
508
|
+
/**
|
|
509
|
+
* Validate a transition and return result
|
|
510
|
+
*/
|
|
511
|
+
validateTransition(from: TState, to: TState): TransitionResult<TState>;
|
|
512
|
+
/**
|
|
513
|
+
* Assert a transition is valid, throw if not
|
|
514
|
+
*/
|
|
515
|
+
assertTransition(from: TState, to: TState): void;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Create a state machine instance
|
|
519
|
+
*/
|
|
520
|
+
declare function createStateMachine<TState extends string>(config: StateMachineConfig<TState>): StateMachine<TState>;
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* @classytic/payroll - Payroll State Machines
|
|
524
|
+
*
|
|
525
|
+
* Defines valid state transitions for all status types.
|
|
526
|
+
* Single source of truth for status management.
|
|
527
|
+
*/
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* PayrollStatus state machine
|
|
531
|
+
*
|
|
532
|
+
* State diagram:
|
|
533
|
+
* ```
|
|
534
|
+
* PENDING ──┬──> PROCESSING ──┬──> PAID ──> REVERSED
|
|
535
|
+
* │ │ │
|
|
536
|
+
* │ │ └──> FAILED ──┐
|
|
537
|
+
* │ │ │
|
|
538
|
+
* │ └──> VOIDED <──────────┘
|
|
539
|
+
* │ ↑
|
|
540
|
+
* └──────────────┘
|
|
541
|
+
* ```
|
|
542
|
+
*
|
|
543
|
+
* - PENDING: Initial state, payroll created but not processed
|
|
544
|
+
* - PROCESSING: Currently being processed (bulk operations)
|
|
545
|
+
* - PAID: Payment completed successfully
|
|
546
|
+
* - FAILED: Processing failed (can retry → pending, or void)
|
|
547
|
+
* - VOIDED: Cancelled before payment (can restore → pending)
|
|
548
|
+
* - REVERSED: Payment reversed after completion (terminal)
|
|
549
|
+
*/
|
|
550
|
+
declare const PayrollStatusMachine: StateMachine<"pending" | "processing" | "paid" | "failed" | "voided" | "reversed">;
|
|
551
|
+
type PayrollStatusState = typeof PayrollStatusMachine.states[number];
|
|
552
|
+
/**
|
|
553
|
+
* TaxStatus state machine
|
|
554
|
+
*
|
|
555
|
+
* State diagram:
|
|
556
|
+
* ```
|
|
557
|
+
* PENDING ──┬──> SUBMITTED ──> PAID
|
|
558
|
+
* │
|
|
559
|
+
* └──> CANCELLED
|
|
560
|
+
* ```
|
|
561
|
+
*
|
|
562
|
+
* - PENDING: Tax withheld, not yet submitted to government
|
|
563
|
+
* - SUBMITTED: Submitted to tax authority, awaiting confirmation
|
|
564
|
+
* - PAID: Payment confirmed by tax authority
|
|
565
|
+
* - CANCELLED: Invalidated (payroll voided/reversed)
|
|
566
|
+
*/
|
|
567
|
+
declare const TaxStatusMachine: StateMachine<"pending" | "paid" | "cancelled" | "submitted">;
|
|
568
|
+
type TaxStatusState = typeof TaxStatusMachine.states[number];
|
|
569
|
+
/**
|
|
570
|
+
* LeaveRequestStatus state machine
|
|
571
|
+
*
|
|
572
|
+
* State diagram:
|
|
573
|
+
* ```
|
|
574
|
+
* PENDING ──┬──> APPROVED
|
|
575
|
+
* │
|
|
576
|
+
* ├──> REJECTED
|
|
577
|
+
* │
|
|
578
|
+
* └──> CANCELLED
|
|
579
|
+
* ```
|
|
580
|
+
*/
|
|
581
|
+
declare const LeaveRequestStatusMachine: StateMachine<"pending" | "approved" | "rejected" | "cancelled">;
|
|
582
|
+
type LeaveRequestStatusState = typeof LeaveRequestStatusMachine.states[number];
|
|
583
|
+
/**
|
|
584
|
+
* EmployeeStatus state machine
|
|
585
|
+
*
|
|
586
|
+
* State diagram:
|
|
587
|
+
* ```
|
|
588
|
+
* ACTIVE ←──┬──→ ON_LEAVE
|
|
589
|
+
* │
|
|
590
|
+
* ├──→ SUSPENDED ──→ ACTIVE
|
|
591
|
+
* │
|
|
592
|
+
* └──→ TERMINATED
|
|
593
|
+
* ```
|
|
594
|
+
*/
|
|
595
|
+
declare const EmployeeStatusMachine: StateMachine<"active" | "on_leave" | "suspended" | "terminated">;
|
|
596
|
+
type EmployeeStatusState = typeof EmployeeStatusMachine.states[number];
|
|
597
|
+
|
|
598
|
+
export { EMPLOYEE_TIMELINE_CONFIG as E, IdempotencyManager as I, LEAVE_REQUEST_TIMELINE_CONFIG as L, PAYROLL_EVENTS as P, StateMachine as S, TaxStatusMachine as T, EmployeeStatusMachine as a, type EmployeeStatusState as b, type IdempotentResult as c, LeaveRequestStatusMachine as d, type LeaveRequestStatusState as e, PAYROLL_RECORD_TIMELINE_CONFIG as f, PayrollStatusMachine as g, type PayrollStatusState as h, type PayrollTimelineEvent as i, type StateMachineConfig as j, type StateTransition as k, type TaxStatusState as l, type TransitionResult as m, buildRequestContext as n, buildTimelineMetadata as o, createStateMachine as p, generatePayrollIdempotencyKey as q, multiTenantPlugin as r };
|
|
@@ -33,7 +33,7 @@ interface ProRatingInput {
|
|
|
33
33
|
*/
|
|
34
34
|
periodEnd: Date;
|
|
35
35
|
/**
|
|
36
|
-
* Working days of the week (1=Monday,
|
|
36
|
+
* Working days of the week using Date.getDay() convention (0=Sunday, 1=Monday, ..., 6=Saturday)
|
|
37
37
|
* @default [1, 2, 3, 4, 5] (Monday-Friday)
|
|
38
38
|
*/
|
|
39
39
|
workingDays: number[];
|
|
@@ -132,4 +132,4 @@ declare function applyProRating(baseAmount: number, ratio: number): number;
|
|
|
132
132
|
*/
|
|
133
133
|
declare function shouldProRate(hireDate: Date, terminationDate: Date | null, periodStart: Date, periodEnd: Date): boolean;
|
|
134
134
|
|
|
135
|
-
export { type ProRatingInput as P,
|
|
135
|
+
export { type ProRatingInput as P, type ProRatingResult as a, applyProRating as b, calculateProRating as c, shouldProRate as s };
|
package/dist/schemas/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'bson';
|
|
2
2
|
import 'mongoose';
|
|
3
|
-
export { P as PayrollSchemaOptions, a as allowanceSchema, b as applyEmployeeIndexes, c as applyLeaveRequestIndexes, d as applyPayrollRecordIndexes, e as applyTaxWithholdingIndexes, f as bankDetailsSchema, g as compensationSchema, h as createEmployeeSchema, i as createEmploymentFields, j as createPayrollRecordFields, k as createPayrollRecordSchema, l as deductionSchema, _ as default,
|
|
4
|
-
import '../types-
|
|
3
|
+
export { P as PayrollSchemaOptions, a as allowanceSchema, b as applyEmployeeIndexes, c as applyLeaveRequestIndexes, d as applyPayrollRecordIndexes, e as applyTaxWithholdingIndexes, f as bankDetailsSchema, g as compensationSchema, h as createEmployeeSchema, i as createEmploymentFields, j as createPayrollRecordFields, k as createPayrollRecordSchema, l as deductionSchema, _ as default, m as employeeIndexes, n as employmentHistorySchema, o as getLeaveRequestFields, p as getLeaveRequestModel, q as getTaxWithholdingFields, r as getTaxWithholdingModel, s as leaveBalanceFields, t as leaveBalanceSchema, u as leaveRequestIndexes, v as leaveRequestSchema, B as leaveRequestTTLIndex, C as payrollBreakdownSchema, w as payrollRecordIndexes, x as payrollStatsSchema, D as periodSchema, y as taxWithholdingIndexes, z as taxWithholdingSchema, A as workScheduleSchema } from '../index-BKLkuSAs.js';
|
|
4
|
+
import '../types-bZdAJueH.js';
|