Function: computePayRun()
computePayRun(
companyId,period):Promise<PayRunPreview>
Defined in: src/server/services/payroll.ts:188
Compute (without persisting) the contractor pay for a bi-monthly period. Pulls each contractor's applicable assignment rate, their period time entries (payable statuses only), and approved holidays (in-house admins), then runs the pure pay engine. Assignment lines whose computed pay is <= 0 centavos are dropped (no empty payslip line); a contractor still appears as long as at least one assignment pays. Used by both the preview and the close action.
Parameters
companyId
string
Tenant scope; every query is filtered to this company.
period
The bi-monthly half (year/month/half + start/end CalendarDates) to price.
Returns
Promise<PayRunPreview>
A PayRunPreview: priced lines (one per paid assignment), totalCentavos (PHP
centavos), the priced-scope/TOCTOU snapshot, warning day-counts, and per-contractor errors.
Remarks
Domain rules baked in here:
- Billing vs pay weeks. Overage approvals are stored on Sunday-anchored billing weeks; the pay
engine keys overage on the ISO Monday week, so loadApprovedOverageWeeks translates each
approved week via
overageApprovalWeekToPayWeek. An approved over-contracted week is paid on its full worked hours; otherwise pay caps at the contracted rate (the lesser of logged/contracted). - Settling-week fetch window. Outsourced pay settles whole Mon–Sun weeks by their Sunday
(ADR-0044), so entries are read from the first settling week's Monday — which may precede
period.start— throughperiod.end. In-period tail days that settle next period stay visible to in-house pay and the close TOCTOU check but do not change outsourced pay. - Holidays are credited only to
in_house_admincontractors and only on their primary assignment, so a multi-assignment admin is never double-credited. - Per-contractor assignment selection is deterministic (stable query ordering), so the separate preview and close runs price the identical rate.
This is read-only: it opens a service-role client and queries but persists nothing. A pay-engine
failure for one contractor is captured in result.errors (not thrown); that contractor is skipped.
Throws
MoneyError (via centavos) if an assignment's bimonthly_rate_centavos is somehow a
non-integer or exceeds the JS safe-integer range; bigint storage makes this practically
unreachable, but unlike pay-engine validation errors it aborts the whole run rather than being
captured in errors.