
# Service Library - `payrollReporting`

This document provides a complete reference of the custom code library for the `payrollReporting` service. It includes all library functions, edge functions with their REST endpoints, templates, and assets.


## Library Functions

Library functions are reusable modules available to all business APIs and other custom code within the service via `require("lib/<moduleName>")`.


### `calculateTotalHoursWorked.js`

```js
// Computes total worked hours for given user within [periodStart, periodEnd].
// Attendance records with status 'present' or 'late' are counted as working hours.
// Args: context (Business API ctx), userId, periodStart, periodEnd
const { fetchRemoteListByMQuery } = require('serviceCommon');
module.exports = async function calculateTotalHoursWorked(context, userId, periodStart, periodEnd) {
  if (!userId || !periodStart || !periodEnd) return 0;
  const records = await fetchRemoteListByMQuery(
    'attendanceRecord',
    {
      userId: userId,
      checkInTime: { $gte: periodStart },
      checkOutTime: { $lte: periodEnd },
      status: { $in: ['present', 'late', 'leftEarly'] },
      isActive: true
    },
    0,
    3000 // practical max per period
  );
  let total = 0;
  for (const rec of records) {
    if (rec.checkInTime && rec.checkOutTime) {
      const hours = (new Date(rec.checkOutTime) - new Date(rec.checkInTime)) / (60 * 60 * 1000);
      total += Math.max(hours, 0.0);
    }
  }
  return Number(total.toFixed(2));
};
```


### `calculateOvertimeHours.js`

```js
// Computes total overtime hours in attendance within [periodStart, periodEnd].
// Overtime: working over 8 hours/shift (could be customized)
const { fetchRemoteListByMQuery } = require('serviceCommon');
module.exports = async function calculateOvertimeHours(context, userId, periodStart, periodEnd) {
  if (!userId || !periodStart || !periodEnd) return 0;
  const records = await fetchRemoteListByMQuery(
    'attendanceRecord',
    {
      userId: userId,
      checkInTime: { $gte: periodStart },
      checkOutTime: { $lte: periodEnd },
      status: { $in: ['present', 'late', 'leftEarly'] },
      isActive: true
    },
    0,
    3000
  );
  let overtime = 0;
  for (const rec of records) {
    if (rec.checkInTime && rec.checkOutTime) {
      const hours = (new Date(rec.checkOutTime) - new Date(rec.checkInTime)) / (60 * 60 * 1000);
      if (hours > 8) overtime += (hours - 8);
    }
  }
  return Number(overtime.toFixed(2));
};
```


### `calculateAbsenceDays.js`

```js
// Absence = days with leaveRequest.status === 'approved' or
//           attendance status === 'absent' during period
const { fetchRemoteListByMQuery } = require('serviceCommon');
module.exports = async function calculateAbsenceDays(context, userId, periodStart, periodEnd) {
  if (!userId || !periodStart || !periodEnd) return 0;
  // Attendance absences
  const attendance = await fetchRemoteListByMQuery(
    'attendanceRecord',
    {
      userId: userId,
      checkInTime: { $gte: periodStart },
      checkOutTime: { $lte: periodEnd },
      status: 'absent',
      isActive: true
    }, 0, 3000
  );
  let absentDays = new Set();
  for (const rec of attendance) {
    if (rec.checkInTime) absentDays.add((new Date(rec.checkInTime)).toISOString().slice(0,10));
  }
  // Leave requests
  const leaveRequests = await fetchRemoteListByMQuery(
    'leaveRequest',
    {
      userId: userId,
      status: 'approved',
      startDate: { $lte: periodEnd },
      endDate: { $gte: periodStart },
      isActive: true
    }, 0, 200
  );
  for (const leave of leaveRequests) {
    let d1 = new Date(leave.startDate), d2 = new Date(leave.endDate);
    for (let d = d1; d <= d2; d.setDate(d.getDate() + 1)) {
      const day = new Date(d).toISOString().slice(0,10);
      if ( (day >= periodStart && day <= periodEnd) ) absentDays.add(day)
    }
  }
  return absentDays.size;
};
```


### `calculateSalary.js`

```js
// Salary calculated based on policy: hourlyRate from employeeProfile/position, multiply worked+overtime, add bonus, subtract deduction. No payments processed. Placeholder: baseRate = 15/hr, overtimeRate = 1.5x
const { fetchRemoteObjectByMQuery } = require('serviceCommon');
module.exports = async function calculateSalary(context, userId, periodStart, periodEnd, totalHoursWorked, overtimeHours, bonus, deduction) {
  if (!userId || !periodStart || !periodEnd) return 0;
  // Fetch employee profile to get salary/position if defined
  let baseRate = 15, overtimeRate = 1.5 * baseRate;
  const empProf = await fetchRemoteObjectByMQuery("employeeProfile", { userId });
  if (empProf && empProf.salary && empProf.salary > 0) baseRate = empProf.salary / 160; // Assume salary is monthly, 160h month
  let base = Number(totalHoursWorked || 0) * baseRate;
  let ot = Number(overtimeHours || 0) * overtimeRate;
  let gross = base + ot + Number(bonus||0) - Number(deduction||0);
  return Number(gross.toFixed(2));
};
```














---

*This document was generated from the service library configuration and should be kept in sync with design changes.*
