Function: buildInvoicePreview()
buildInvoicePreview(
companyId,facilityId,weekStart,opts?):Promise<InvoicePreview| {error:string; }>
Defined in: src/server/services/invoice/generate.ts:171
Compute (without persisting) a facility's weekly invoice: one service line per contractor (the latest/chosen assignment, deduped via pickLatestPerContractor), billing the lesser of actual vs contracted weekly hours at the USD hourly rate, with the hours actually worked compared against contracted for the variance flag. Read-only — no rows are written.
Domain rules:
- Billing week is Sunday-anchored: the period is
weekStartthroughweekStart + 6inclusive. - One assignment per contractor is chosen deterministically (latest effective_date, primary on a tie, then lowest id), consistent with the payroll engine.
- Each line bills
min(actual, contracted)hours; an approved overage (anapprovedapproval_request for this assignment/contractor andweek_start) lifts the cap to actual. - Actual hours sum only payable time entries (status in submitted/pending_approval/approved/locked); soft-deleted (terminated) contractors and assignments with no hourly rate are excluded.
- The variance flag fires when a line's hours differ from contracted by more than the facility's
variance_flag_threshold_pct(default 10%) and overage was not approved — a review signal only.
Parameters
companyId
string
Tenant scope; all reads are filtered to this company.
facilityId
string
Facility to invoice.
weekStart
The Sunday that anchors the billing week (a CalendarDate, not a JS Date).
opts?
allowInactive: true permits previewing an inactive facility (used by recompute /
correct / send-staleness recompute on an already-existing invoice). Default refuses inactive.
allowInactive?
boolean
Returns
Promise<InvoicePreview | { error: string; }>
On success an InvoicePreview (with existingInvoice set when a non-void invoice
already exists for this facility+week, and an empty lines array when there is nothing to bill);
on failure { error } with a user-facing message (facility not found, or inactive without
allowInactive).