@classytic/payroll 1.0.1 → 2.0.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.
- package/README.md +168 -489
- package/dist/core/index.d.ts +480 -0
- package/dist/core/index.js +971 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index-CTjHlCzz.d.ts +721 -0
- package/dist/index.d.ts +967 -0
- package/dist/index.js +4352 -0
- package/dist/index.js.map +1 -0
- package/dist/payroll.d.ts +233 -0
- package/dist/payroll.js +2103 -0
- package/dist/payroll.js.map +1 -0
- package/dist/plugin-D9mOr3_d.d.ts +333 -0
- package/dist/schemas/index.d.ts +2869 -0
- package/dist/schemas/index.js +440 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.js +1696 -0
- package/dist/services/index.js.map +1 -0
- package/dist/types-BSYyX2KJ.d.ts +671 -0
- package/dist/utils/index.d.ts +873 -0
- package/dist/utils/index.js +1046 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +61 -25
- package/payroll.d.ts +0 -241
- 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,971 @@
|
|
|
1
|
+
// src/core/result.ts
|
|
2
|
+
function ok(value) {
|
|
3
|
+
return { ok: true, value };
|
|
4
|
+
}
|
|
5
|
+
function err(error) {
|
|
6
|
+
return { ok: false, error };
|
|
7
|
+
}
|
|
8
|
+
function isOk(result) {
|
|
9
|
+
return result.ok === true;
|
|
10
|
+
}
|
|
11
|
+
function isErr(result) {
|
|
12
|
+
return result.ok === false;
|
|
13
|
+
}
|
|
14
|
+
function unwrap(result) {
|
|
15
|
+
if (isOk(result)) {
|
|
16
|
+
return result.value;
|
|
17
|
+
}
|
|
18
|
+
throw result.error;
|
|
19
|
+
}
|
|
20
|
+
function unwrapOr(result, defaultValue) {
|
|
21
|
+
if (isOk(result)) {
|
|
22
|
+
return result.value;
|
|
23
|
+
}
|
|
24
|
+
return defaultValue;
|
|
25
|
+
}
|
|
26
|
+
function unwrapOrElse(result, fn) {
|
|
27
|
+
if (isOk(result)) {
|
|
28
|
+
return result.value;
|
|
29
|
+
}
|
|
30
|
+
return fn(result.error);
|
|
31
|
+
}
|
|
32
|
+
function map(result, fn) {
|
|
33
|
+
if (isOk(result)) {
|
|
34
|
+
return ok(fn(result.value));
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
function mapErr(result, fn) {
|
|
39
|
+
if (isErr(result)) {
|
|
40
|
+
return err(fn(result.error));
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
function flatMap(result, fn) {
|
|
45
|
+
if (isOk(result)) {
|
|
46
|
+
return fn(result.value);
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
async function tryCatch(fn, errorTransform) {
|
|
51
|
+
try {
|
|
52
|
+
const value = await fn();
|
|
53
|
+
return ok(value);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (errorTransform) {
|
|
56
|
+
return err(errorTransform(error));
|
|
57
|
+
}
|
|
58
|
+
return err(error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function tryCatchSync(fn, errorTransform) {
|
|
62
|
+
try {
|
|
63
|
+
const value = fn();
|
|
64
|
+
return ok(value);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (errorTransform) {
|
|
67
|
+
return err(errorTransform(error));
|
|
68
|
+
}
|
|
69
|
+
return err(error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function all(results) {
|
|
73
|
+
const values = [];
|
|
74
|
+
for (const result of results) {
|
|
75
|
+
if (isErr(result)) {
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
values.push(result.value);
|
|
79
|
+
}
|
|
80
|
+
return ok(values);
|
|
81
|
+
}
|
|
82
|
+
function match(result, handlers) {
|
|
83
|
+
if (isOk(result)) {
|
|
84
|
+
return handlers.ok(result.value);
|
|
85
|
+
}
|
|
86
|
+
return handlers.err(result.error);
|
|
87
|
+
}
|
|
88
|
+
async function fromPromise(promise, errorTransform) {
|
|
89
|
+
return tryCatch(() => promise, errorTransform);
|
|
90
|
+
}
|
|
91
|
+
function fromNullable(value, error) {
|
|
92
|
+
if (value === null || value === void 0) {
|
|
93
|
+
return err(error);
|
|
94
|
+
}
|
|
95
|
+
return ok(value);
|
|
96
|
+
}
|
|
97
|
+
var ResultClass = class _ResultClass {
|
|
98
|
+
constructor(result) {
|
|
99
|
+
this.result = result;
|
|
100
|
+
}
|
|
101
|
+
static ok(value) {
|
|
102
|
+
return new _ResultClass(ok(value));
|
|
103
|
+
}
|
|
104
|
+
static err(error) {
|
|
105
|
+
return new _ResultClass(err(error));
|
|
106
|
+
}
|
|
107
|
+
static async fromAsync(fn, errorTransform) {
|
|
108
|
+
const result = await tryCatch(fn, errorTransform);
|
|
109
|
+
return new _ResultClass(result);
|
|
110
|
+
}
|
|
111
|
+
isOk() {
|
|
112
|
+
return isOk(this.result);
|
|
113
|
+
}
|
|
114
|
+
isErr() {
|
|
115
|
+
return isErr(this.result);
|
|
116
|
+
}
|
|
117
|
+
unwrap() {
|
|
118
|
+
return unwrap(this.result);
|
|
119
|
+
}
|
|
120
|
+
unwrapOr(defaultValue) {
|
|
121
|
+
return unwrapOr(this.result, defaultValue);
|
|
122
|
+
}
|
|
123
|
+
map(fn) {
|
|
124
|
+
return new _ResultClass(map(this.result, fn));
|
|
125
|
+
}
|
|
126
|
+
mapErr(fn) {
|
|
127
|
+
return new _ResultClass(mapErr(this.result, fn));
|
|
128
|
+
}
|
|
129
|
+
flatMap(fn) {
|
|
130
|
+
return new _ResultClass(flatMap(this.result, fn));
|
|
131
|
+
}
|
|
132
|
+
match(handlers) {
|
|
133
|
+
return match(this.result, handlers);
|
|
134
|
+
}
|
|
135
|
+
toResult() {
|
|
136
|
+
return this.result;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var Result = {
|
|
140
|
+
ok,
|
|
141
|
+
err,
|
|
142
|
+
isOk,
|
|
143
|
+
isErr,
|
|
144
|
+
unwrap,
|
|
145
|
+
unwrapOr,
|
|
146
|
+
unwrapOrElse,
|
|
147
|
+
map,
|
|
148
|
+
mapErr,
|
|
149
|
+
flatMap,
|
|
150
|
+
tryCatch,
|
|
151
|
+
tryCatchSync,
|
|
152
|
+
all,
|
|
153
|
+
match,
|
|
154
|
+
fromPromise,
|
|
155
|
+
fromNullable
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// src/core/events.ts
|
|
159
|
+
var EventBus = class {
|
|
160
|
+
handlers = /* @__PURE__ */ new Map();
|
|
161
|
+
/**
|
|
162
|
+
* Register an event handler
|
|
163
|
+
*/
|
|
164
|
+
on(event, handler) {
|
|
165
|
+
if (!this.handlers.has(event)) {
|
|
166
|
+
this.handlers.set(event, /* @__PURE__ */ new Set());
|
|
167
|
+
}
|
|
168
|
+
this.handlers.get(event).add(handler);
|
|
169
|
+
return () => this.off(event, handler);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Register a one-time event handler
|
|
173
|
+
*/
|
|
174
|
+
once(event, handler) {
|
|
175
|
+
const wrappedHandler = async (payload) => {
|
|
176
|
+
this.off(event, wrappedHandler);
|
|
177
|
+
await handler(payload);
|
|
178
|
+
};
|
|
179
|
+
return this.on(event, wrappedHandler);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Remove an event handler
|
|
183
|
+
*/
|
|
184
|
+
off(event, handler) {
|
|
185
|
+
const eventHandlers = this.handlers.get(event);
|
|
186
|
+
if (eventHandlers) {
|
|
187
|
+
eventHandlers.delete(handler);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Emit an event
|
|
192
|
+
*/
|
|
193
|
+
async emit(event, payload) {
|
|
194
|
+
const eventHandlers = this.handlers.get(event);
|
|
195
|
+
if (!eventHandlers || eventHandlers.size === 0) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const handlers = Array.from(eventHandlers);
|
|
199
|
+
await Promise.all(
|
|
200
|
+
handlers.map(async (handler) => {
|
|
201
|
+
try {
|
|
202
|
+
await handler(payload);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error(`Event handler error for ${event}:`, error);
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Emit event synchronously (fire-and-forget)
|
|
211
|
+
*/
|
|
212
|
+
emitSync(event, payload) {
|
|
213
|
+
void this.emit(event, payload);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Remove all handlers for an event
|
|
217
|
+
*/
|
|
218
|
+
removeAllListeners(event) {
|
|
219
|
+
if (event) {
|
|
220
|
+
this.handlers.delete(event);
|
|
221
|
+
} else {
|
|
222
|
+
this.handlers.clear();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Get listener count for an event
|
|
227
|
+
*/
|
|
228
|
+
listenerCount(event) {
|
|
229
|
+
return this.handlers.get(event)?.size ?? 0;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Get all registered events
|
|
233
|
+
*/
|
|
234
|
+
eventNames() {
|
|
235
|
+
return Array.from(this.handlers.keys());
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
var defaultEventBus = null;
|
|
239
|
+
function getEventBus() {
|
|
240
|
+
if (!defaultEventBus) {
|
|
241
|
+
defaultEventBus = new EventBus();
|
|
242
|
+
}
|
|
243
|
+
return defaultEventBus;
|
|
244
|
+
}
|
|
245
|
+
function createEventBus() {
|
|
246
|
+
return new EventBus();
|
|
247
|
+
}
|
|
248
|
+
function resetEventBus() {
|
|
249
|
+
if (defaultEventBus) {
|
|
250
|
+
defaultEventBus.removeAllListeners();
|
|
251
|
+
}
|
|
252
|
+
defaultEventBus = null;
|
|
253
|
+
}
|
|
254
|
+
function onEmployeeHired(handler) {
|
|
255
|
+
return getEventBus().on("employee:hired", handler);
|
|
256
|
+
}
|
|
257
|
+
function onSalaryProcessed(handler) {
|
|
258
|
+
return getEventBus().on("salary:processed", handler);
|
|
259
|
+
}
|
|
260
|
+
function onPayrollCompleted(handler) {
|
|
261
|
+
return getEventBus().on("payroll:completed", handler);
|
|
262
|
+
}
|
|
263
|
+
function onMilestoneAchieved(handler) {
|
|
264
|
+
return getEventBus().on("milestone:achieved", handler);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/core/plugin.ts
|
|
268
|
+
var PluginManager = class {
|
|
269
|
+
constructor(context) {
|
|
270
|
+
this.context = context;
|
|
271
|
+
}
|
|
272
|
+
plugins = /* @__PURE__ */ new Map();
|
|
273
|
+
hooks = /* @__PURE__ */ new Map();
|
|
274
|
+
/**
|
|
275
|
+
* Register a plugin
|
|
276
|
+
*/
|
|
277
|
+
async register(plugin) {
|
|
278
|
+
if (this.plugins.has(plugin.name)) {
|
|
279
|
+
throw new Error(`Plugin "${plugin.name}" is already registered`);
|
|
280
|
+
}
|
|
281
|
+
if (plugin.hooks) {
|
|
282
|
+
for (const [hookName, handler] of Object.entries(plugin.hooks)) {
|
|
283
|
+
if (handler) {
|
|
284
|
+
this.addHook(hookName, handler);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (plugin.init) {
|
|
289
|
+
await plugin.init(this.context);
|
|
290
|
+
}
|
|
291
|
+
this.plugins.set(plugin.name, plugin);
|
|
292
|
+
this.context.logger.debug(`Plugin "${plugin.name}" registered`);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Unregister a plugin
|
|
296
|
+
*/
|
|
297
|
+
async unregister(name) {
|
|
298
|
+
const plugin = this.plugins.get(name);
|
|
299
|
+
if (!plugin) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (plugin.destroy) {
|
|
303
|
+
await plugin.destroy();
|
|
304
|
+
}
|
|
305
|
+
this.plugins.delete(name);
|
|
306
|
+
this.context.logger.debug(`Plugin "${name}" unregistered`);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Add a hook handler
|
|
310
|
+
*/
|
|
311
|
+
addHook(hookName, handler) {
|
|
312
|
+
if (!this.hooks.has(hookName)) {
|
|
313
|
+
this.hooks.set(hookName, []);
|
|
314
|
+
}
|
|
315
|
+
this.hooks.get(hookName).push(handler);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Execute hooks for a given event
|
|
319
|
+
*/
|
|
320
|
+
async executeHooks(hookName, ...args) {
|
|
321
|
+
const handlers = this.hooks.get(hookName);
|
|
322
|
+
if (!handlers || handlers.length === 0) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
for (const handler of handlers) {
|
|
326
|
+
try {
|
|
327
|
+
await handler(...args);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
this.context.logger.error(`Hook "${hookName}" error:`, { error });
|
|
330
|
+
const errorHandlers = this.hooks.get("onError");
|
|
331
|
+
if (errorHandlers) {
|
|
332
|
+
for (const errorHandler of errorHandlers) {
|
|
333
|
+
try {
|
|
334
|
+
await errorHandler(error, hookName);
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Get registered plugin names
|
|
344
|
+
*/
|
|
345
|
+
getPluginNames() {
|
|
346
|
+
return Array.from(this.plugins.keys());
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Check if plugin is registered
|
|
350
|
+
*/
|
|
351
|
+
hasPlugin(name) {
|
|
352
|
+
return this.plugins.has(name);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
function definePlugin(definition) {
|
|
356
|
+
return definition;
|
|
357
|
+
}
|
|
358
|
+
var loggingPlugin = definePlugin({
|
|
359
|
+
name: "logging",
|
|
360
|
+
version: "1.0.0",
|
|
361
|
+
init: (context) => {
|
|
362
|
+
context.addHook("employee:hired", (payload) => {
|
|
363
|
+
context.logger.info("Employee hired", {
|
|
364
|
+
employeeId: payload.employee.employeeId,
|
|
365
|
+
position: payload.employee.position
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
context.addHook("salary:processed", (payload) => {
|
|
369
|
+
context.logger.info("Salary processed", {
|
|
370
|
+
employeeId: payload.employee.employeeId,
|
|
371
|
+
amount: payload.payroll.netAmount,
|
|
372
|
+
period: payload.payroll.period
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
context.addHook("employee:terminated", (payload) => {
|
|
376
|
+
context.logger.info("Employee terminated", {
|
|
377
|
+
employeeId: payload.employee.employeeId,
|
|
378
|
+
reason: payload.reason
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
},
|
|
382
|
+
hooks: {
|
|
383
|
+
onError: (error, context) => {
|
|
384
|
+
console.error(`[Payroll Error] ${context}:`, error.message);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
var metricsPlugin = definePlugin({
|
|
389
|
+
name: "metrics",
|
|
390
|
+
version: "1.0.0",
|
|
391
|
+
init: (context) => {
|
|
392
|
+
const metrics = {
|
|
393
|
+
employeesHired: 0,
|
|
394
|
+
employeesTerminated: 0,
|
|
395
|
+
salariesProcessed: 0,
|
|
396
|
+
totalPaid: 0,
|
|
397
|
+
errors: 0
|
|
398
|
+
};
|
|
399
|
+
context.addHook("employee:hired", () => {
|
|
400
|
+
metrics.employeesHired++;
|
|
401
|
+
});
|
|
402
|
+
context.addHook("employee:terminated", () => {
|
|
403
|
+
metrics.employeesTerminated++;
|
|
404
|
+
});
|
|
405
|
+
context.addHook("salary:processed", (payload) => {
|
|
406
|
+
metrics.salariesProcessed++;
|
|
407
|
+
metrics.totalPaid += payload.payroll.netAmount;
|
|
408
|
+
});
|
|
409
|
+
context.payroll.metrics = metrics;
|
|
410
|
+
},
|
|
411
|
+
hooks: {
|
|
412
|
+
onError: (error, context) => {
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
function createNotificationPlugin(options) {
|
|
417
|
+
return definePlugin({
|
|
418
|
+
name: "notification",
|
|
419
|
+
version: "1.0.0",
|
|
420
|
+
init: (context) => {
|
|
421
|
+
if (options.onHired) {
|
|
422
|
+
context.addHook("employee:hired", async (payload) => {
|
|
423
|
+
await options.onHired({
|
|
424
|
+
id: payload.employee.id,
|
|
425
|
+
name: payload.employee.position
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
if (options.onTerminated) {
|
|
430
|
+
context.addHook("employee:terminated", async (payload) => {
|
|
431
|
+
await options.onTerminated({
|
|
432
|
+
id: payload.employee.id,
|
|
433
|
+
name: payload.employee.name
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
if (options.onSalaryProcessed) {
|
|
438
|
+
context.addHook("salary:processed", async (payload) => {
|
|
439
|
+
await options.onSalaryProcessed({
|
|
440
|
+
employee: {
|
|
441
|
+
id: payload.employee.id,
|
|
442
|
+
name: payload.employee.name
|
|
443
|
+
},
|
|
444
|
+
amount: payload.payroll.netAmount
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
if (options.onMilestone) {
|
|
449
|
+
context.addHook("milestone:achieved", async (payload) => {
|
|
450
|
+
await options.onMilestone({
|
|
451
|
+
employee: {
|
|
452
|
+
id: payload.employee.id,
|
|
453
|
+
name: payload.employee.name
|
|
454
|
+
},
|
|
455
|
+
milestone: payload.milestone.message
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
var notificationPlugin = createNotificationPlugin({});
|
|
463
|
+
|
|
464
|
+
// src/utils/logger.ts
|
|
465
|
+
var createConsoleLogger = () => ({
|
|
466
|
+
info: (message, meta) => {
|
|
467
|
+
if (meta) {
|
|
468
|
+
console.log(`[Payroll] INFO: ${message}`, meta);
|
|
469
|
+
} else {
|
|
470
|
+
console.log(`[Payroll] INFO: ${message}`);
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
error: (message, meta) => {
|
|
474
|
+
if (meta) {
|
|
475
|
+
console.error(`[Payroll] ERROR: ${message}`, meta);
|
|
476
|
+
} else {
|
|
477
|
+
console.error(`[Payroll] ERROR: ${message}`);
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
warn: (message, meta) => {
|
|
481
|
+
if (meta) {
|
|
482
|
+
console.warn(`[Payroll] WARN: ${message}`, meta);
|
|
483
|
+
} else {
|
|
484
|
+
console.warn(`[Payroll] WARN: ${message}`);
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
debug: (message, meta) => {
|
|
488
|
+
if (process.env.NODE_ENV !== "production") {
|
|
489
|
+
if (meta) {
|
|
490
|
+
console.log(`[Payroll] DEBUG: ${message}`, meta);
|
|
491
|
+
} else {
|
|
492
|
+
console.log(`[Payroll] DEBUG: ${message}`);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
var currentLogger = createConsoleLogger();
|
|
498
|
+
function getLogger() {
|
|
499
|
+
return currentLogger;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// src/config.ts
|
|
503
|
+
var HRM_CONFIG = {
|
|
504
|
+
dataRetention: {
|
|
505
|
+
payrollRecordsTTL: 63072e3,
|
|
506
|
+
// 2 years in seconds
|
|
507
|
+
exportWarningDays: 30,
|
|
508
|
+
archiveBeforeDeletion: true
|
|
509
|
+
},
|
|
510
|
+
payroll: {
|
|
511
|
+
defaultCurrency: "BDT",
|
|
512
|
+
allowProRating: true,
|
|
513
|
+
attendanceIntegration: true,
|
|
514
|
+
autoDeductions: true,
|
|
515
|
+
overtimeEnabled: false,
|
|
516
|
+
overtimeMultiplier: 1.5
|
|
517
|
+
},
|
|
518
|
+
salary: {
|
|
519
|
+
minimumWage: 0,
|
|
520
|
+
maximumAllowances: 10,
|
|
521
|
+
maximumDeductions: 10,
|
|
522
|
+
defaultFrequency: "monthly"
|
|
523
|
+
},
|
|
524
|
+
employment: {
|
|
525
|
+
defaultProbationMonths: 3,
|
|
526
|
+
maxProbationMonths: 6,
|
|
527
|
+
allowReHiring: true,
|
|
528
|
+
trackEmploymentHistory: true
|
|
529
|
+
},
|
|
530
|
+
validation: {
|
|
531
|
+
requireBankDetails: false,
|
|
532
|
+
requireEmployeeId: true,
|
|
533
|
+
uniqueEmployeeIdPerOrg: true,
|
|
534
|
+
allowMultiTenantEmployees: true
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
var ORG_ROLES = {
|
|
538
|
+
OWNER: {
|
|
539
|
+
key: "owner",
|
|
540
|
+
label: "Owner",
|
|
541
|
+
description: "Full organization access (set by Organization model)"
|
|
542
|
+
},
|
|
543
|
+
MANAGER: {
|
|
544
|
+
key: "manager",
|
|
545
|
+
label: "Manager",
|
|
546
|
+
description: "Management and administrative features"
|
|
547
|
+
},
|
|
548
|
+
TRAINER: {
|
|
549
|
+
key: "trainer",
|
|
550
|
+
label: "Trainer",
|
|
551
|
+
description: "Training and coaching features"
|
|
552
|
+
},
|
|
553
|
+
STAFF: {
|
|
554
|
+
key: "staff",
|
|
555
|
+
label: "Staff",
|
|
556
|
+
description: "General staff access to basic features"
|
|
557
|
+
},
|
|
558
|
+
INTERN: {
|
|
559
|
+
key: "intern",
|
|
560
|
+
label: "Intern",
|
|
561
|
+
description: "Limited access for interns"
|
|
562
|
+
},
|
|
563
|
+
CONSULTANT: {
|
|
564
|
+
key: "consultant",
|
|
565
|
+
label: "Consultant",
|
|
566
|
+
description: "Project-based consultant access"
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
Object.values(ORG_ROLES).map((role) => role.key);
|
|
570
|
+
function mergeConfig(customConfig) {
|
|
571
|
+
if (!customConfig) return HRM_CONFIG;
|
|
572
|
+
return {
|
|
573
|
+
dataRetention: { ...HRM_CONFIG.dataRetention, ...customConfig.dataRetention },
|
|
574
|
+
payroll: { ...HRM_CONFIG.payroll, ...customConfig.payroll },
|
|
575
|
+
salary: { ...HRM_CONFIG.salary, ...customConfig.salary },
|
|
576
|
+
employment: { ...HRM_CONFIG.employment, ...customConfig.employment },
|
|
577
|
+
validation: { ...HRM_CONFIG.validation, ...customConfig.validation }
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// src/core/container.ts
|
|
582
|
+
var Container = class _Container {
|
|
583
|
+
static instance = null;
|
|
584
|
+
_models = null;
|
|
585
|
+
_config = HRM_CONFIG;
|
|
586
|
+
_singleTenant = null;
|
|
587
|
+
_logger;
|
|
588
|
+
_initialized = false;
|
|
589
|
+
constructor() {
|
|
590
|
+
this._logger = getLogger();
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Get singleton instance
|
|
594
|
+
*/
|
|
595
|
+
static getInstance() {
|
|
596
|
+
if (!_Container.instance) {
|
|
597
|
+
_Container.instance = new _Container();
|
|
598
|
+
}
|
|
599
|
+
return _Container.instance;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Reset instance (for testing)
|
|
603
|
+
*/
|
|
604
|
+
static resetInstance() {
|
|
605
|
+
_Container.instance = null;
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Initialize container with configuration
|
|
609
|
+
*/
|
|
610
|
+
initialize(config) {
|
|
611
|
+
if (this._initialized) {
|
|
612
|
+
this._logger.warn("Container already initialized, re-initializing");
|
|
613
|
+
}
|
|
614
|
+
this._models = config.models;
|
|
615
|
+
this._config = mergeConfig(config.config);
|
|
616
|
+
this._singleTenant = config.singleTenant ?? null;
|
|
617
|
+
if (config.logger) {
|
|
618
|
+
this._logger = config.logger;
|
|
619
|
+
}
|
|
620
|
+
this._initialized = true;
|
|
621
|
+
this._logger.info("Container initialized", {
|
|
622
|
+
hasEmployeeModel: !!this._models.EmployeeModel,
|
|
623
|
+
hasPayrollRecordModel: !!this._models.PayrollRecordModel,
|
|
624
|
+
hasTransactionModel: !!this._models.TransactionModel,
|
|
625
|
+
hasAttendanceModel: !!this._models.AttendanceModel,
|
|
626
|
+
isSingleTenant: !!this._singleTenant
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Check if container is initialized
|
|
631
|
+
*/
|
|
632
|
+
isInitialized() {
|
|
633
|
+
return this._initialized;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Ensure container is initialized
|
|
637
|
+
*/
|
|
638
|
+
ensureInitialized() {
|
|
639
|
+
if (!this._initialized || !this._models) {
|
|
640
|
+
throw new Error(
|
|
641
|
+
"Payroll not initialized. Call Payroll.initialize() first."
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Get models container
|
|
647
|
+
*/
|
|
648
|
+
getModels() {
|
|
649
|
+
this.ensureInitialized();
|
|
650
|
+
return this._models;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Get Employee model
|
|
654
|
+
*/
|
|
655
|
+
getEmployeeModel() {
|
|
656
|
+
this.ensureInitialized();
|
|
657
|
+
return this._models.EmployeeModel;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Get PayrollRecord model
|
|
661
|
+
*/
|
|
662
|
+
getPayrollRecordModel() {
|
|
663
|
+
this.ensureInitialized();
|
|
664
|
+
return this._models.PayrollRecordModel;
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Get Transaction model
|
|
668
|
+
*/
|
|
669
|
+
getTransactionModel() {
|
|
670
|
+
this.ensureInitialized();
|
|
671
|
+
return this._models.TransactionModel;
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Get Attendance model (optional)
|
|
675
|
+
*/
|
|
676
|
+
getAttendanceModel() {
|
|
677
|
+
this.ensureInitialized();
|
|
678
|
+
return this._models.AttendanceModel ?? null;
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Get configuration
|
|
682
|
+
*/
|
|
683
|
+
getConfig() {
|
|
684
|
+
return this._config;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Get specific config section
|
|
688
|
+
*/
|
|
689
|
+
getConfigSection(section) {
|
|
690
|
+
return this._config[section];
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Check if single-tenant mode
|
|
694
|
+
*/
|
|
695
|
+
isSingleTenant() {
|
|
696
|
+
return !!this._singleTenant;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Get single-tenant config
|
|
700
|
+
*/
|
|
701
|
+
getSingleTenantConfig() {
|
|
702
|
+
return this._singleTenant;
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Get organization ID (for single-tenant mode)
|
|
706
|
+
*/
|
|
707
|
+
getOrganizationId() {
|
|
708
|
+
if (!this._singleTenant || !this._singleTenant.organizationId) return null;
|
|
709
|
+
return typeof this._singleTenant.organizationId === "string" ? this._singleTenant.organizationId : this._singleTenant.organizationId.toString();
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Get logger
|
|
713
|
+
*/
|
|
714
|
+
getLogger() {
|
|
715
|
+
return this._logger;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Set logger
|
|
719
|
+
*/
|
|
720
|
+
setLogger(logger) {
|
|
721
|
+
this._logger = logger;
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Has attendance integration
|
|
725
|
+
*/
|
|
726
|
+
hasAttendanceIntegration() {
|
|
727
|
+
return !!this._models?.AttendanceModel && this._config.payroll.attendanceIntegration;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Create operation context with defaults
|
|
731
|
+
*/
|
|
732
|
+
createOperationContext(overrides) {
|
|
733
|
+
const context = {};
|
|
734
|
+
if (this._singleTenant?.autoInject && !overrides?.organizationId) {
|
|
735
|
+
context.organizationId = this.getOrganizationId();
|
|
736
|
+
}
|
|
737
|
+
return { ...context, ...overrides };
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
function getContainer() {
|
|
741
|
+
return Container.getInstance();
|
|
742
|
+
}
|
|
743
|
+
function initializeContainer(config) {
|
|
744
|
+
Container.getInstance().initialize(config);
|
|
745
|
+
}
|
|
746
|
+
function isContainerInitialized() {
|
|
747
|
+
return Container.getInstance().isInitialized();
|
|
748
|
+
}
|
|
749
|
+
function getModels() {
|
|
750
|
+
return Container.getInstance().getModels();
|
|
751
|
+
}
|
|
752
|
+
function getConfig() {
|
|
753
|
+
return Container.getInstance().getConfig();
|
|
754
|
+
}
|
|
755
|
+
function isSingleTenant() {
|
|
756
|
+
return Container.getInstance().isSingleTenant();
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// src/core/config.ts
|
|
760
|
+
var COUNTRY_DEFAULTS = {
|
|
761
|
+
US: {
|
|
762
|
+
currency: "USD",
|
|
763
|
+
workDays: [1, 2, 3, 4, 5],
|
|
764
|
+
// Mon-Fri
|
|
765
|
+
taxBrackets: [
|
|
766
|
+
{ min: 0, max: 11e3, rate: 0.1 },
|
|
767
|
+
{ min: 11e3, max: 44725, rate: 0.12 },
|
|
768
|
+
{ min: 44725, max: 95375, rate: 0.22 },
|
|
769
|
+
{ min: 95375, max: 182100, rate: 0.24 },
|
|
770
|
+
{ min: 182100, max: Infinity, rate: 0.32 }
|
|
771
|
+
]
|
|
772
|
+
},
|
|
773
|
+
BD: {
|
|
774
|
+
currency: "BDT",
|
|
775
|
+
workDays: [0, 1, 2, 3, 4],
|
|
776
|
+
// Sun-Thu
|
|
777
|
+
taxBrackets: [
|
|
778
|
+
{ min: 0, max: 35e4, rate: 0 },
|
|
779
|
+
{ min: 35e4, max: 45e4, rate: 0.05 },
|
|
780
|
+
{ min: 45e4, max: 75e4, rate: 0.1 },
|
|
781
|
+
{ min: 75e4, max: 115e4, rate: 0.15 },
|
|
782
|
+
{ min: 115e4, max: Infinity, rate: 0.2 }
|
|
783
|
+
]
|
|
784
|
+
},
|
|
785
|
+
UK: {
|
|
786
|
+
currency: "GBP",
|
|
787
|
+
workDays: [1, 2, 3, 4, 5],
|
|
788
|
+
taxBrackets: [
|
|
789
|
+
{ min: 0, max: 12570, rate: 0 },
|
|
790
|
+
{ min: 12570, max: 50270, rate: 0.2 },
|
|
791
|
+
{ min: 50270, max: 125140, rate: 0.4 },
|
|
792
|
+
{ min: 125140, max: Infinity, rate: 0.45 }
|
|
793
|
+
]
|
|
794
|
+
},
|
|
795
|
+
IN: {
|
|
796
|
+
currency: "INR",
|
|
797
|
+
workDays: [1, 2, 3, 4, 5, 6],
|
|
798
|
+
// Mon-Sat
|
|
799
|
+
taxBrackets: [
|
|
800
|
+
{ min: 0, max: 3e5, rate: 0 },
|
|
801
|
+
{ min: 3e5, max: 6e5, rate: 0.05 },
|
|
802
|
+
{ min: 6e5, max: 9e5, rate: 0.1 },
|
|
803
|
+
{ min: 9e5, max: 12e5, rate: 0.15 },
|
|
804
|
+
{ min: 12e5, max: Infinity, rate: 0.2 }
|
|
805
|
+
]
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
var DEFAULT_WORK_SCHEDULE = {
|
|
809
|
+
workDays: [1, 2, 3, 4, 5],
|
|
810
|
+
// Monday to Friday
|
|
811
|
+
hoursPerDay: 8
|
|
812
|
+
};
|
|
813
|
+
var DEFAULT_TAX_BRACKETS = COUNTRY_DEFAULTS.US.taxBrackets;
|
|
814
|
+
function countWorkingDays(startDate, endDate, options = {}) {
|
|
815
|
+
const workDays = options.workDays || DEFAULT_WORK_SCHEDULE.workDays;
|
|
816
|
+
const holidaySet = new Set(
|
|
817
|
+
(options.holidays || []).map((d) => new Date(d).toDateString())
|
|
818
|
+
);
|
|
819
|
+
let totalDays = 0;
|
|
820
|
+
let workingDays = 0;
|
|
821
|
+
let holidays = 0;
|
|
822
|
+
let weekends = 0;
|
|
823
|
+
const current = new Date(startDate);
|
|
824
|
+
current.setHours(0, 0, 0, 0);
|
|
825
|
+
const end = new Date(endDate);
|
|
826
|
+
end.setHours(0, 0, 0, 0);
|
|
827
|
+
while (current <= end) {
|
|
828
|
+
totalDays++;
|
|
829
|
+
const isHoliday = holidaySet.has(current.toDateString());
|
|
830
|
+
const isWorkDay = workDays.includes(current.getDay());
|
|
831
|
+
if (isHoliday) {
|
|
832
|
+
holidays++;
|
|
833
|
+
} else if (isWorkDay) {
|
|
834
|
+
workingDays++;
|
|
835
|
+
} else {
|
|
836
|
+
weekends++;
|
|
837
|
+
}
|
|
838
|
+
current.setDate(current.getDate() + 1);
|
|
839
|
+
}
|
|
840
|
+
return { totalDays, workingDays, weekends, holidays };
|
|
841
|
+
}
|
|
842
|
+
function calculateProration(hireDate, terminationDate, periodStart, periodEnd) {
|
|
843
|
+
const hire = new Date(hireDate);
|
|
844
|
+
hire.setHours(0, 0, 0, 0);
|
|
845
|
+
const term = terminationDate ? new Date(terminationDate) : null;
|
|
846
|
+
if (term) term.setHours(0, 0, 0, 0);
|
|
847
|
+
const start = new Date(periodStart);
|
|
848
|
+
start.setHours(0, 0, 0, 0);
|
|
849
|
+
const end = new Date(periodEnd);
|
|
850
|
+
end.setHours(0, 0, 0, 0);
|
|
851
|
+
if (hire > end || term && term < start) {
|
|
852
|
+
return { ratio: 0, reason: "full", isProrated: true };
|
|
853
|
+
}
|
|
854
|
+
const effectiveStart = hire > start ? hire : start;
|
|
855
|
+
const effectiveEnd = term && term < end ? term : end;
|
|
856
|
+
const totalDays = Math.ceil((end.getTime() - start.getTime()) / 864e5) + 1;
|
|
857
|
+
const actualDays = Math.ceil((effectiveEnd.getTime() - effectiveStart.getTime()) / 864e5) + 1;
|
|
858
|
+
const ratio = Math.min(1, Math.max(0, actualDays / totalDays));
|
|
859
|
+
const isNewHire = hire > start;
|
|
860
|
+
const isTermination = term !== null && term < end;
|
|
861
|
+
let reason = "full";
|
|
862
|
+
if (isNewHire && isTermination) {
|
|
863
|
+
reason = "both";
|
|
864
|
+
} else if (isNewHire) {
|
|
865
|
+
reason = "new_hire";
|
|
866
|
+
} else if (isTermination) {
|
|
867
|
+
reason = "termination";
|
|
868
|
+
}
|
|
869
|
+
return { ratio, reason, isProrated: ratio < 1 };
|
|
870
|
+
}
|
|
871
|
+
function calculateTax(monthlyIncome, currency, customBrackets) {
|
|
872
|
+
const brackets = customBrackets || COUNTRY_DEFAULTS[currency]?.taxBrackets || DEFAULT_TAX_BRACKETS;
|
|
873
|
+
const annualIncome = monthlyIncome * 12;
|
|
874
|
+
let annualTax = 0;
|
|
875
|
+
for (const bracket of brackets) {
|
|
876
|
+
if (annualIncome <= bracket.min) continue;
|
|
877
|
+
const taxableInBracket = Math.min(annualIncome, bracket.max) - bracket.min;
|
|
878
|
+
annualTax += taxableInBracket * bracket.rate;
|
|
879
|
+
}
|
|
880
|
+
const monthlyTax = Math.round(annualTax / 12);
|
|
881
|
+
const effectiveRate = monthlyIncome > 0 ? monthlyTax / monthlyIncome : 0;
|
|
882
|
+
return { amount: monthlyTax, effectiveRate };
|
|
883
|
+
}
|
|
884
|
+
function calculateAttendanceDeduction(expectedDays, actualDays, dailyRate, maxDeductionPercent = 100) {
|
|
885
|
+
const absentDays = Math.max(0, expectedDays - actualDays);
|
|
886
|
+
const deduction = Math.round(absentDays * dailyRate);
|
|
887
|
+
const maxDeduction = Math.round(dailyRate * expectedDays * maxDeductionPercent / 100);
|
|
888
|
+
return Math.min(deduction, maxDeduction);
|
|
889
|
+
}
|
|
890
|
+
function calculateSalaryBreakdown(params) {
|
|
891
|
+
const {
|
|
892
|
+
baseSalary,
|
|
893
|
+
currency,
|
|
894
|
+
hireDate,
|
|
895
|
+
terminationDate,
|
|
896
|
+
periodStart,
|
|
897
|
+
periodEnd,
|
|
898
|
+
allowances = [],
|
|
899
|
+
deductions = [],
|
|
900
|
+
options = {},
|
|
901
|
+
attendance
|
|
902
|
+
} = params;
|
|
903
|
+
const workSchedule = { ...DEFAULT_WORK_SCHEDULE, ...options.workSchedule };
|
|
904
|
+
const workingDays = countWorkingDays(periodStart, periodEnd, {
|
|
905
|
+
workDays: workSchedule.workDays,
|
|
906
|
+
holidays: options.holidays
|
|
907
|
+
});
|
|
908
|
+
const proration = options.skipProration ? { ratio: 1, reason: "full", isProrated: false } : calculateProration(hireDate, terminationDate, periodStart, periodEnd);
|
|
909
|
+
const proratedBase = Math.round(baseSalary * proration.ratio);
|
|
910
|
+
const processedAllowances = allowances.map((a) => ({
|
|
911
|
+
type: a.type,
|
|
912
|
+
amount: Math.round(a.amount * proration.ratio),
|
|
913
|
+
taxable: a.taxable ?? true
|
|
914
|
+
}));
|
|
915
|
+
const totalAllowances = processedAllowances.reduce((sum, a) => sum + a.amount, 0);
|
|
916
|
+
const processedDeductions = deductions.map((d) => ({
|
|
917
|
+
type: d.type,
|
|
918
|
+
amount: Math.round(d.amount * proration.ratio)
|
|
919
|
+
}));
|
|
920
|
+
let attendanceDeduction = 0;
|
|
921
|
+
if (attendance && !options.skipAttendance && workingDays.workingDays > 0) {
|
|
922
|
+
const dailyRate = proratedBase / workingDays.workingDays;
|
|
923
|
+
attendanceDeduction = calculateAttendanceDeduction(
|
|
924
|
+
attendance.expectedDays,
|
|
925
|
+
attendance.actualDays,
|
|
926
|
+
dailyRate
|
|
927
|
+
);
|
|
928
|
+
if (attendanceDeduction > 0) {
|
|
929
|
+
processedDeductions.push({ type: "attendance", amount: attendanceDeduction });
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
const grossSalary = proratedBase + totalAllowances;
|
|
933
|
+
let taxAmount = 0;
|
|
934
|
+
if (!options.skipTax) {
|
|
935
|
+
const taxableAllowances = processedAllowances.filter((a) => a.taxable).reduce((sum, a) => sum + a.amount, 0);
|
|
936
|
+
const taxableIncome = proratedBase + taxableAllowances;
|
|
937
|
+
const taxResult = calculateTax(taxableIncome, currency);
|
|
938
|
+
taxAmount = taxResult.amount;
|
|
939
|
+
if (taxAmount > 0) {
|
|
940
|
+
processedDeductions.push({ type: "tax", amount: taxAmount });
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
const totalDeductions = processedDeductions.filter((d) => d.type !== "tax" && d.type !== "attendance").reduce((sum, d) => sum + d.amount, 0);
|
|
944
|
+
const netSalary = grossSalary - totalDeductions - attendanceDeduction - taxAmount;
|
|
945
|
+
return {
|
|
946
|
+
baseSalary,
|
|
947
|
+
proratedBase,
|
|
948
|
+
totalAllowances,
|
|
949
|
+
totalDeductions,
|
|
950
|
+
attendanceDeduction,
|
|
951
|
+
grossSalary,
|
|
952
|
+
taxAmount,
|
|
953
|
+
netSalary,
|
|
954
|
+
proration,
|
|
955
|
+
workingDays,
|
|
956
|
+
breakdown: {
|
|
957
|
+
allowances: processedAllowances,
|
|
958
|
+
deductions: processedDeductions
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
function getPayPeriod(month, year, payDay = 28) {
|
|
963
|
+
const startDate = new Date(year, month - 1, 1);
|
|
964
|
+
const endDate = new Date(year, month, 0);
|
|
965
|
+
const payDate = new Date(year, month - 1, Math.min(payDay, endDate.getDate()));
|
|
966
|
+
return { startDate, endDate, payDate };
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
export { COUNTRY_DEFAULTS, Container, DEFAULT_TAX_BRACKETS, DEFAULT_WORK_SCHEDULE, EventBus, PluginManager, Result, ResultClass, all, calculateAttendanceDeduction, calculateProration, calculateSalaryBreakdown, calculateTax, countWorkingDays, createEventBus, createNotificationPlugin, definePlugin, err, flatMap, fromNullable, fromPromise, getConfig, getContainer, getEventBus, getModels, getPayPeriod, initializeContainer, isContainerInitialized, isErr, isOk, isSingleTenant, loggingPlugin, map, mapErr, match, metricsPlugin, notificationPlugin, ok, onEmployeeHired, onMilestoneAchieved, onPayrollCompleted, onSalaryProcessed, resetEventBus, tryCatch, tryCatchSync, unwrap, unwrapOr, unwrapOrElse };
|
|
970
|
+
//# sourceMappingURL=index.js.map
|
|
971
|
+
//# sourceMappingURL=index.js.map
|