@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,433 @@
1
+ import { X as Compensation, b8 as TaxBracket, aM as PayrollBreakdown } from '../types-BN3K_Uhr.js';
2
+ import 'mongoose';
3
+
4
+ /**
5
+ * @classytic/payroll - Salary Calculator
6
+ *
7
+ * Pure functions for complete salary breakdown calculations.
8
+ * No database dependencies - can be used client-side!
9
+ *
10
+ * This is the SINGLE SOURCE OF TRUTH for all salary calculations.
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+
15
+ /**
16
+ * Input for salary breakdown calculation
17
+ */
18
+ interface SalaryCalculationInput {
19
+ /**
20
+ * Employee data (minimal subset needed for calculation)
21
+ */
22
+ employee: {
23
+ hireDate: Date;
24
+ terminationDate?: Date | null;
25
+ compensation: Compensation;
26
+ workSchedule?: {
27
+ workingDays?: number[];
28
+ hoursPerDay?: number;
29
+ };
30
+ };
31
+ /**
32
+ * Salary period
33
+ */
34
+ period: {
35
+ month: number;
36
+ year: number;
37
+ startDate: Date;
38
+ endDate: Date;
39
+ };
40
+ /**
41
+ * Attendance data (optional)
42
+ */
43
+ attendance?: {
44
+ expectedDays?: number;
45
+ actualDays?: number;
46
+ } | null;
47
+ /**
48
+ * Processing options
49
+ */
50
+ options?: {
51
+ holidays?: Date[];
52
+ workSchedule?: {
53
+ workingDays?: number[];
54
+ hoursPerDay?: number;
55
+ };
56
+ skipTax?: boolean;
57
+ skipAttendance?: boolean;
58
+ skipProration?: boolean;
59
+ };
60
+ /**
61
+ * Configuration (minimal subset)
62
+ */
63
+ config: {
64
+ allowProRating: boolean;
65
+ autoDeductions: boolean;
66
+ defaultCurrency: string;
67
+ attendanceIntegration: boolean;
68
+ };
69
+ /**
70
+ * Tax brackets for the employee's currency
71
+ */
72
+ taxBrackets: TaxBracket[];
73
+ }
74
+ /**
75
+ * Processed allowance with calculated amount
76
+ */
77
+ interface ProcessedAllowance {
78
+ type: string;
79
+ amount: number;
80
+ taxable: boolean;
81
+ originalAmount?: number;
82
+ isPercentage?: boolean;
83
+ value?: number;
84
+ }
85
+ /**
86
+ * Processed deduction with calculated amount
87
+ */
88
+ interface ProcessedDeduction {
89
+ type: string;
90
+ amount: number;
91
+ description?: string;
92
+ originalAmount?: number;
93
+ isPercentage?: boolean;
94
+ value?: number;
95
+ }
96
+ /**
97
+ * Calculate complete salary breakdown
98
+ *
99
+ * This is the SINGLE SOURCE OF TRUTH for salary calculations.
100
+ * All payroll processing uses this function.
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * const breakdown = calculateSalaryBreakdown({
105
+ * employee: {
106
+ * hireDate: new Date('2024-01-01'),
107
+ * compensation: {
108
+ * baseAmount: 100000,
109
+ * currency: 'USD',
110
+ * allowances: [{ type: 'housing', amount: 20000, taxable: true }],
111
+ * deductions: [{ type: 'insurance', amount: 5000 }],
112
+ * },
113
+ * },
114
+ * period: {
115
+ * month: 3,
116
+ * year: 2024,
117
+ * startDate: new Date('2024-03-01'),
118
+ * endDate: new Date('2024-03-31'),
119
+ * },
120
+ * attendance: {
121
+ * expectedDays: 22,
122
+ * actualDays: 20, // 2 days absent
123
+ * },
124
+ * options: {
125
+ * holidays: [new Date('2024-03-26')],
126
+ * },
127
+ * config: {
128
+ * allowProRating: true,
129
+ * autoDeductions: true,
130
+ * defaultCurrency: 'USD',
131
+ * attendanceIntegration: true,
132
+ * },
133
+ * taxBrackets: [...],
134
+ * });
135
+ * ```
136
+ *
137
+ * @param input - Salary calculation parameters
138
+ * @returns Complete payroll breakdown
139
+ *
140
+ * @pure This function has no side effects and doesn't access database
141
+ */
142
+ declare function calculateSalaryBreakdown(input: SalaryCalculationInput): PayrollBreakdown;
143
+
144
+ /**
145
+ * @classytic/payroll - Pro-Rating Calculator
146
+ *
147
+ * Pure functions for salary pro-rating calculations.
148
+ * No database dependencies - can be used client-side!
149
+ *
150
+ * Handles:
151
+ * - Mid-period hires
152
+ * - Mid-period terminations
153
+ * - Working days (not calendar days)
154
+ * - Holidays exclusion
155
+ *
156
+ * @packageDocumentation
157
+ */
158
+ /**
159
+ * Input for pro-rating calculation
160
+ */
161
+ interface ProRatingInput {
162
+ /**
163
+ * Employee hire date
164
+ */
165
+ hireDate: Date;
166
+ /**
167
+ * Employee termination date (null if still employed)
168
+ */
169
+ terminationDate: Date | null;
170
+ /**
171
+ * Start of the salary period
172
+ */
173
+ periodStart: Date;
174
+ /**
175
+ * End of the salary period
176
+ */
177
+ periodEnd: Date;
178
+ /**
179
+ * Working days of the week (1=Monday, 7=Sunday)
180
+ * @default [1, 2, 3, 4, 5] (Monday-Friday)
181
+ */
182
+ workingDays: number[];
183
+ /**
184
+ * Public holidays to exclude from working days
185
+ * @default []
186
+ */
187
+ holidays?: Date[];
188
+ }
189
+ /**
190
+ * Result of pro-rating calculation
191
+ */
192
+ interface ProRatingResult {
193
+ /**
194
+ * Whether the salary needs to be pro-rated
195
+ */
196
+ isProRated: boolean;
197
+ /**
198
+ * Pro-rating ratio (0-1)
199
+ * 1 = full salary, 0.5 = half salary, etc.
200
+ */
201
+ ratio: number;
202
+ /**
203
+ * Total working days in the period
204
+ */
205
+ periodWorkingDays: number;
206
+ /**
207
+ * Working days the employee was actually employed
208
+ */
209
+ effectiveWorkingDays: number;
210
+ /**
211
+ * Effective start date (max of hire date and period start)
212
+ */
213
+ effectiveStart: Date;
214
+ /**
215
+ * Effective end date (min of termination date and period end)
216
+ */
217
+ effectiveEnd: Date;
218
+ }
219
+ /**
220
+ * Calculate pro-rating for mid-period hires/terminations
221
+ *
222
+ * This function uses WORKING DAYS (not calendar days) for accurate pro-rating.
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * // Employee hired on March 15th, process March salary
227
+ * const result = calculateProRating({
228
+ * hireDate: new Date('2024-03-15'),
229
+ * terminationDate: null,
230
+ * periodStart: new Date('2024-03-01'),
231
+ * periodEnd: new Date('2024-03-31'),
232
+ * workingDays: [1, 2, 3, 4, 5], // Mon-Fri
233
+ * });
234
+ *
235
+ * console.log(result);
236
+ * // {
237
+ * // isProRated: true,
238
+ * // ratio: 0.64, // Worked 14 out of 22 working days
239
+ * // periodWorkingDays: 22,
240
+ * // effectiveWorkingDays: 14
241
+ * // }
242
+ * ```
243
+ *
244
+ * @param input - Pro-rating calculation parameters
245
+ * @returns Pro-rating result with ratio and working days breakdown
246
+ *
247
+ * @pure This function has no side effects and doesn't access external state
248
+ */
249
+ declare function calculateProRating(input: ProRatingInput): ProRatingResult;
250
+ /**
251
+ * Calculate pro-rated amount from base amount and ratio
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * const proRatedSalary = applyProRating(100000, 0.64); // 64000
256
+ * ```
257
+ *
258
+ * @param baseAmount - Original amount
259
+ * @param ratio - Pro-rating ratio (0-1)
260
+ * @returns Pro-rated amount (rounded)
261
+ *
262
+ * @pure No side effects
263
+ */
264
+ declare function applyProRating(baseAmount: number, ratio: number): number;
265
+ /**
266
+ * Check if pro-rating should be applied for a given hire/termination scenario
267
+ *
268
+ * @param hireDate - Employee hire date
269
+ * @param terminationDate - Employee termination date (null if active)
270
+ * @param periodStart - Salary period start
271
+ * @param periodEnd - Salary period end
272
+ * @returns True if pro-rating is needed
273
+ *
274
+ * @pure No side effects
275
+ */
276
+ declare function shouldProRate(hireDate: Date, terminationDate: Date | null, periodStart: Date, periodEnd: Date): boolean;
277
+
278
+ /**
279
+ * @classytic/payroll - Attendance Deduction Calculator
280
+ *
281
+ * Pure functions for calculating salary deductions based on attendance.
282
+ * No database dependencies - can be used client-side!
283
+ *
284
+ * @packageDocumentation
285
+ */
286
+ /**
287
+ * Input for attendance deduction calculation
288
+ */
289
+ interface AttendanceDeductionInput {
290
+ /**
291
+ * Expected working days in the period (for this specific employee)
292
+ * Should account for hire/termination dates
293
+ */
294
+ expectedWorkingDays: number;
295
+ /**
296
+ * Actual working days the employee was present
297
+ */
298
+ actualWorkingDays: number;
299
+ /**
300
+ * Daily salary rate for this employee
301
+ * Calculated as: baseAmount / expectedWorkingDays
302
+ */
303
+ dailyRate: number;
304
+ }
305
+ /**
306
+ * Result of attendance deduction calculation
307
+ */
308
+ interface AttendanceDeductionResult {
309
+ /**
310
+ * Number of absent days
311
+ */
312
+ absentDays: number;
313
+ /**
314
+ * Total deduction amount
315
+ */
316
+ deductionAmount: number;
317
+ /**
318
+ * Daily rate used for calculation
319
+ */
320
+ dailyRate: number;
321
+ /**
322
+ * Whether any deduction was applied
323
+ */
324
+ hasDeduction: boolean;
325
+ }
326
+ /**
327
+ * Calculate attendance deduction based on absent days
328
+ *
329
+ * @example
330
+ * ```typescript
331
+ * const result = calculateAttendanceDeduction({
332
+ * expectedWorkingDays: 22,
333
+ * actualWorkingDays: 20, // 2 days absent
334
+ * dailyRate: 4545, // 100000 / 22
335
+ * });
336
+ *
337
+ * console.log(result);
338
+ * // {
339
+ * // absentDays: 2,
340
+ * // deductionAmount: 9090,
341
+ * // dailyRate: 4545,
342
+ * // hasDeduction: true
343
+ * // }
344
+ * ```
345
+ *
346
+ * @param input - Attendance deduction parameters
347
+ * @returns Deduction result with breakdown
348
+ *
349
+ * @pure This function has no side effects
350
+ */
351
+ declare function calculateAttendanceDeduction(input: AttendanceDeductionInput): AttendanceDeductionResult;
352
+ /**
353
+ * Calculate daily rate from monthly salary and working days
354
+ *
355
+ * @example
356
+ * ```typescript
357
+ * const daily = calculateDailyRate(100000, 22); // 4545
358
+ * ```
359
+ *
360
+ * @param monthlySalary - Monthly base salary
361
+ * @param workingDays - Working days in the month
362
+ * @returns Daily rate (rounded)
363
+ *
364
+ * @pure No side effects
365
+ */
366
+ declare function calculateDailyRate(monthlySalary: number, workingDays: number): number;
367
+ /**
368
+ * Calculate hourly rate from monthly salary
369
+ *
370
+ * @example
371
+ * ```typescript
372
+ * const hourly = calculateHourlyRate(100000, 22, 8); // 568
373
+ * ```
374
+ *
375
+ * @param monthlySalary - Monthly base salary
376
+ * @param workingDays - Working days in the month
377
+ * @param hoursPerDay - Hours per working day (default: 8)
378
+ * @returns Hourly rate (rounded)
379
+ *
380
+ * @pure No side effects
381
+ */
382
+ declare function calculateHourlyRate(monthlySalary: number, workingDays: number, hoursPerDay?: number): number;
383
+ /**
384
+ * Calculate deduction for partial day absence (half-day, quarter-day, etc.)
385
+ *
386
+ * @example
387
+ * ```typescript
388
+ * // Half-day absence
389
+ * const deduction = calculatePartialDayDeduction(4545, 0.5); // 2272
390
+ * ```
391
+ *
392
+ * @param dailyRate - Daily salary rate
393
+ * @param fractionAbsent - Fraction of day absent (0-1)
394
+ * @returns Deduction amount (rounded)
395
+ *
396
+ * @pure No side effects
397
+ */
398
+ declare function calculatePartialDayDeduction(dailyRate: number, fractionAbsent: number): number;
399
+ /**
400
+ * Calculate total attendance deduction including full and partial day absences
401
+ *
402
+ * @example
403
+ * ```typescript
404
+ * const result = calculateTotalAttendanceDeduction({
405
+ * dailyRate: 4545,
406
+ * fullDayAbsences: 2,
407
+ * partialDayAbsences: [0.5, 0.25], // Half-day + quarter-day
408
+ * });
409
+ *
410
+ * console.log(result);
411
+ * // {
412
+ * // fullDayDeduction: 9090,
413
+ * // partialDayDeduction: 3408,
414
+ * // totalDeduction: 12498
415
+ * // }
416
+ * ```
417
+ *
418
+ * @param input - Absence breakdown
419
+ * @returns Deduction breakdown and total
420
+ *
421
+ * @pure No side effects
422
+ */
423
+ declare function calculateTotalAttendanceDeduction(input: {
424
+ dailyRate: number;
425
+ fullDayAbsences?: number;
426
+ partialDayAbsences?: number[];
427
+ }): {
428
+ fullDayDeduction: number;
429
+ partialDayDeduction: number;
430
+ totalDeduction: number;
431
+ };
432
+
433
+ export { type AttendanceDeductionInput, type AttendanceDeductionResult, type ProRatingInput, type ProRatingResult, type ProcessedAllowance, type ProcessedDeduction, type SalaryCalculationInput, applyProRating, calculateAttendanceDeduction, calculateDailyRate, calculateHourlyRate, calculatePartialDayDeduction, calculateProRating, calculateSalaryBreakdown, calculateTotalAttendanceDeduction, shouldProRate };
@@ -0,0 +1,283 @@
1
+ // src/utils/calculation.ts
2
+ function sumBy(items, getter) {
3
+ return items.reduce((total, item) => total + getter(item), 0);
4
+ }
5
+ function sumAllowances(allowances) {
6
+ return sumBy(allowances, (a) => a.amount);
7
+ }
8
+ function sumDeductions(deductions) {
9
+ return sumBy(deductions, (d) => d.amount);
10
+ }
11
+ function calculateGross(baseAmount, allowances) {
12
+ return baseAmount + sumAllowances(allowances);
13
+ }
14
+ function calculateNet(gross, deductions) {
15
+ return Math.max(0, gross - sumDeductions(deductions));
16
+ }
17
+ function applyTaxBrackets(amount, brackets) {
18
+ let tax = 0;
19
+ for (const bracket of brackets) {
20
+ if (amount > bracket.min) {
21
+ const taxableAmount = Math.min(amount, bracket.max) - bracket.min;
22
+ tax += taxableAmount * bracket.rate;
23
+ }
24
+ }
25
+ return Math.round(tax);
26
+ }
27
+
28
+ // src/core/config.ts
29
+ var DEFAULT_WORK_SCHEDULE = {
30
+ workingDays: [1, 2, 3, 4, 5]};
31
+ function countWorkingDays(startDate, endDate, options = {}) {
32
+ const workDays = options.workingDays || DEFAULT_WORK_SCHEDULE.workingDays;
33
+ const holidaySet = new Set(
34
+ (options.holidays || []).map((d) => new Date(d).toDateString())
35
+ );
36
+ let totalDays = 0;
37
+ let workingDays = 0;
38
+ let holidays = 0;
39
+ let weekends = 0;
40
+ const current = new Date(startDate);
41
+ current.setHours(0, 0, 0, 0);
42
+ const end = new Date(endDate);
43
+ end.setHours(0, 0, 0, 0);
44
+ while (current <= end) {
45
+ totalDays++;
46
+ const isHoliday = holidaySet.has(current.toDateString());
47
+ const isWorkDay = workDays.includes(current.getDay());
48
+ if (isHoliday) {
49
+ holidays++;
50
+ } else if (isWorkDay) {
51
+ workingDays++;
52
+ } else {
53
+ weekends++;
54
+ }
55
+ current.setDate(current.getDate() + 1);
56
+ }
57
+ return { totalDays, workingDays, weekends, holidays };
58
+ }
59
+
60
+ // src/calculators/prorating.calculator.ts
61
+ function calculateProRating(input) {
62
+ const { hireDate, terminationDate, periodStart, periodEnd, workingDays, holidays = [] } = input;
63
+ const hire = new Date(hireDate);
64
+ const termination = terminationDate ? new Date(terminationDate) : null;
65
+ const effectiveStart = hire > periodStart ? hire : periodStart;
66
+ const effectiveEnd = termination && termination < periodEnd ? termination : periodEnd;
67
+ if (effectiveStart > periodEnd || termination && termination < periodStart) {
68
+ const periodWorkingDays2 = countWorkingDays(periodStart, periodEnd, { workingDays, holidays }).workingDays;
69
+ return {
70
+ isProRated: true,
71
+ ratio: 0,
72
+ periodWorkingDays: periodWorkingDays2,
73
+ effectiveWorkingDays: 0,
74
+ effectiveStart: periodStart,
75
+ effectiveEnd: periodStart
76
+ // Effectively zero days
77
+ };
78
+ }
79
+ const periodWorkingDays = countWorkingDays(periodStart, periodEnd, { workingDays, holidays }).workingDays;
80
+ const effectiveWorkingDays = countWorkingDays(effectiveStart, effectiveEnd, { workingDays, holidays }).workingDays;
81
+ const ratio = periodWorkingDays > 0 ? Math.min(1, Math.max(0, effectiveWorkingDays / periodWorkingDays)) : 0;
82
+ const isProRated = ratio < 1;
83
+ return {
84
+ isProRated,
85
+ ratio,
86
+ periodWorkingDays,
87
+ effectiveWorkingDays,
88
+ effectiveStart,
89
+ effectiveEnd
90
+ };
91
+ }
92
+ function applyProRating(baseAmount, ratio) {
93
+ return Math.round(baseAmount * ratio);
94
+ }
95
+ function shouldProRate(hireDate, terminationDate, periodStart, periodEnd) {
96
+ const hire = new Date(hireDate);
97
+ const termination = terminationDate ? new Date(terminationDate) : null;
98
+ if (hire > periodStart) return true;
99
+ if (termination && termination < periodEnd) return true;
100
+ return false;
101
+ }
102
+
103
+ // src/calculators/attendance.calculator.ts
104
+ function calculateAttendanceDeduction(input) {
105
+ const { expectedWorkingDays, actualWorkingDays, dailyRate } = input;
106
+ const expected = Math.max(0, expectedWorkingDays);
107
+ const actual = Math.max(0, actualWorkingDays);
108
+ const rate = Math.max(0, dailyRate);
109
+ const absentDays = Math.max(0, expected - actual);
110
+ const deductionAmount = Math.round(absentDays * rate);
111
+ return {
112
+ absentDays,
113
+ deductionAmount,
114
+ dailyRate: rate,
115
+ hasDeduction: deductionAmount > 0
116
+ };
117
+ }
118
+ function calculateDailyRate(monthlySalary, workingDays) {
119
+ if (workingDays <= 0) return 0;
120
+ return Math.round(monthlySalary / workingDays);
121
+ }
122
+ function calculateHourlyRate(monthlySalary, workingDays, hoursPerDay = 8) {
123
+ const dailyRate = calculateDailyRate(monthlySalary, workingDays);
124
+ if (hoursPerDay <= 0) return 0;
125
+ return Math.round(dailyRate / hoursPerDay);
126
+ }
127
+ function calculatePartialDayDeduction(dailyRate, fractionAbsent) {
128
+ const fraction = Math.min(1, Math.max(0, fractionAbsent));
129
+ return Math.round(dailyRate * fraction);
130
+ }
131
+ function calculateTotalAttendanceDeduction(input) {
132
+ const { dailyRate, fullDayAbsences = 0, partialDayAbsences = [] } = input;
133
+ const fullDayDeduction = Math.round(dailyRate * Math.max(0, fullDayAbsences));
134
+ const partialDayDeduction = partialDayAbsences.reduce(
135
+ (sum, fraction) => sum + calculatePartialDayDeduction(dailyRate, fraction),
136
+ 0
137
+ );
138
+ return {
139
+ fullDayDeduction,
140
+ partialDayDeduction,
141
+ totalDeduction: fullDayDeduction + partialDayDeduction
142
+ };
143
+ }
144
+
145
+ // src/calculators/salary.calculator.ts
146
+ function calculateSalaryBreakdown(input) {
147
+ const { employee, period, attendance, options = {}, config, taxBrackets } = input;
148
+ const comp = employee.compensation;
149
+ const originalBaseAmount = comp.baseAmount;
150
+ const proRating = calculateProRatingForSalary(
151
+ employee.hireDate,
152
+ employee.terminationDate || null,
153
+ period.startDate,
154
+ period.endDate,
155
+ options,
156
+ employee.workSchedule
157
+ );
158
+ let baseAmount = originalBaseAmount;
159
+ if (proRating.isProRated && config.allowProRating && !options.skipProration) {
160
+ baseAmount = Math.round(baseAmount * proRating.ratio);
161
+ }
162
+ const effectiveAllowances = (comp.allowances || []).filter((a) => isEffectiveForPeriod(a, period.startDate, period.endDate));
163
+ const effectiveDeductions = (comp.deductions || []).filter((d) => isEffectiveForPeriod(d, period.startDate, period.endDate)).filter((d) => d.auto || d.recurring);
164
+ const allowances = processAllowances(effectiveAllowances, originalBaseAmount, proRating, config);
165
+ const deductions = processDeductions(effectiveDeductions, originalBaseAmount, proRating, config);
166
+ if (!options.skipAttendance && config.attendanceIntegration && attendance) {
167
+ const attendanceDeductionResult = calculateAttendanceDeductionFromData(
168
+ attendance,
169
+ baseAmount,
170
+ proRating.effectiveWorkingDays
171
+ );
172
+ if (attendanceDeductionResult.hasDeduction) {
173
+ deductions.push({
174
+ type: "absence",
175
+ amount: attendanceDeductionResult.deductionAmount,
176
+ description: `Unpaid leave deduction (${attendanceDeductionResult.absentDays} days)`
177
+ });
178
+ }
179
+ }
180
+ const grossSalary = calculateGross(baseAmount, allowances);
181
+ const taxableAllowances = allowances.filter((a) => a.taxable);
182
+ const taxableAmount = baseAmount + sumAllowances(taxableAllowances);
183
+ let taxAmount = 0;
184
+ if (!options.skipTax && taxBrackets.length > 0 && config.autoDeductions) {
185
+ const annualTaxable = taxableAmount * 12;
186
+ const annualTax = applyTaxBrackets(annualTaxable, taxBrackets);
187
+ taxAmount = Math.round(annualTax / 12);
188
+ }
189
+ if (taxAmount > 0) {
190
+ deductions.push({
191
+ type: "tax",
192
+ amount: taxAmount,
193
+ description: "Income tax"
194
+ });
195
+ }
196
+ const netSalary = calculateNet(grossSalary, deductions);
197
+ return {
198
+ baseAmount,
199
+ allowances,
200
+ deductions,
201
+ grossSalary,
202
+ netSalary,
203
+ taxableAmount,
204
+ taxAmount,
205
+ workingDays: proRating.periodWorkingDays,
206
+ actualDays: proRating.effectiveWorkingDays,
207
+ proRatedAmount: proRating.isProRated && !options.skipProration ? baseAmount : 0,
208
+ attendanceDeduction: attendance ? deductions.find((d) => d.type === "absence")?.amount || 0 : 0
209
+ };
210
+ }
211
+ function isEffectiveForPeriod(item, periodStart, periodEnd) {
212
+ const effectiveFrom = item.effectiveFrom ? new Date(item.effectiveFrom) : /* @__PURE__ */ new Date(0);
213
+ const effectiveTo = item.effectiveTo ? new Date(item.effectiveTo) : /* @__PURE__ */ new Date("2099-12-31");
214
+ return effectiveFrom <= periodEnd && effectiveTo >= periodStart;
215
+ }
216
+ function calculateProRatingForSalary(hireDate, terminationDate, periodStart, periodEnd, options, employeeWorkSchedule) {
217
+ const workingDays = options?.workSchedule?.workingDays || employeeWorkSchedule?.workingDays || [1, 2, 3, 4, 5];
218
+ const holidays = options?.holidays || [];
219
+ return calculateProRating({
220
+ hireDate,
221
+ terminationDate,
222
+ periodStart,
223
+ periodEnd,
224
+ workingDays,
225
+ holidays
226
+ });
227
+ }
228
+ function processAllowances(allowances, originalBaseAmount, proRating, config) {
229
+ return allowances.map((a) => {
230
+ let amount = a.isPercentage && a.value !== void 0 ? Math.round(originalBaseAmount * a.value / 100) : a.amount;
231
+ const originalAmount = amount;
232
+ if (proRating.isProRated && config.allowProRating) {
233
+ amount = Math.round(amount * proRating.ratio);
234
+ }
235
+ return {
236
+ type: a.type,
237
+ amount,
238
+ taxable: a.taxable ?? true,
239
+ originalAmount,
240
+ isPercentage: a.isPercentage,
241
+ value: a.value
242
+ };
243
+ });
244
+ }
245
+ function processDeductions(deductions, originalBaseAmount, proRating, config) {
246
+ return deductions.map((d) => {
247
+ let amount = d.isPercentage && d.value !== void 0 ? Math.round(originalBaseAmount * d.value / 100) : d.amount;
248
+ const originalAmount = amount;
249
+ if (proRating.isProRated && config.allowProRating) {
250
+ amount = Math.round(amount * proRating.ratio);
251
+ }
252
+ return {
253
+ type: d.type,
254
+ amount,
255
+ description: d.description,
256
+ originalAmount,
257
+ isPercentage: d.isPercentage,
258
+ value: d.value
259
+ };
260
+ });
261
+ }
262
+ function calculateAttendanceDeductionFromData(attendance, baseAmount, effectiveWorkingDays) {
263
+ const expectedDays = attendance.expectedDays ?? effectiveWorkingDays;
264
+ const actualDays = attendance.actualDays;
265
+ if (actualDays === void 0) {
266
+ return { hasDeduction: false, deductionAmount: 0, absentDays: 0 };
267
+ }
268
+ const dailyRate = calculateDailyRate(baseAmount, expectedDays);
269
+ const result = calculateAttendanceDeduction({
270
+ expectedWorkingDays: expectedDays,
271
+ actualWorkingDays: actualDays,
272
+ dailyRate
273
+ });
274
+ return {
275
+ hasDeduction: result.hasDeduction,
276
+ deductionAmount: result.deductionAmount,
277
+ absentDays: result.absentDays
278
+ };
279
+ }
280
+
281
+ export { applyProRating, calculateAttendanceDeduction, calculateDailyRate, calculateHourlyRate, calculatePartialDayDeduction, calculateProRating, calculateSalaryBreakdown, calculateTotalAttendanceDeduction, shouldProRate };
282
+ //# sourceMappingURL=index.js.map
283
+ //# sourceMappingURL=index.js.map