wh347 (R)

Calculations for 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), the package computes columns 5 to 9 of the form, per-plan fringe totals for the crew, and a reconciliation check of column 6B. It has no dependencies and no I/O.

R port of the Go package codeberg.org/tresor2k/tabletemplates-go/wh347 and the Rust crate wh347; the tests replay every case of the Go tests with the same expected values.

Install

install.packages("wh347", repos = c("https://tresor4k.r-universe.dev", "https://cloud.r-project.org"))

Example

library(wh347)

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))

line <- wh347_compute_line(week)
line$total_hours                       # 44    column 5
line$ot_rate                           # 45    column 6A, OT line
wh347_round_cents(line$fringe_credit)  # 264   column 6B
wh347_round_cents(line$gross_project)  # 1380  column 7A
wh347_round_cents(line$net_pay)        # 1070  column 9
line$sanity                            # "ok"

run <- wh347_compute_run(list(week))
wh347_round_cents(run$plan_totals$health_welfare)  # 176
run$reconciles                                     # TRUE

Columns of the revised form

Column Content In this package
1A to 1E Worker entry number, name, identifying number not handled (identity)
2 "J" journeyworker or "RA" registered apprentice worker_type of wh347_worker_week(), copied to the line
3 Labor classification not handled
4 Hours worked each day, ST and OT lines st_by_day, ot_by_day
5 Total hours for the week st_hours, ot_hours, total_hours
6A Hourly rate paid, ST and OT lines (excluding cash in lieu of fringe) st_rate, ot_rate = base rate x 1.5
6B Total fringe benefit credit fringe_credit = total hours x total hourly fringe credit
6C Payment in lieu of fringe benefits cash_in_lieu = total hours x cash_in_lieu_rate
7A Gross amount earned, this project gross_project = ST x rate + OT x rate x 1.5 + 6C
7B Gross amount earned, all work gross_all_work = entered value (gross_all_work not NULL), else 7A
8 Deductions for all work total_deductions = sum of the itemized deductions
9 Net payment for all work net_pay = 7B - 8 (the 6B fringe credit is never included)

sanity is "review" when the net pay is negative, the week exceeds 112 hours, the base rate is negative, or an entered 7B is lower than 7A.

Arithmetic is plain double precision with no intermediate rounding, in the same order of operations as the Go package. wh347_round_cents() rounds to the cent (halves toward +Inf, like the Go RoundCents; not round()) and is meant for display only. The ST/OT split is entered by the user, not computed from a daily or weekly threshold.

Hosted tool and guide

Scope and disclaimer

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.

License

MIT, see LICENSE.md.