Package 'wh347'

Title: Calculations for the WH-347 Certified Payroll Form
Description: Computes one line and one week of the U.S. Department of Labor WH-347 certified payroll form, revised version (Rev. January 2025), used on Davis-Bacon and Related Acts contracts. Given a worker's week (base rate, fringe rates per plan, straight-time and overtime hours per day, cash in lieu of fringe, deductions), it returns columns 5 to 9 of the form, the per-plan fringe totals for the crew and a reconciliation check of column 6B. Port of the Go package 'wh347' published by TableTemplates; no dependency and no I/O.
Authors: TableTemplates [aut, cre, cph]
Maintainer: TableTemplates <[email protected]>
License: MIT + file LICENSE
Version: 0.1.0
Built: 2026-10-09 09:30:42 UTC
Source: https://github.com/tresor4k/wh347-r

Help Index


Compute one line of the WH-347 certified payroll form

Description

Computes one line of the U.S. Department of Labor WH-347 certified payroll form, revised version (Rev. January 2025), used on Davis-Bacon and Related Acts contracts: column 2 and columns 5 to 9, from one worker's week on one project.

Usage

wh347_compute_line(week)

Arguments

week

a worker week built by wh347_worker_week.

Details

Arithmetic is plain double precision with no intermediate rounding, in the same order of operations as the Go package; use wh347_round_cents for display only. The ST/OT split is entered by the user, not computed from a daily or weekly threshold.

The line is flagged "review" when the net pay is negative, the week exceeds 112 hours, the base rate is negative, or an entered column 7B is lower than column 7A minus 0.005.

Value

A named list:

worker_type

column 2, copied from the input: "J", "RA" or "" (not entered).

st_hours

column 5, straight-time hours for the week.

ot_hours

column 5, overtime hours for the week.

total_hours

column 5, total hours (ST + OT).

st_rate

column 6A, ST line: base rate, $/h.

ot_rate

column 6A, OT line: base rate x 1.5, $/h.

gross

wages ST x rate + OT x rate x 1.5 (excludes 6C).

fringe_credit

column 6B: total hours x total fringe $/h.

cash_in_lieu

column 6C: total hours x cash-in-lieu $/h.

gross_project

column 7A, gross earned on this project: wages + 6C.

gross_all_work

column 7B, gross earned for all work: entered value, else 7A.

gross_all_work_entered

TRUE when 7B was entered, FALSE when it defaulted to 7A.

total_deductions

column 8, total deductions for all work.

net_pay

column 9: 7B - 8. The 6B fringe credit is never included.

rate_plus_fringe

base rate + total fringe, $/h (utility value, not a form column).

sanity

"ok" or "review".

Source

Not an official DOL tool, not legal advice; you remain responsible for your certified payrolls. The package does not check wage determinations, fill the Statement of Compliance (page 2), or produce the form itself. DOL instructions for the WH-347: https://www.dol.gov/agencies/whd/forms/wh347. The same calculations are available as a hosted tool at https://tabletemplates.com/certified-payroll-software/.

See Also

wh347_compute_run, wh347_worker_week

Examples

week <- wh347_worker_week(
  base_rate = 30,
  fringe = wh347_fringe_rates(health_welfare = 4, pension = 2),
  st_by_day = c(8, 8, 8, 8, 8, 0, 0),
  ot_by_day = c(4, 0, 0, 0, 0, 0, 0),
  deductions = wh347_deductions(other = 310))
l <- wh347_compute_line(week)
l$total_hours                       # 44, column 5
l$ot_rate                           # 45, column 6A, OT line
wh347_round_cents(l$fringe_credit)  # 264, column 6B
wh347_round_cents(l$gross_project)  # 1380, column 7A
wh347_round_cents(l$net_pay)        # 1070, column 9
l$sanity                            # "ok"

Compute a WH-347 run: one project, one week

Description

Computes all lines of a run with wh347_compute_line, the crew totals paid to each fringe plan and the reconciliation check of column 6B.

Usage

wh347_compute_run(weeks)

Arguments

weeks

a list of worker weeks built by wh347_worker_week (NULL or an empty list for an empty crew).

Value

A named list:

lines

one line per input worker, in input order (see wh347_compute_line).

plan_totals

crew totals paid to each plan, a list built by wh347_fringe_rates: sum of total hours x plan rate.

plan_totals_sum

sum of the 4 plan totals.

fringe_column_sum

sum of column 6B over all lines.

reconciles

TRUE when the absolute difference between fringe_column_sum and plan_totals_sum is lower than 0.005.

See Also

wh347_compute_line

Examples

week <- wh347_worker_week(
  base_rate = 30,
  fringe = wh347_fringe_rates(health_welfare = 4, pension = 2),
  st_by_day = c(8, 8, 8, 8, 8, 0, 0),
  ot_by_day = c(4, 0, 0, 0, 0, 0, 0),
  deductions = wh347_deductions(other = 310))
r <- wh347_compute_run(list(week))
wh347_round_cents(r$plan_totals$health_welfare)  # 176
r$reconciles                                     # TRUE

Itemized weekly deductions (column 8)

Description

wh347_deductions holds the itemized weekly deductions in $ for all work (column 8). They are entered, never computed. wh347_deductions_total returns the column 8 total: the sum of the 4 itemized deductions.

Usage

wh347_deductions(fica = 0, federal_tax = 0, state_tax = 0, other = 0)
wh347_deductions_total(deductions)

Arguments

fica

FICA withholding.

federal_tax

federal income tax withholding.

state_tax

state income tax withholding.

other

other permissible deductions.

deductions

a list built by wh347_deductions.

Value

wh347_deductions: a named list with elements fica, federal_tax, state_tax and other. wh347_deductions_total: a number.

Examples

d <- wh347_deductions(fica = 61.2, federal_tax = 90, state_tax = 38.5, other = 10.3)
wh347_deductions_total(d)  # 200

Fringe benefit rates per plan

Description

wh347_fringe_rates holds the fringe benefit rates in $/hour, one per plan. wh347_fringe_total returns the total hourly fringe credit: the sum of the 4 plan rates.

Usage

wh347_fringe_rates(health_welfare = 0, pension = 0, vacation = 0, training = 0)
wh347_fringe_total(fringe)

Arguments

health_welfare

health and welfare plan, $/h.

pension

pension plan, $/h.

vacation

vacation / holiday plan, $/h.

training

training plan, $/h.

fringe

a list built by wh347_fringe_rates.

Value

wh347_fringe_rates: a named list with elements health_welfare, pension, vacation and training. wh347_fringe_total: a number.

Examples

f <- wh347_fringe_rates(health_welfare = 4, pension = 2)
wh347_fringe_total(f)  # 6

Round to the cent, halves toward +Inf

Description

Rounds to cents, halves toward +Inf: the same result as the Go function RoundCents and as JavaScript Math.round(n * 100) / 100. For display and snapshots only, never inside the calculation.

Usage

wh347_round_cents(x)

Arguments

x

a numeric vector.

Details

x * 100 is computed in double precision, floored, and increased by one when the remainder is at least 0.5. This differs from round(x, 2), which follows IEC 60559 and does not round halves toward +Inf.

Value

A numeric vector of the same length as x.

Examples

wh347_round_cents(c(1069.999999999, 0.005, -1.005, -0.125, 2.675))
# 1070.00 0.01 -1.00 -0.12 2.68

One worker's week on one project: the input of one WH-347 line

Description

Builds the input of wh347_compute_line: a named list with the base rate, the fringe rates per plan, the straight-time and overtime hours of the 7 days of the payroll week, the deductions, the cash paid in lieu of fringe benefits, the gross earned for all work (column 7B) and the worker type (column 2).

Usage

wh347_worker_week(base_rate = 0, fringe = wh347_fringe_rates(),
                  st_by_day = rep(0, 7), ot_by_day = rep(0, 7),
                  deductions = wh347_deductions(), cash_in_lieu_rate = 0,
                  gross_all_work = NULL, worker_type = "")

Arguments

base_rate

hourly base rate actually paid, $/h (column 6A, ST line).

fringe

hourly fringe credit per plan, built by wh347_fringe_rates (column 6B is derived from it).

st_by_day

straight-time hours per day, 7 days of the payroll week.

ot_by_day

overtime hours per day, 7 days of the payroll week. The ST/OT split is entered, not computed.

deductions

itemized deductions for all work (column 8), built by wh347_deductions.

cash_in_lieu_rate

cash paid in lieu of fringe benefits, $/h (column 6C). Zero means none.

gross_all_work

gross earned for all work, all projects (column 7B). NULL means 7B = 7A.

worker_type

column 2: "J" (journeyworker), "RA" (registered apprentice) or "" (not entered, printed blank, never defaulted to "J").

Value

A named list with the same elements as the arguments.

See Also

wh347_compute_line, wh347_fringe_rates, wh347_deductions

Examples

week <- wh347_worker_week(
  base_rate = 20,
  fringe = wh347_fringe_rates(health_welfare = 1, pension = 1,
                              vacation = 0.5, training = 0.25),
  st_by_day = c(8, 8, 8, 8, 8, 0, 0),
  gross_all_work = 1500,
  worker_type = "RA")
wh347_compute_line(week)$net_pay  # 1500