Your Accountant Isn't Catching Your Margin Bleed
Your Accountant Isn't Catching Your Margin Bleed
In 2019, I was sitting in a conference room in Tysons Corner with a 14-truck residential HVAC shop's financials open on my laptop. The tab I remember is the job-level detail we'd pulled from his QuickBooks — not the summary P&L, the actual install records. His CPA had produced clean statements for three years running. Organized. Consistent. His gross margin was sitting at 38%, which is where I want to see a residential shop.
The business had been losing money on every install job for three years. The owner did not know this.
The Accountant Did Her Job. That's the Problem.
Your CPA was hired to produce an accurate tax return and, if you're paying for it, financial statements that comply with generally accepted accounting principles. The categorization decisions she makes are made with the IRS in mind. Not with your install margin in mind.
Those are different objectives. Tax accounting asks what is taxable income and when does it occur. Management accounting asks which jobs made money and by how much. Answering the first question correctly doesn't touch the second one.
That's not a criticism of your CPA. It's a structural mismatch. The accountant on that 14-truck shop wasn't negligent — she reported what she was given. The cost information flowing to her had been organized for tax purposes, and nobody had ever built a parallel structure for operational visibility. The gross margin on the income statement was real. It was also useless as a diagnostic tool.
Where the Miscategorization Actually Happens
Labor is the most common and most expensive mistake. In every shop I reviewed at Atlantic Comfort Partners, technician wages ran as a single labor bucket — billable install hours mixed in with drive time, callback hours, and warranty work. When you blend those together, gross margin on installs looks better than it is. The unbillable hours aren't assigned to a job; they're just labor expense sitting below the line. The install margin looks fine. The callbacks and drive time are invisible, absorbing hours nobody is pricing for.
Materials have a timing problem. When materials are expensed at purchase rather than when they're consumed on a specific job, the P&L compresses in Q2 and inflates in Q3 with no corresponding change in job-level performance. A shop that loaded up on refrigerant and coils in April looks like it had a rough spring and a strong summer. The accountant sees purchase timing. You need to see job consumption.
Subcontractors get treated as overhead in roughly half the shops I've reviewed. The electrician you call for every panel upgrade, the sheet metal shop doing your custom fab — those costs belong in cost of goods sold, matched to the specific jobs they touched. When they park in operating expenses, your gross margin is inflated by exactly what you paid those subs. That's not a rounding error.
Equipment depreciation often lands above the gross margin line in a way that makes COGS look lower than it should. Recovery machines, vacuum pumps, installation equipment — these are job costs. If they're depreciated into SG&A rather than allocated to COGS, gross margin improves on paper while the actual cost of doing installs doesn't change.
What Your Gross Margin Number Is Actually Telling You
Most shop owners treat gross margin as the diagnostic number — the one you bring to the bank, the one you use to decide whether to hire the next tech. A gross margin figure built on miscategorized COGS is not telling you what you think it is.
The industry benchmarks you're comparing against have the same construction flaw baked in. Comparing your miscategorized gross margin to a benchmark average of miscategorized gross margins is not analysis. It's pattern-matching against noise.
The benchmarks are aggregated from shops that categorize costs differently. Some pull depreciation above the gross margin line, some below. Subcontractor handling varies by accountant. The average of all that inconsistency is not a target. It's a number that sounds authoritative.
This is also where my frustration with flat-rate pricing books lands. The books produce predictable revenue per ticket. They don't produce predictable margin per ticket, because the cost side isn't job-costed. The book says $6,200 for a 3-ton split system. Whether that job made money depends on actual hours logged, actual materials consumed, whether the sub invoice showed up on day one or day four, and whether there was a callback. The book doesn't know any of that. Your pricing model is operating on the revenue side of the equation with no feedback from the cost side.
What you actually need is contribution margin — the margin that strips out only the costs that moved with that specific job. Direct labor on that job. Materials pulled for that job. The sub invoice for that job. Equipment at actual acquisition cost allocated to that job. Most shops have never seen this number because their P&L isn't structured to produce it.
The Number Your Accountant Will Never Show You
Job-costing is the structural fix. Not a software decision — the discipline of closing a cost envelope on every job before calling it done.
I watched this operate at Bayview Mechanical in Sunnyvale before I had the vocabulary for it. The senior techs kept their own time logs. Nobody required it. They kept them because they knew when a job had run long and they wanted the record when the next similar job came up for bid. The habit came first. The system didn't exist yet.
Shops that buy job-costing software before that habit exists — and I've watched this happen with ServiceTitan implementations more than once — get an expensive way to record incomplete data.
A useful job cost envelope needs five things:
- Actual labor hours by tech, from timesheets or dispatch logs, not from the original quote
- Materials pulled from inventory or purchased on the truck, at actual acquisition cost, matched to the job
- The subcontractor invoice matched to the job ticket number
- Equipment cost at actual acquisition price
- Warranty callback hours logged against the original job number, not opened as a new call
The two most commonly missed are callback hours and materials at actual cost. Shops almost universally log callbacks as separate service calls, which flatters install margin and inflates service department volume simultaneously. Materials get estimated or priced at list. The variance between estimated and actual materials cost is where a lot of the margin story hides.
What the Owner's Labor Is Doing to Your Numbers
If you're a working owner pulling tools on jobs and you're not charging your labor to those jobs at a market rate, your gross margin is inflated by the gap between what a journeyman would cost and what you're actually entering on the job cost sheet — which is usually nothing.
In the audits I've done on shops under 25 trucks, I see this constantly. An owner reports net margins in the high teens or low twenties. Once I charge their labor to COGS at journeyman-equivalent rate — what they'd pay a tech to do the work they personally do — those margins drop hard. The business hasn't changed. The cost structure became honest.
The tax version of this is that your CPA sets your W-2 at a defensible "reasonable compensation" level for S-corp purposes. That's a sound tax strategy. It's a terrible basis for pricing. The gap between your tax W-2 and your actual market labor rate is a fiction distributed across every job you touched this year. It's in your gross margin.
Run two figures. Tax return uses the IRS-reasonable W-2. Your internal management P&L charges your labor to COGS at market rate. The gap between those two versions is what you're actually subsidizing. When you hire the lead tech who replaces you on jobs — and if the business grows, that day comes — the subsidy ends and the cash requirement doesn't.
Price for it now.
What You Do Monday Morning
First: Pull the last ten closed install jobs. Reconstruct actual labor hours from tech timesheets or GPS dispatch logs, not from the original quotes. Match actual materials cost from supplier invoices against what the estimate assumed. If the number is more than 8 points different from estimated cost — in either direction — your pricing model has a structural problem. The variance tells you more than the average.
Second: Build a one-page job cost sheet covering the five data points above. Paper. Run it manually on every job for 30 days before you make any software decision. The shops that buy job-costing software before they have the manual habit get a faster way to record incomplete information.
Third: Once you have 30 days of real job cost data, look at your days sales outstanding alongside it. DSO usually reads as a cash problem. What job costing surfaces is that slow-paying jobs are also a margin problem — the carrying cost of those receivables doesn't appear in the job's cost envelope. That changes how you write payment terms on the next proposal. It changes which customers you're willing to work for.
Your accountant isn't going to hand you this. She wasn't built to. Build it yourself, starting with the last ten jobs.
FAQ
My accountant reviews my P&L every quarter and has never flagged a margin problem. Does that mean I don't have one?
A CPA reviewing a P&L for a small contractor is looking for accuracy against the chart of accounts, tax exposure, and consistency with prior periods. She is not auditing whether your install labor is separated from your callback labor, or whether subcontractor costs are matched to specific jobs. If the numbers foot and the categories are consistent, the P&L is clean — even if the underlying job economics are broken. Clean books and accurate job economics are different things. You can have one without the other.
What's the difference between job costing and just tracking my costs more carefully?
Tracking costs more carefully means entering supplier invoices on time, reconciling the card, keeping receipts. Useful. Not the same thing. Job costing means closing a cost envelope on each individual job: this job consumed 6.2 hours of labor, $847 in materials, a $320 sub invoice. The discipline is job-level specificity, not general accuracy. A shop can have perfectly accurate books and no idea which jobs made money. Job costing tells you which jobs to bid again and which to reprice.
If I start charging my own labor to jobs at market rate, my net income drops on paper. Is that actually useful?
It's useful because it's accurate. The version of net income that doesn't charge your labor at market rate is telling you the business is profitable partly because you're subsidizing it with discounted wages. That's a legitimate tradeoff for an owner-operator to make deliberately. What isn't legitimate is pricing jobs as though that subsidy is permanent. If you want to sell the business — and the acquirer's offer is going to be based on earnings with your labor charged at market, I've watched that math get run in deal rooms — better to see what that does to your margin now, while you can reprice.
Should I get job-costing software, or can I do this in a spreadsheet?
Spreadsheet first, for at least 30 days. Not because the software is bad — some of it is genuinely good — but because the habit has to precede the system. A spreadsheet forces you to understand what you're capturing and why. Once you're closing cost envelopes consistently on every job and you know what the five data points are and where they actually come from, then evaluate software. You'll know what you need it to do, which is a better position than signing up during a demo.
How do I handle jobs where labor spans multiple days or multiple techs?
Each tech logs hours to the job number each day. The cost sheet stays open until the job is complete and all hours are in. For multi-tech jobs, the labor line is the sum of all hours at each tech's loaded cost — base wage plus burden. Burden on a fully loaded HVAC tech in most mid-Atlantic markets runs somewhere in the range of employer payroll taxes plus workers' comp plus benefits; check your state comp schedule and your actual benefits cost, don't use a national average. Most shops run labor estimates at base wage only. That understates true cost, and it does so on every single job, which means the error compounds into the gross margin figure you're making decisions from.
What if my supplier invoices don't arrive until after I've closed the job in my system?
This is why most shops undercount materials cost per job. Use a two-step close: mark the job complete when the work is done, but hold the cost envelope open until the materials invoices are matched and entered. Five to seven business days is usually enough. If you close the envelope before invoices arrive, every job looks cheaper than it was, systematically, and your apparent margin on installs is inflated by the same amount every time. Holding that envelope open for a week is the difference between pricing on real numbers and pricing on a guess.
Enjoyed this article?
Get articles like this in your inbox every Monday. Free, no spam.
