@classytic/payroll 1.0.0 → 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.

@@ -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
- * Batch Payroll Factory - Process multiple employees
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) => ({
package/src/init.js CHANGED
@@ -3,6 +3,27 @@ import logger, { setLogger } from './utils/logger.js';
3
3
 
4
4
  let initialized = false;
5
5
 
6
+ /**
7
+ * Initialize HRM/Payroll framework
8
+ *
9
+ * @param {Object} options - Initialization options
10
+ * @param {Model} options.EmployeeModel - Employee model (required)
11
+ * @param {Model} options.PayrollRecordModel - Payroll record model (required)
12
+ * @param {Model} options.TransactionModel - Transaction model (required)
13
+ * @param {Model} options.AttendanceModel - Optional attendance model for integration
14
+ * @param {Object} options.logger - Optional custom logger
15
+ *
16
+ * @example Multi-Tenant (default)
17
+ * initializeHRM({
18
+ * EmployeeModel,
19
+ * PayrollRecordModel,
20
+ * TransactionModel
21
+ * });
22
+ *
23
+ * @example Single-Tenant
24
+ * // For single-tenant apps, add organizationId with default value in your Employee schema:
25
+ * // organizationId: { type: ObjectId, required: true, default: () => FIXED_ORG_ID }
26
+ */
6
27
  export function initializeHRM({ EmployeeModel, PayrollRecordModel, TransactionModel, AttendanceModel = null, logger: customLogger }) {
7
28
  // Allow users to inject their own logger
8
29
  if (customLogger) {
@@ -136,11 +136,18 @@ export function employeePlugin(schema, options = {}) {
136
136
  });
137
137
  };
138
138
 
139
- schema.pre('save', function(next) {
139
+ /**
140
+ * Pre-save hook to automatically update salary calculations
141
+ * when compensation is modified.
142
+ *
143
+ * Mongoose v9 compatible - uses async function without next callback
144
+ * - Use throw instead of next(err) for errors
145
+ * - Use return instead of return next()
146
+ */
147
+ schema.pre('save', async function() {
140
148
  if (this.isModified('compensation')) {
141
149
  this.updateSalaryCalculations();
142
150
  }
143
- next();
144
151
  });
145
152
 
146
153
  schema.index({ organizationId: 1, employeeId: 1 }, { unique: true });