Skip to content

Module — Payroll

Monthly staff compensation. It generates the payroll run from HR contracts and attendance, splits each salary across project budget lines and donors, and manages the supporting employee documents — advances / loans (with ordinary and emergency cash boxes), overtime claims, and timesheets (including the leave requests that flow through the same controller).

Source: NKO.Main/NKO.Main/Controllers/{Payroll,Overtime,Timesheet}Controller.cs and AdvanceController .cs; NKO.Main/NKO.Main/BAL/{BPayroll,BAdvance,BOvertime,BTimesheet}.cs; NKO.Lib/NKO.Shared/ViewModels/Payroll/PayrollStatus.cs.

Purpose & scope

  • In scope: the Payroll run and its per-employee PayrollInfo lines, salary allocation across budget lines, advances / loans and the cash boxes, overtime claims, and timesheets.
  • Out of scope: the contracts and compensation records themselves (HR), the budget lines and donor exchange rates (Grant), and the leave approval workflow (Leave Management) — the leave requests live on TimesheetController but the rules are HR's.
  • Database: NKO_DB (core), context NKO_DBEntities1.

Key features

  • Payroll run — one Payroll per month/year; Generate builds a PayrollInfo per eligible (non-private) employee; four-tier sign-off (Requester → Allocator → Finance Manager → Country Director) with refuse-to-draft reset; the exchange rate is captured at the Finance stage; exports (full, "min", per-month, allocations); "Transfer Finance / Partners data" Excel import; the branch treasurer is notified on acceptance.
  • Allocations — distribute an employee's monthly basic salary across budget lines by LOE %, converting to USD / EUR via DonorExchangeRate; the allocator cannot sign until every shared employee is fully allocated (IsAllRatiosAvailable).
  • Advances & loans — an eligibility engine (core staff only, past the trial period, tenure and prior-loan rules); advance ≤ 50 % of net salary (50–100 % needs justification); a loan repayment schedule auto-split over N months; ordinary + emergency cash boxes (balances held in CommonSetting), pending-loan auto-payment, a cash-box transaction ledger, "Set as paid", and guarantors.
  • Overtime — multi-date claims; amount = hours × ((contract.Amount / 30) / 8) × factor (1.5 normal, 2.0 weekend / public holiday); Complete / Edit recompute; copy-as-draft; emergent flag + finance disclosure.
  • Timesheets & leave — a monthly timesheet per employee (Draft → Manager → HR → Treasurer pay → payment confirm); leave requests with balance checks, a substitute user, hourly / daily types; project-ratio months; leave-balance create / import; the attendance calendar.

Screens

Route = /{Controller}/{Action}; primary screens only. Full list in the Payroll API reference.

PayrollController — /Payroll/*

Feature Route View Permission key
Payroll runs list /Payroll/Index Payroll/Index.cshtml PayrollIndex
Run detail (per-employee lines + sign-off) /Payroll/Details/{id} Details.cshtml PayrollDetails
Generate a run /Payroll/Create _Create.cshtml PayrollCreate
Reset a run to draft /Payroll/Reset/{id} (redirect) PayrollCreate
Upload partner-contribution split /Payroll/TransferData TransferData.cshtml PayrollTransferData
Upload bank / finance data /Payroll/TransferFinanceData/{id} TransferFinanceData.cshtml PayrollTransferData
Exports (bank file / min / allocations) /Payroll/Export/{id}, /Payroll/ExportMin/{id}, /Payroll/ExportPayroll, /Payroll/ExportAllocations (files) PayrollExport, PayrollTransferData

AdvanceController — /Advance/*

Feature Route View Permission key
Advance & loan requests /Advance/Index Advance/Index.cshtml AdvanceIndex
Request detail /Advance/Details/{id} Details.cshtml AdvanceDetails
Create / manage / complete /Advance/Manage/{id}, /Advance/Complete/{id} Manage.cshtml, Complete.cshtml AdvanceCreate
Cash-box transaction ledger /Advance/CashBoxTransaction CashBoxTransaction.cshtml AdvanceCashBoxTransaction
Set a disbursement as paid /Advance/SetAsPaid/{id} _AdvanceDetailsPaid.cshtml AdvanceCashBoxTransaction

OvertimeController — /Overtime/*

Feature Route View Permission key
Overtime claims /Overtime/Index Overtime/Index.cshtml OvertimeIndex
Claim detail /Overtime/Details/{id} Details.cshtml OvertimeDetails
Create / edit / complete /Overtime/Create/{id}, /Overtime/Edit/{id}, /Overtime/Complete/{id} Create/Edit/Complete.cshtml OvertimeCreate

TimesheetController — /Timesheet/*

Feature Route View Permission key
Timesheets list /Timesheet/Index Timesheet/Index.cshtml TimesheetIndex
Timesheet detail /Timesheet/Details/{id} Details.cshtml TimesheetDetails
Create timesheet /Timesheet/Create Create.cshtml TimesheetCreate
Project ratios /Timesheet/ProjectsRatio ProjectsRatio.cshtml TimesheetProjectsRatio
Leaves list / details /Timesheet/Leaves, /Timesheet/LeaveDetails/{id} Leaves.cshtml, LeaveDetails.cshtml TimesheetLeaves, TimesheetLeaveDetails
Create / edit / complete leave /Timesheet/CreateLeave, /Timesheet/EditLeave/{id}, /Timesheet/CompleteLeave/{id} CreateLeave/EditLeave/CompleteLeave.cshtml TimesheetCreateLeave, TimesheetEditLeave
Leave-balance create / import /Timesheet/CreateLeaveBalance, /Timesheet/ImportData _CreateLeaveBalance.cshtml, ImportData.cshtml UserIndex
Attendance calendar /Timesheet/AttendanceCalendar AttendanceCalendar.cshtml TimesheetLeaves
SR / payroll exports /Timesheet/ExportSR, /Timesheet/ExportPayroll (files) TimesheetExportSR, TimesheetTransferData

Business logic

Class File Responsibility & notable logic
BPayroll NKO.Main/NKO.Main/BAL/BPayroll.cs (~1070 ln) Generate(id) / Create — wipe existing PayrollInfo, call GetPayrollVM(month, year), materialise one PayrollInfo per employee, then ProcBudgetLineHandler.Reallocate(month, year). GetPayrollVM computes per employee (contract overlapping the month, !IsPrivate): basic salary — one contract → its Amount; several → pro-rate Amount/30 × GetWorkingDays(...) capping the remaining days, rounded to 4 dp. Rewards = Σ AppUserReward.Amount; SocialInsurance = Σ AppUserInsurance.AmountUSD. Loan = Σ BAdvance.GetLoansList(...); Advance = Σ accepted advances signed in the month. Overtime = BTimesheet.GetOvertime(...).TotalAmount. Unpaid = BLeave.GetAnnualBalanceByMonth(...).UnPaidLeaves + totalAbsence (from IAttendancesHandler.DelayInHoursMinutes); UnPaidLeaves = userDays + unpaid where userDays = 30 − BUser.GetWorkingDays(...). TotalDeductions = autoDeductions + userDeductions + advance + loan, autoDeductions = (userDays + unpaid) × basicSalary/30. Workflow: SetSent, SetAllocatorAccepted/Refused (gated by BTimesheet.IsAllRatiosAvailable), SetFinanceManagerAccepted(…, exchangeRate)/Refused, SetCountryDirectorAccepted/Refused.
BAdvance NKO.Main/NKO.Main/BAL/BAdvance.cs (~2440 ln) GetBalance(user) — core only, past trial period: AdvBalance = (netSalary + allowance) / 2; LoanBalance = 0 if tenure < 1 yr OR an unpaid loan detail exists OR the last loan repaid < 6 months ago, else contract.Amount (1–2 yrs) or contract.Amount × 2 (≥ 2 yrs). CanSubmitAdvance — rejects non-core / in-trial / already-pending; > ½ (net + allowance) ⇒ AcceptedWithJusitification. MapLoanDetails — DivRem(amount, months, out reminder); monthlyAmount = (amount − reminder)/months; the first instalment carries the remainder; one AppUserAdvanceDetails per month. Cash boxes — GetOrdinaryBox / GetEmergencyBox read CommonSetting keys CashBox / EmergencyBox; Add/Substract…Box mutate them. CompletePendingLoans — for accepted unpaid loans: emergent & ≤ ordinary → one ordinary CashBoxTransaction; > ordinary → split ordinary + emergency; non-emergent → ordinary only. SetLoanDetailsPaid — tops the emergency box back to CashBoxStandards.EmergencyCashBox first, remainder to ordinary. Long list of Set* approval methods.
BOvertime NKO.Main/NKO.Main/BAL/BOvertime.cs (~1460 ln) Create — dailyAmount = (contract.Amount / 30) / 8; per date factor = 1.5, bumped to 2 if the date is in a public-holiday range (BCalendar.GetPublicHolidays); DailyHours = round(GetDuration(start, end), 2); Amount += DailyHours × dailyAmount × factor. Complete derives factor from Attendance.Type (Weekend / PublicHoliday → 2). Reuses BAdvance's advance/loan helpers.
BTimesheet NKO.Main/NKO.Main/BAL/BTimesheet.cs (~760 ln) Create — CreatedOn = last day of the month; status Draft. GetOvertime(userId, month, year) → OvertimeFullVM (TotalAmount = Σ AppUserOvertime.Amount) — consumed by BPayroll. IsAllRatiosAvailable(year, month) — Σ AppUserAllocation.SalaryRatio must equal PayrollInfo count × 100 (the allocator sign-off gate). Pay / AcceptPayment — the treasurer pays and the recipient confirms; AcceptPayment calls BAdvance.SetAdvancePaidBack. GetMyTimesheets is data-scoped (All / Location / Custom / Default).

Data

  • Run: Payroll, PayrollInfo (BasicSalary, TotalDeductions, UnpaidLeaves, SocialInsurance, Rewards, Overtime, OvertimeHours, TransferredToBank, Advance, AdvanceIds CSV, Loan).
  • Allocation: AppUserAllocation (SalaryRatio, BenefitRatio, Month, Year, BudgetLineId, PayrollInfoId, SalaryAmountUSD/EURO/TL, ExchangeRateUSD/Euro).
  • Advances & cash: AppUserAdvance, AppUserAdvanceDetails, CashBoxTransaction, Bank (ref).
  • Overtime: AppUserOvertime, AppUserOvertimeDates, AppUserOvertimeConsumption.
  • Timesheet: Timesheet, PartnersContributionMain, PartnersContribution.
  • Compensation inputs (HR-owned): AppUserSalary, AppUserAllowance, AppUserDeduction, AppUserCharge, AppUserReward, AppUserBankPayment, AppUserInsurance, AppUserContract.

Full column detail: Payroll database.

Permissions

Distinct keys: PayrollIndex, PayrollDetails, PayrollCreate, PayrollTransferData, PayrollExport; AdvanceIndex, AdvanceDetails, AdvanceCreate, AdvanceEdit, AdvanceCashBoxTransaction; OvertimeIndex, OvertimeDetails, OvertimeCreate; TimesheetIndex, TimesheetDetails, TimesheetCreate, TimesheetEdit, TimesheetEditInvoice, TimesheetLeaves, TimesheetLeaveDetails, TimesheetCreateLeave, TimesheetEditLeave, TimesheetCreateMonth, TimesheetProjectsRatio, TimesheetRatioDetails, TimesheetExportSR, TimesheetTransferData. Cross-module keys reused: AllocationsIndex, GetUsers, UserIndex, ProjectCreate, HumanResourceExportUsers. Data scoping: SharedPermissions.{Advances = 6, Overtime = 15, Timesheet = 3, Leave = 2}.

PayrollStatus: Draft (0) · WaitingForAllocations (1) · WaitingForFinanceManager (2) · WaitingForCountryDirector (3) · Accepted (4) · Refused (5). Refused (5) is declared but never assigned — a refusal at any step sends the payroll back to Draft.

Screenshots

Payroll runs and a run's approval timeline — /Payroll and /Payroll/Details/{id}:

Payrolls list Payroll approval timeline — part 1 part 2

Timesheets that feed a run — /Timesheet:

Timesheet list

Advance / Loan requests — /Advance (filter panel and ALL REQUESTS tab; this view is scoped to the signed-in user's own / approval-chain requests, so it is empty for an admin — see Recommendations R7-12):

Advance / Loan request list

Loans Box — /Advance/CashBoxTransaction (the Ordinary and Emergency cash boxes with owed / available balances, plus the transaction and queue lists):

Loans Box cash boxes

Overtime requests — /Overtime (employee names masked):

Overtime request list