@classytic/payroll 1.0.1 → 1.0.2
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/dist/types/config.d.ts +162 -0
- package/dist/types/core/compensation.manager.d.ts +54 -0
- package/dist/types/core/employment.manager.d.ts +49 -0
- package/dist/types/core/payroll.manager.d.ts +60 -0
- package/dist/types/enums.d.ts +117 -0
- package/dist/types/factories/compensation.factory.d.ts +196 -0
- package/dist/types/factories/employee.factory.d.ts +149 -0
- package/dist/types/factories/payroll.factory.d.ts +319 -0
- package/dist/types/hrm.orchestrator.d.ts +47 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/init.d.ts +30 -0
- package/dist/types/models/payroll-record.model.d.ts +3 -0
- package/dist/types/plugins/employee.plugin.d.ts +2 -0
- package/dist/types/schemas/employment.schema.d.ts +959 -0
- package/dist/types/services/compensation.service.d.ts +94 -0
- package/dist/types/services/employee.service.d.ts +28 -0
- package/dist/types/services/payroll.service.d.ts +30 -0
- package/dist/types/utils/calculation.utils.d.ts +26 -0
- package/dist/types/utils/date.utils.d.ts +35 -0
- package/dist/types/utils/logger.d.ts +12 -0
- package/dist/types/utils/query-builders.d.ts +83 -0
- package/dist/types/utils/validation.utils.d.ts +33 -0
- package/package.json +32 -13
- package/src/factories/payroll.factory.js +167 -1
- package/src/init.js +21 -0
- package/src/plugins/employee.plugin.js +9 -2
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export class CompensationService {
|
|
2
|
+
constructor(EmployeeModel: any);
|
|
3
|
+
EmployeeModel: any;
|
|
4
|
+
getEmployeeCompensation(employeeId: any): Promise<any>;
|
|
5
|
+
calculateBreakdown(employeeId: any): Promise<{
|
|
6
|
+
baseAmount: any;
|
|
7
|
+
allowances: any;
|
|
8
|
+
deductions: any;
|
|
9
|
+
grossAmount: any;
|
|
10
|
+
netAmount: number;
|
|
11
|
+
}>;
|
|
12
|
+
updateBaseAmount(employeeId: any, newAmount: any, effectiveFrom: any): Promise<{
|
|
13
|
+
baseAmount: any;
|
|
14
|
+
allowances: any;
|
|
15
|
+
deductions: any;
|
|
16
|
+
grossAmount: any;
|
|
17
|
+
netAmount: number;
|
|
18
|
+
}>;
|
|
19
|
+
applyIncrement(employeeId: any, { percentage, amount, effectiveFrom }: {
|
|
20
|
+
percentage: any;
|
|
21
|
+
amount: any;
|
|
22
|
+
effectiveFrom: any;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
baseAmount: any;
|
|
25
|
+
allowances: any;
|
|
26
|
+
deductions: any;
|
|
27
|
+
grossAmount: any;
|
|
28
|
+
netAmount: number;
|
|
29
|
+
}>;
|
|
30
|
+
addAllowance(employeeId: any, allowance: any): Promise<{
|
|
31
|
+
baseAmount: any;
|
|
32
|
+
allowances: any;
|
|
33
|
+
deductions: any;
|
|
34
|
+
grossAmount: any;
|
|
35
|
+
netAmount: number;
|
|
36
|
+
}>;
|
|
37
|
+
removeAllowance(employeeId: any, allowanceType: any): Promise<{
|
|
38
|
+
baseAmount: any;
|
|
39
|
+
allowances: any;
|
|
40
|
+
deductions: any;
|
|
41
|
+
grossAmount: any;
|
|
42
|
+
netAmount: number;
|
|
43
|
+
}>;
|
|
44
|
+
addDeduction(employeeId: any, deduction: any): Promise<{
|
|
45
|
+
baseAmount: any;
|
|
46
|
+
allowances: any;
|
|
47
|
+
deductions: any;
|
|
48
|
+
grossAmount: any;
|
|
49
|
+
netAmount: number;
|
|
50
|
+
}>;
|
|
51
|
+
removeDeduction(employeeId: any, deductionType: any): Promise<{
|
|
52
|
+
baseAmount: any;
|
|
53
|
+
allowances: any;
|
|
54
|
+
deductions: any;
|
|
55
|
+
grossAmount: any;
|
|
56
|
+
netAmount: number;
|
|
57
|
+
}>;
|
|
58
|
+
setStandardCompensation(employeeId: any, baseAmount: any): Promise<{
|
|
59
|
+
baseAmount: any;
|
|
60
|
+
allowances: any;
|
|
61
|
+
deductions: any;
|
|
62
|
+
grossAmount: any;
|
|
63
|
+
netAmount: number;
|
|
64
|
+
}>;
|
|
65
|
+
compareCompensation(employeeId1: any, employeeId2: any): Promise<{
|
|
66
|
+
employee1: {
|
|
67
|
+
baseAmount: any;
|
|
68
|
+
allowances: any;
|
|
69
|
+
deductions: any;
|
|
70
|
+
grossAmount: any;
|
|
71
|
+
netAmount: number;
|
|
72
|
+
};
|
|
73
|
+
employee2: {
|
|
74
|
+
baseAmount: any;
|
|
75
|
+
allowances: any;
|
|
76
|
+
deductions: any;
|
|
77
|
+
grossAmount: any;
|
|
78
|
+
netAmount: number;
|
|
79
|
+
};
|
|
80
|
+
difference: {
|
|
81
|
+
base: number;
|
|
82
|
+
gross: number;
|
|
83
|
+
net: number;
|
|
84
|
+
};
|
|
85
|
+
ratio: {
|
|
86
|
+
base: number;
|
|
87
|
+
gross: number;
|
|
88
|
+
net: number;
|
|
89
|
+
};
|
|
90
|
+
}>;
|
|
91
|
+
getDepartmentCompensationStats(organizationId: any, department: any): Promise<any>;
|
|
92
|
+
getOrganizationCompensationStats(organizationId: any): Promise<any>;
|
|
93
|
+
}
|
|
94
|
+
export function createCompensationService(EmployeeModel: any): CompensationService;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export class EmployeeService {
|
|
2
|
+
constructor(EmployeeModel: any);
|
|
3
|
+
EmployeeModel: any;
|
|
4
|
+
findById(employeeId: any): Promise<any>;
|
|
5
|
+
findByUserId(userId: any, organizationId: any): Promise<any>;
|
|
6
|
+
findActive(organizationId: any, options?: {}): Promise<any>;
|
|
7
|
+
findEmployed(organizationId: any, options?: {}): Promise<any>;
|
|
8
|
+
findByDepartment(organizationId: any, department: any): Promise<any>;
|
|
9
|
+
findEligibleForPayroll(organizationId: any, month: any, year: any): Promise<any>;
|
|
10
|
+
create(data: any): Promise<any>;
|
|
11
|
+
updateStatus(employeeId: any, status: any, context?: {}): Promise<any>;
|
|
12
|
+
terminate(employeeId: any, reason: any, context?: {}): Promise<any>;
|
|
13
|
+
updateCompensation(employeeId: any, compensation: any): Promise<any>;
|
|
14
|
+
getEmployeeStats(organizationId: any): Promise<{
|
|
15
|
+
total: any;
|
|
16
|
+
active: any;
|
|
17
|
+
employed: any;
|
|
18
|
+
canReceiveSalary: any;
|
|
19
|
+
byStatus: any;
|
|
20
|
+
byDepartment: any;
|
|
21
|
+
}>;
|
|
22
|
+
groupByStatus(employees: any): any;
|
|
23
|
+
groupByDepartment(employees: any): any;
|
|
24
|
+
isActive(employee: any): boolean;
|
|
25
|
+
isEmployed(employee: any): boolean;
|
|
26
|
+
canReceiveSalary(employee: any): boolean;
|
|
27
|
+
}
|
|
28
|
+
export function createEmployeeService(EmployeeModel: any): EmployeeService;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class PayrollService {
|
|
2
|
+
constructor(PayrollModel: any, EmployeeService: any);
|
|
3
|
+
PayrollModel: any;
|
|
4
|
+
EmployeeService: any;
|
|
5
|
+
findById(payrollId: any): Promise<any>;
|
|
6
|
+
findByEmployee(employeeId: any, organizationId: any, options?: {}): Promise<any>;
|
|
7
|
+
findForPeriod(organizationId: any, month: any, year: any): Promise<any>;
|
|
8
|
+
findPending(organizationId: any, month: any, year: any): Promise<any>;
|
|
9
|
+
create(data: any): Promise<any>;
|
|
10
|
+
generateForEmployee(employeeId: any, organizationId: any, month: any, year: any): Promise<any>;
|
|
11
|
+
generateBatch(organizationId: any, month: any, year: any): Promise<{
|
|
12
|
+
success: boolean;
|
|
13
|
+
generated: number;
|
|
14
|
+
message: string;
|
|
15
|
+
payrolls?: undefined;
|
|
16
|
+
} | {
|
|
17
|
+
success: boolean;
|
|
18
|
+
generated: any;
|
|
19
|
+
payrolls: any;
|
|
20
|
+
message?: undefined;
|
|
21
|
+
}>;
|
|
22
|
+
markAsPaid(payrollId: any, paymentDetails?: {}): Promise<any>;
|
|
23
|
+
markAsProcessed(payrollId: any): Promise<any>;
|
|
24
|
+
calculatePeriodSummary(organizationId: any, month: any, year: any): Promise<any>;
|
|
25
|
+
getEmployeePayrollHistory(employeeId: any, organizationId: any, limit?: number): Promise<any>;
|
|
26
|
+
findByEmployeeAndPeriod(employeeId: any, organizationId: any, month: any, year: any): Promise<any>;
|
|
27
|
+
groupByStatus(payrolls: any): any;
|
|
28
|
+
getOverviewStats(organizationId: any): Promise<any>;
|
|
29
|
+
}
|
|
30
|
+
export function createPayrollService(PayrollModel: any, EmployeeService: any): PayrollService;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function sum(items: any, key: any): any;
|
|
2
|
+
export function sumBy(key: any): (items: any) => any;
|
|
3
|
+
export function sumAllowances(items: any): any;
|
|
4
|
+
export function sumDeductions(items: any): any;
|
|
5
|
+
export function calculateGross(base: any, allowances: any): any;
|
|
6
|
+
export function calculateNet(gross: any, deductions: any): number;
|
|
7
|
+
export function calculateTotalCompensation(base: any, allowances: any, deductions: any): {
|
|
8
|
+
gross: any;
|
|
9
|
+
net: number;
|
|
10
|
+
deductions: any;
|
|
11
|
+
};
|
|
12
|
+
export function applyTaxBracket(amount: any, brackets: any): number;
|
|
13
|
+
export function calculateTax(amount: any, brackets: any): {
|
|
14
|
+
gross: any;
|
|
15
|
+
tax: number;
|
|
16
|
+
net: number;
|
|
17
|
+
};
|
|
18
|
+
export function proRateAmount(amount: any, workedDays: any, totalDays: any): number;
|
|
19
|
+
export function calculatePercentage(value: any, total: any): number;
|
|
20
|
+
export function applyPercentage(amount: any, percentage: any): number;
|
|
21
|
+
export function composeDeductions(...deductionFns: any[]): (amount: any) => any;
|
|
22
|
+
export function composeSalaryPipeline(base: any, operations: any): any;
|
|
23
|
+
export function createAllowanceCalculator(allowances: any): (base: any) => any;
|
|
24
|
+
export function createDeductionCalculator(deductions: any): (gross: any) => any;
|
|
25
|
+
export function pipe(...fns: any[]): (value: any) => any;
|
|
26
|
+
export function compose(...fns: any[]): (value: any) => any;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function addDays(date: any, days: any): Date;
|
|
2
|
+
export function addMonths(date: any, months: any): Date;
|
|
3
|
+
export function addYears(date: any, years: any): Date;
|
|
4
|
+
export function startOfMonth(date: any): Date;
|
|
5
|
+
export function endOfMonth(date: any): Date;
|
|
6
|
+
export function startOfYear(date: any): Date;
|
|
7
|
+
export function endOfYear(date: any): Date;
|
|
8
|
+
export function isWeekday(date: any): boolean;
|
|
9
|
+
export function isWeekend(date: any): boolean;
|
|
10
|
+
export function getPayPeriod(month: any, year: any): {
|
|
11
|
+
month: any;
|
|
12
|
+
year: any;
|
|
13
|
+
startDate: Date;
|
|
14
|
+
endDate: Date;
|
|
15
|
+
};
|
|
16
|
+
export function getCurrentPeriod(date?: Date): {
|
|
17
|
+
year: number;
|
|
18
|
+
month: number;
|
|
19
|
+
};
|
|
20
|
+
export function calculateProbationEnd(hireDate: any, probationMonths: any): Date;
|
|
21
|
+
export function formatDateForDB(date: any): string;
|
|
22
|
+
export function parseDBDate(dateString: any): Date;
|
|
23
|
+
export function diffInDays(start: any, end: any): number;
|
|
24
|
+
export function diffInMonths(start: any, end: any): number;
|
|
25
|
+
export function daysBetween(start: any, end: any): number;
|
|
26
|
+
export function monthsBetween(start: any, end: any): number;
|
|
27
|
+
export function isDateInRange(date: any, start: any, end: any): boolean;
|
|
28
|
+
export function formatPeriod({ month, year }: {
|
|
29
|
+
month: any;
|
|
30
|
+
year: any;
|
|
31
|
+
}): string;
|
|
32
|
+
export function parsePeriod(periodString: any): {
|
|
33
|
+
month: any;
|
|
34
|
+
year: any;
|
|
35
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set custom logger implementation
|
|
3
|
+
* @param {Object} customLogger - Logger instance with info, warn, error, debug methods
|
|
4
|
+
*/
|
|
5
|
+
export function setLogger(customLogger: any): void;
|
|
6
|
+
export namespace logger {
|
|
7
|
+
function info(...args: any[]): void;
|
|
8
|
+
function warn(...args: any[]): void;
|
|
9
|
+
function error(...args: any[]): void;
|
|
10
|
+
function debug(...args: any[]): void;
|
|
11
|
+
}
|
|
12
|
+
export default logger;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export function toObjectId(id: any): mongoose.Types.ObjectId;
|
|
2
|
+
export class QueryBuilder {
|
|
3
|
+
constructor(initialQuery?: {});
|
|
4
|
+
query: {};
|
|
5
|
+
where(field: any, value: any): this;
|
|
6
|
+
whereIn(field: any, values: any): this;
|
|
7
|
+
whereNotIn(field: any, values: any): this;
|
|
8
|
+
whereGte(field: any, value: any): this;
|
|
9
|
+
whereLte(field: any, value: any): this;
|
|
10
|
+
whereBetween(field: any, start: any, end: any): this;
|
|
11
|
+
whereExists(field: any): this;
|
|
12
|
+
whereNotExists(field: any): this;
|
|
13
|
+
build(): {};
|
|
14
|
+
}
|
|
15
|
+
export function createQueryBuilder(initialQuery: any): QueryBuilder;
|
|
16
|
+
export class EmployeeQueryBuilder extends QueryBuilder {
|
|
17
|
+
forOrganization(organizationId: any): this;
|
|
18
|
+
forUser(userId: any): this;
|
|
19
|
+
withStatus(...statuses: any[]): this;
|
|
20
|
+
active(): this;
|
|
21
|
+
employed(): this;
|
|
22
|
+
inDepartment(department: any): this;
|
|
23
|
+
inPosition(position: any): this;
|
|
24
|
+
withEmploymentType(type: any): this;
|
|
25
|
+
hiredAfter(date: any): this;
|
|
26
|
+
hiredBefore(date: any): this;
|
|
27
|
+
}
|
|
28
|
+
export class PayrollQueryBuilder extends QueryBuilder {
|
|
29
|
+
forOrganization(organizationId: any): this;
|
|
30
|
+
forEmployee(employeeId: any): this;
|
|
31
|
+
forPeriod(month: any, year: any): this;
|
|
32
|
+
withStatus(...statuses: any[]): this;
|
|
33
|
+
paid(): this;
|
|
34
|
+
pending(): this;
|
|
35
|
+
inDateRange(start: any, end: any): this;
|
|
36
|
+
}
|
|
37
|
+
export function employee(): EmployeeQueryBuilder;
|
|
38
|
+
export function payroll(): PayrollQueryBuilder;
|
|
39
|
+
export function buildEmployeeQuery({ organizationId, userId, statuses }: {
|
|
40
|
+
organizationId: any;
|
|
41
|
+
userId: any;
|
|
42
|
+
statuses: any;
|
|
43
|
+
}): {};
|
|
44
|
+
export function buildPayrollQuery({ employeeId, period, statuses }: {
|
|
45
|
+
employeeId: any;
|
|
46
|
+
period: any;
|
|
47
|
+
statuses: any;
|
|
48
|
+
}): {};
|
|
49
|
+
export function buildAggregationPipeline(...stages: any[]): any[];
|
|
50
|
+
export function matchStage(query: any): {
|
|
51
|
+
$match: any;
|
|
52
|
+
};
|
|
53
|
+
export function groupStage(groupBy: any, aggregations: any): {
|
|
54
|
+
$group: any;
|
|
55
|
+
};
|
|
56
|
+
export function sortStage(sortBy: any): {
|
|
57
|
+
$sort: any;
|
|
58
|
+
};
|
|
59
|
+
export function limitStage(limit: any): {
|
|
60
|
+
$limit: any;
|
|
61
|
+
};
|
|
62
|
+
export function projectStage(fields: any): {
|
|
63
|
+
$project: any;
|
|
64
|
+
};
|
|
65
|
+
export function lookupStage({ from, localField, foreignField, as }: {
|
|
66
|
+
from: any;
|
|
67
|
+
localField: any;
|
|
68
|
+
foreignField: any;
|
|
69
|
+
as: any;
|
|
70
|
+
}): {
|
|
71
|
+
$lookup: {
|
|
72
|
+
from: any;
|
|
73
|
+
localField: any;
|
|
74
|
+
foreignField: any;
|
|
75
|
+
as: any;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
export function unwindStage(path: any, options?: {}): {
|
|
79
|
+
$unwind: {
|
|
80
|
+
path: any;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
import mongoose from 'mongoose';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function isActive(employee: any): boolean;
|
|
2
|
+
export function isOnLeave(employee: any): boolean;
|
|
3
|
+
export function isSuspended(employee: any): boolean;
|
|
4
|
+
export function isTerminated(employee: any): boolean;
|
|
5
|
+
export function isEmployed(employee: any): boolean;
|
|
6
|
+
export function canReceiveSalary(employee: any): boolean;
|
|
7
|
+
export function canUpdateEmployment(employee: any): boolean;
|
|
8
|
+
export function isInProbation(employee: any, now?: Date): boolean;
|
|
9
|
+
export function hasCompletedProbation(employee: any, now?: Date): boolean;
|
|
10
|
+
export function hasCompensation(employee: any): boolean;
|
|
11
|
+
export function isEligibleForBonus(employee: any, requiredMonths?: number): boolean;
|
|
12
|
+
export function isValidCompensation(compensation: any): any;
|
|
13
|
+
export function isValidBankDetails(bankDetails: any): any;
|
|
14
|
+
export function hasRequiredFields(obj: any, fields: any): any;
|
|
15
|
+
export function createValidator(validationFns: any): (data: any) => {
|
|
16
|
+
isValid: boolean;
|
|
17
|
+
errors: {
|
|
18
|
+
field: string;
|
|
19
|
+
message: any;
|
|
20
|
+
}[];
|
|
21
|
+
};
|
|
22
|
+
export function required(fieldName: any): (value: any) => string | true;
|
|
23
|
+
export function min(minValue: any, fieldName: any): (value: any) => string | true;
|
|
24
|
+
export function max(maxValue: any, fieldName: any): (value: any) => string | true;
|
|
25
|
+
export function inRange(minValue: any, maxValue: any, fieldName: any): (value: any) => string | true;
|
|
26
|
+
export function oneOf(allowedValues: any, fieldName: any): (value: any) => string | true;
|
|
27
|
+
export function compose(...validators: any[]): (value: any, data: any) => any;
|
|
28
|
+
export function isPositive(fieldName: any): (value: any) => string | true;
|
|
29
|
+
export function isValidStatus(value: any): boolean;
|
|
30
|
+
export function isValidEmploymentType(value: any): boolean;
|
|
31
|
+
export function minValue(minValue: any, fieldName: any): (value: any) => string | true;
|
|
32
|
+
export function maxValue(maxValue: any, fieldName: any): (value: any) => string | true;
|
|
33
|
+
export function isInRange(minValue: any, maxValue: any, fieldName: any): (value: any) => string | true;
|
package/package.json
CHANGED
|
@@ -1,21 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/payroll",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Modern HRM and payroll management library for Node.js applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
|
-
"types": "./
|
|
7
|
+
"types": "./dist/types/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
|
-
".":
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"./
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/types/index.d.ts",
|
|
11
|
+
"import": "./src/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./init": {
|
|
14
|
+
"types": "./dist/types/init.d.ts",
|
|
15
|
+
"import": "./src/init.js"
|
|
16
|
+
},
|
|
17
|
+
"./service": {
|
|
18
|
+
"types": "./dist/types/service.d.ts",
|
|
19
|
+
"import": "./src/service.js"
|
|
20
|
+
},
|
|
21
|
+
"./schemas/*": {
|
|
22
|
+
"types": "./dist/types/schemas/*.d.ts",
|
|
23
|
+
"import": "./src/schemas/*.js"
|
|
24
|
+
}
|
|
16
25
|
},
|
|
17
26
|
"files": [
|
|
18
27
|
"src/**/*.js",
|
|
28
|
+
"!src/**/*.test.js",
|
|
29
|
+
"!src/**/*.spec.js",
|
|
30
|
+
"!src/**/__tests__/**",
|
|
31
|
+
"dist/types/",
|
|
19
32
|
"payroll.d.ts",
|
|
20
33
|
"README.md",
|
|
21
34
|
"LICENSE"
|
|
@@ -42,20 +55,26 @@
|
|
|
42
55
|
},
|
|
43
56
|
"homepage": "https://github.com/classytic/payroll#readme",
|
|
44
57
|
"peerDependencies": {
|
|
45
|
-
"mongoose": "^8.0.0"
|
|
58
|
+
"mongoose": "^8.0.0 || ^9.0.0"
|
|
46
59
|
},
|
|
47
60
|
"devDependencies": {
|
|
48
|
-
"mongoose": "^
|
|
61
|
+
"mongoose": "^9.0.0",
|
|
49
62
|
"mongoose-aggregate-paginate-v2": "^1.1.4",
|
|
50
|
-
"mongoose-paginate-v2": "^1.9.0"
|
|
63
|
+
"mongoose-paginate-v2": "^1.9.0",
|
|
64
|
+
"@types/node": "^22.8.7",
|
|
65
|
+
"typescript": "^5.6.3"
|
|
51
66
|
},
|
|
52
67
|
"engines": {
|
|
53
68
|
"node": ">=18.0.0"
|
|
54
69
|
},
|
|
55
70
|
"scripts": {
|
|
71
|
+
"types": "tsc --project tsconfig.types.json",
|
|
72
|
+
"build": "npm run types",
|
|
73
|
+
"prepublishOnly": "npm run build",
|
|
56
74
|
"example:basic": "node test/examples/basic-usage.js",
|
|
57
75
|
"example:mongoose": "node test/examples/with-mongoose.js",
|
|
58
76
|
"example:workflow": "node test/examples/full-workflow.js",
|
|
59
|
-
"test": "
|
|
77
|
+
"test:v9": "node test/employee-plugin-v9.test.js",
|
|
78
|
+
"test": "npm run example:basic && npm run example:mongoose && npm run example:workflow && npm run test:v9"
|
|
60
79
|
}
|
|
61
80
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Payroll Factory - Beautiful Salary Calculation & Record Creation
|
|
3
3
|
* Clean, testable, immutable payroll object creation
|
|
4
|
+
*
|
|
5
|
+
* Compatible with Mongoose v8 and v9
|
|
4
6
|
*/
|
|
5
7
|
|
|
6
8
|
import {
|
|
@@ -12,7 +14,66 @@ import {
|
|
|
12
14
|
|
|
13
15
|
import { getPayPeriod } from '../utils/date.utils.js';
|
|
14
16
|
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {Object} AllowanceInput
|
|
19
|
+
* @property {string} type - Type of allowance
|
|
20
|
+
* @property {string} [name] - Display name for the allowance
|
|
21
|
+
* @property {number} value - Allowance value (amount or percentage)
|
|
22
|
+
* @property {boolean} [isPercentage=false] - Whether value is a percentage
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {Object} DeductionInput
|
|
27
|
+
* @property {string} type - Type of deduction
|
|
28
|
+
* @property {string} [name] - Display name for the deduction
|
|
29
|
+
* @property {number} value - Deduction value (amount or percentage)
|
|
30
|
+
* @property {boolean} [isPercentage=false] - Whether value is a percentage
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @typedef {Object} PeriodInput
|
|
35
|
+
* @property {number} [month] - Month (1-12)
|
|
36
|
+
* @property {number} [year] - Year
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @typedef {Object} PayrollMetadata
|
|
41
|
+
* @property {string} [currency='BDT'] - Currency code
|
|
42
|
+
* @property {string} [paymentMethod] - Payment method
|
|
43
|
+
* @property {string} [notes] - Additional notes
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @typedef {Object} PayrollRecord
|
|
48
|
+
* @property {string} employeeId - Employee identifier
|
|
49
|
+
* @property {string} organizationId - Organization identifier
|
|
50
|
+
* @property {Object} period - Pay period information
|
|
51
|
+
* @property {Object} breakdown - Salary breakdown
|
|
52
|
+
* @property {number} breakdown.baseAmount - Base salary amount
|
|
53
|
+
* @property {Array} breakdown.allowances - Calculated allowances
|
|
54
|
+
* @property {Array} breakdown.deductions - Calculated deductions
|
|
55
|
+
* @property {number} breakdown.grossSalary - Gross salary
|
|
56
|
+
* @property {number} breakdown.netSalary - Net salary after deductions
|
|
57
|
+
* @property {string} status - Payroll status ('pending', 'processed', 'paid')
|
|
58
|
+
* @property {Date|null} processedAt - When payroll was processed
|
|
59
|
+
* @property {Date|null} paidAt - When payment was made
|
|
60
|
+
* @property {PayrollMetadata} metadata - Additional metadata
|
|
61
|
+
*/
|
|
62
|
+
|
|
15
63
|
export class PayrollFactory {
|
|
64
|
+
/**
|
|
65
|
+
* Create a new payroll record
|
|
66
|
+
*
|
|
67
|
+
* @param {Object} params - Payroll parameters
|
|
68
|
+
* @param {string} params.employeeId - Employee ID
|
|
69
|
+
* @param {string} params.organizationId - Organization ID
|
|
70
|
+
* @param {number} params.baseAmount - Base salary amount
|
|
71
|
+
* @param {AllowanceInput[]} [params.allowances=[]] - Allowances array
|
|
72
|
+
* @param {DeductionInput[]} [params.deductions=[]] - Deductions array
|
|
73
|
+
* @param {PeriodInput} [params.period={}] - Pay period
|
|
74
|
+
* @param {PayrollMetadata} [params.metadata={}] - Additional metadata
|
|
75
|
+
* @returns {PayrollRecord} Payroll record object
|
|
76
|
+
*/
|
|
16
77
|
static create({
|
|
17
78
|
employeeId,
|
|
18
79
|
organizationId,
|
|
@@ -50,6 +111,14 @@ export class PayrollFactory {
|
|
|
50
111
|
};
|
|
51
112
|
}
|
|
52
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Create a pay period object
|
|
116
|
+
*
|
|
117
|
+
* @param {PeriodInput} [params={}] - Period parameters
|
|
118
|
+
* @param {number} [params.month] - Month (defaults to current month)
|
|
119
|
+
* @param {number} [params.year] - Year (defaults to current year)
|
|
120
|
+
* @returns {Object} Pay period object with startDate, endDate, etc.
|
|
121
|
+
*/
|
|
53
122
|
static createPeriod({ month, year } = {}) {
|
|
54
123
|
const now = new Date();
|
|
55
124
|
return getPayPeriod(
|
|
@@ -58,6 +127,13 @@ export class PayrollFactory {
|
|
|
58
127
|
);
|
|
59
128
|
}
|
|
60
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Calculate allowances from base amount and allowance inputs
|
|
132
|
+
*
|
|
133
|
+
* @param {number} baseAmount - Base salary amount
|
|
134
|
+
* @param {AllowanceInput[]} allowances - Array of allowances
|
|
135
|
+
* @returns {Array} Calculated allowances with amounts
|
|
136
|
+
*/
|
|
61
137
|
static calculateAllowances(baseAmount, allowances) {
|
|
62
138
|
return allowances.map((allowance) => {
|
|
63
139
|
const amount = allowance.isPercentage
|
|
@@ -74,6 +150,13 @@ export class PayrollFactory {
|
|
|
74
150
|
});
|
|
75
151
|
}
|
|
76
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Calculate deductions from base amount and deduction inputs
|
|
155
|
+
*
|
|
156
|
+
* @param {number} baseAmount - Base salary amount
|
|
157
|
+
* @param {DeductionInput[]} deductions - Array of deductions
|
|
158
|
+
* @returns {Array} Calculated deductions with amounts
|
|
159
|
+
*/
|
|
77
160
|
static calculateDeductions(baseAmount, deductions) {
|
|
78
161
|
return deductions.map((deduction) => {
|
|
79
162
|
const amount = deduction.isPercentage
|
|
@@ -90,6 +173,16 @@ export class PayrollFactory {
|
|
|
90
173
|
});
|
|
91
174
|
}
|
|
92
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Create a bonus object
|
|
178
|
+
*
|
|
179
|
+
* @param {Object} params - Bonus parameters
|
|
180
|
+
* @param {string} params.type - Bonus type
|
|
181
|
+
* @param {number} params.amount - Bonus amount
|
|
182
|
+
* @param {string} params.reason - Reason for bonus
|
|
183
|
+
* @param {string} params.approvedBy - User who approved the bonus
|
|
184
|
+
* @returns {Object} Bonus object
|
|
185
|
+
*/
|
|
93
186
|
static createBonus({ type, amount, reason, approvedBy }) {
|
|
94
187
|
return {
|
|
95
188
|
type,
|
|
@@ -100,6 +193,16 @@ export class PayrollFactory {
|
|
|
100
193
|
};
|
|
101
194
|
}
|
|
102
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Create a deduction object
|
|
198
|
+
*
|
|
199
|
+
* @param {Object} params - Deduction parameters
|
|
200
|
+
* @param {string} params.type - Deduction type
|
|
201
|
+
* @param {number} params.amount - Deduction amount
|
|
202
|
+
* @param {string} params.reason - Reason for deduction
|
|
203
|
+
* @param {string} params.appliedBy - User who applied the deduction
|
|
204
|
+
* @returns {Object} Deduction object
|
|
205
|
+
*/
|
|
103
206
|
static createDeduction({ type, amount, reason, appliedBy }) {
|
|
104
207
|
return {
|
|
105
208
|
type,
|
|
@@ -110,6 +213,16 @@ export class PayrollFactory {
|
|
|
110
213
|
};
|
|
111
214
|
}
|
|
112
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Mark a payroll record as paid (immutable - returns new object)
|
|
218
|
+
*
|
|
219
|
+
* @param {PayrollRecord} payroll - Payroll record to mark as paid
|
|
220
|
+
* @param {Object} [params={}] - Payment details
|
|
221
|
+
* @param {Date} [params.paidAt] - Payment date (defaults to now)
|
|
222
|
+
* @param {string} [params.transactionId] - Transaction ID
|
|
223
|
+
* @param {string} [params.paymentMethod] - Payment method
|
|
224
|
+
* @returns {PayrollRecord} New payroll record marked as paid
|
|
225
|
+
*/
|
|
113
226
|
static markAsPaid(payroll, { paidAt = new Date(), transactionId, paymentMethod } = {}) {
|
|
114
227
|
return {
|
|
115
228
|
...payroll,
|
|
@@ -124,6 +237,14 @@ export class PayrollFactory {
|
|
|
124
237
|
};
|
|
125
238
|
}
|
|
126
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Mark a payroll record as processed (immutable - returns new object)
|
|
242
|
+
*
|
|
243
|
+
* @param {PayrollRecord} payroll - Payroll record to mark as processed
|
|
244
|
+
* @param {Object} [params={}] - Processing details
|
|
245
|
+
* @param {Date} [params.processedAt] - Processing date (defaults to now)
|
|
246
|
+
* @returns {PayrollRecord} New payroll record marked as processed
|
|
247
|
+
*/
|
|
127
248
|
static markAsProcessed(payroll, { processedAt = new Date() } = {}) {
|
|
128
249
|
return {
|
|
129
250
|
...payroll,
|
|
@@ -133,6 +254,18 @@ export class PayrollFactory {
|
|
|
133
254
|
}
|
|
134
255
|
}
|
|
135
256
|
|
|
257
|
+
/**
|
|
258
|
+
* PayrollBuilder - Fluent builder pattern for creating payroll records
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* const payroll = createPayroll()
|
|
262
|
+
* .forEmployee('emp-123')
|
|
263
|
+
* .inOrganization('org-456')
|
|
264
|
+
* .withBaseAmount(50000)
|
|
265
|
+
* .addAllowance('housing', 10000)
|
|
266
|
+
* .addDeduction('tax', 15, true)
|
|
267
|
+
* .build();
|
|
268
|
+
*/
|
|
136
269
|
export class PayrollBuilder {
|
|
137
270
|
constructor() {
|
|
138
271
|
this.data = {
|
|
@@ -203,12 +336,34 @@ export class PayrollBuilder {
|
|
|
203
336
|
}
|
|
204
337
|
}
|
|
205
338
|
|
|
339
|
+
/**
|
|
340
|
+
* Create a new PayrollBuilder instance
|
|
341
|
+
*
|
|
342
|
+
* @returns {PayrollBuilder} New builder instance
|
|
343
|
+
*/
|
|
206
344
|
export const createPayroll = () => new PayrollBuilder();
|
|
207
345
|
|
|
208
346
|
/**
|
|
209
|
-
*
|
|
347
|
+
* BatchPayrollFactory - Process payroll for multiple employees at once
|
|
348
|
+
*
|
|
349
|
+
* @example
|
|
350
|
+
* const payrolls = BatchPayrollFactory.createBatch(employees, {
|
|
351
|
+
* month: 1,
|
|
352
|
+
* year: 2025,
|
|
353
|
+
* organizationId: 'org-123'
|
|
354
|
+
* });
|
|
210
355
|
*/
|
|
211
356
|
export class BatchPayrollFactory {
|
|
357
|
+
/**
|
|
358
|
+
* Create payroll records for multiple employees
|
|
359
|
+
*
|
|
360
|
+
* @param {Array} employees - Array of employee objects
|
|
361
|
+
* @param {Object} params - Batch parameters
|
|
362
|
+
* @param {number} params.month - Month for payroll
|
|
363
|
+
* @param {number} params.year - Year for payroll
|
|
364
|
+
* @param {string} params.organizationId - Organization ID
|
|
365
|
+
* @returns {PayrollRecord[]} Array of payroll records
|
|
366
|
+
*/
|
|
212
367
|
static createBatch(employees, { month, year, organizationId }) {
|
|
213
368
|
return employees.map((employee) =>
|
|
214
369
|
PayrollFactory.create({
|
|
@@ -222,6 +377,17 @@ export class BatchPayrollFactory {
|
|
|
222
377
|
);
|
|
223
378
|
}
|
|
224
379
|
|
|
380
|
+
/**
|
|
381
|
+
* Calculate total payroll amounts across multiple records
|
|
382
|
+
*
|
|
383
|
+
* @param {PayrollRecord[]} payrolls - Array of payroll records
|
|
384
|
+
* @returns {Object} Totals summary
|
|
385
|
+
* @returns {number} return.count - Total number of payrolls
|
|
386
|
+
* @returns {number} return.totalGross - Sum of gross salaries
|
|
387
|
+
* @returns {number} return.totalNet - Sum of net salaries
|
|
388
|
+
* @returns {number} return.totalAllowances - Sum of all allowances
|
|
389
|
+
* @returns {number} return.totalDeductions - Sum of all deductions
|
|
390
|
+
*/
|
|
225
391
|
static calculateTotalPayroll(payrolls) {
|
|
226
392
|
return payrolls.reduce(
|
|
227
393
|
(totals, payroll) => ({
|