Matt O'Neil

Commercial and operational finance

Finding the profit in operational data.

I work where operations meet the P&L, in pricing and cost to serve. I start with the activity behind the numbers, what was sold, delivered and worked, find where margin is leaking, and build the models and reporting that fix it.

Looking for a full-time role, and open to select project work. Based in Golden, Colorado.

Revenue side

Price, terms and what gets billed

Client and product profitability, rate cards, contract terms, and the charges that go unbilled.

Cost side

Cost to serve and where the hours go

Labor and asset use, cost by customer and service line, and the operating drivers behind the budget.

Four projects from two past roles

The first three are from a warehousing and fulfillment company with about $50M in revenue and 300 employees. The fourth is from a much larger IT services company. Exhibits use illustrative figures, and the dashboards are recreations: the layouts follow what I built, and every client name and number in them is invented.

$2.5M

Modeled incremental annual gross profit from the new rate structures. Every account signed the new terms.

Finance manager, reporting to the CFO, on a five-person finance team.

Rebuilding client rates from two years of order history

The problem
Client contracts had been written one at a time over years. The terms were all over the place. Some of them capped what a single order could be charged, and those caps were where the losses were.
What I did
Built client-level profitability from two years of shipment history at order and SKU grain, and turned it into a Tableau rate card model with a control for each fee and a minimum order charge in place of the old maximums. On renegotiation calls I ran it live, so each client saw what a change did to their own order history.
Getting sales on board
The sales team pushed back at first. I put the live model in front of them and we agreed a price floor for each client before its renegotiation call, so sales went in knowing exactly where they could and could not move.

Monthly billing for sample clients, current terms against the new rate card

New card terms: order fee $2.75, SKU fee $0.60, each fee $0.20, minimum order $4.00

Illustrative figures for a sample of clients; the original model covered every client. The recreation shows 18 months, the original used two years.
See the model

Click any page to see it full size.

All sample clients by month. The four fees and the minimum order are controls that recalculate the whole table.

One client, the view used on a renegotiation call.

Order detail. Every order priced twice, under the old terms and under the new card, with the minimum order top-up where it applies.

$600K

Annual revenue added as billable hours rose to 80 percent of total hours

Same role. Built in Smartsheet and Power BI, which the company already licensed.

Finding the billable work that was being done for free

The problem
Warehouse and sales staff were doing work the rate card allowed us to bill, and much of it never reached an invoice. Nobody could see how anyone's hours were spent, and a turnaround budget ruled out buying time tracking software.
What I did
Worked with operations and sales to define every task category and which ones were billable. Built two trackers in Smartsheet, one for the warehouse team and one for sales, with one line per task and a manager approval step, so only reviewed time reached the reports. A tracker filled Smartsheet's row limit about once a month, so I archived it, started a new one and extended the Power Query feed, keeping one live Power BI model over the full history.
The result
Billable work that sales had been doing for free started reaching invoices, and idle time became visible by team. The same tracking was later used to cost the warehouse reconciliation below.

Every task mapped to whether it bills, and how

  1. Log each taskOne line per task in the warehouse or sales tracker, several a day per person
  2. ApproveEach line is reviewed, and anything not approved is kept out of the reports
  3. ReportPower BI reads every current and archived tracker for ops, sales and the CFO
TaskTeamBillableHow it bills
Kitting and assemblyWarehouseYesHourly project labor
Client-requested inventory countWarehouseYesHourly labor
Special labeling or reworkWarehouseYesHourly project labor
Client inventory or report requestSalesYesHourly account services
Order changes after releaseSalesYesPer-request fee
Warehouse reconciliationWarehouseNoInternal project
Prospect callsSalesNoOverhead
Training and adminBothNoOverhead
IdleWarehouseNoTracked for capacity
Illustrative rows. The real map covered every task the two teams logged, agreed with operations and sales before the trackers went live.
See the dashboard and the tracker

Click any page to see it full size.

The Power BI dashboard used by operations, sales and the CFO. Checkbox filters for date, employee, customer, project, task and billable status, hours by category, billable against non-billable by team, and the raw entries underneath.

The warehouse tracker in Smartsheet, one line per task. Lines without a check are waiting on review, and anything not approved was kept out of the reports. Once a sheet reached Smartsheet's row limit it was archived and a new one started.

$720K

A year in new storage billing and freed warehouse space, combined

Same role. Run with operations and sales, neither of which reported to me.

Reconciling the warehouse to the billing system

The problem
Storage was billed off what the warehouse management system said was in each pallet location, and the system and the floor had drifted apart. Some goods sat unbilled long after their campaigns ended.
What I did
Joined the physical audit to the system export by location, sorted every location across 12 system statuses, and fed it into a live Power BI report. I ran twice-weekly working sessions with operations and sales off that report. Sales asked each client to either remove the goods or start paying storage on them.
The result
Every location ended in one of three states that matched in both places. Goods that stayed went on invoice, and purged goods freed warehouse space.

Pallet locations by status, before and after

Illustrative figures. 12 system statuses collapsed to three states that tie between the system and the floor.
See the full dashboard

Click any page to see it full size.

A snapshot from partway through the project, about two thirds done. Locations already worked tie one to one with the floor. The ones still showing mismatch statuses are all in the batch not yet worked. By the end, every location had resolved to the three states.

Daily pace, rolling average and the projected finish date, as of the same snapshot.

Locations in process by step and owner, with anything over two days in a step called out for the twice-weekly session.

Built the budget process from scratch

Reporting to the CFO, at an IT services company of several hundred million in revenue.

Planning revenue from what drives it

The problem
The annual revenue budget needed to tie to the people who would deliver it: about 30 sales reps across seven offices, with very different track records. The subscription cloud business needed a forecast of its own.
What I did
Stack-ranked the reps into productivity bands, attached expected annual production to each band, and built the revenue budget from that model. For the subscription cloud business, I built the forecast from counts of its three main products with growth and churn rates, and based new sales on the same rep bands and counts. Alongside it I built the sales and pipeline reporting, so actuals could be read against the same bands through the year, and an engineer utilization report of hours worked against hours billed.
The result
A revenue budget built bottom up from each rep's band, which leadership could trace to people and offices and track against as the year ran.

Revenue budget, built from its drivers

Revenue budgetBuilt from rep bands and product counts
Sales rep production30 reps stack-ranked into four bands
  • Band A5 reps × $1.60M$8.0M
  • Band B9 reps × $1.10M$9.9M
  • Band C10 reps × $0.75M$7.5M
  • Band D6 reps × $0.40M$2.4M
  • Total30 reps$27.8M
Subscription cloud forecastIts own forecast, by product
  • Installed base: counts of the three main products
  • Growth and churn rates applied to each product
  • New sales from the same rep bands and counts
Illustrative figures, scaled down. Band production is expected annual revenue per rep. The subscription branch shows the drivers only.

How I work

I start with the transactions and activity behind the numbers, because they say more than the general ledger does, and I build profitability from the lowest grain available so every figure traces back to what happened. I automate the recurring reporting so it refreshes on its own and my time goes to analysis. The fix usually lands in how sales quotes or how operations bills, so I put the live model in front of the people who own that decision and keep working it with them until the change is in place.

Three fictional companies, worked the same way

Each one shows the margin problem, the data gap that hides its cause, how I'd fix the data, and what I'd change once the cause is visible. Every name and number is invented.

Show the three examplesHide the examples

Halvorsen Records Group (fictional)

Halvorsen stores paper records for law firms, hospitals and banks. It charges by the box each month, plus a fee each time a box is pulled, delivered or destroyed, and it has grown by buying three smaller competitors.

The margin problem
Revenue grew with each of three acquisitions, but gross margin fell from 41 to 36 percent over three years. The CFO suspects some customers cost more to serve than they pay, but can't say which ones.
Why the data hides it
Halvorsen and the three companies it bought each still bill from their own system. The same service, a box pulled and delivered, is billed under four names at four prices. With no common list of services, nobody can compare what customers pay across the four systems, and no system records what it costs to store and pull a customer's boxes.
How I'd fix the data
I'd map every billing code from the four systems to one list of standard services and match each customer to a single record. Then I'd add what each customer costs to serve, from boxes stored and how often they ask for them, so revenue and cost sit on the same line for every customer.
How I'd fix the margin
With customers ranked from most to least profitable, the last 205 lose $1.4M between them. Most came with the acquisitions, are still on their old, low rates, and pull boxes often. I'd move those 205 to one standard rate card with a monthly minimum first, phased in so no bill rises too far in a single year. Everyone else moves to the card at renewal, and new accounts are priced from it on day one.

One service, four names, four prices

Billing systemCode on the invoicePrice
HalvorsenRTRV-STD$4.00
Valley DocumentPull Request$2.75
Pinecrest RecordsRetrieval$3.50
Summit ArchivePR-1$5.25

All four become one standard service: Retrieval and delivery

The same retrieval as billed by each of the four systems.

Cumulative gross profit by customer, most to least profitable

The curve peaks where customers stop adding profit and start losing it. The last 205 customers lose $1.4M between them.

Ridgeline Mechanical (fictional)

Ridgeline services heating and cooling systems in commercial buildings. Most of its money comes from technicians' time, billed on repair calls or covered by annual maintenance agreements, and it has grown by buying local service companies.

The margin problem
Service revenue grew, but service gross margin fell from 34 to 29 percent in two years. Overtime keeps climbing, and branch managers say their technicians are fully booked and want to hire.
Why the data hides it
Hours live on timecards and jobs live on work orders, and at the acquired companies the two don't connect. Much of the time is charged to a catch-all code called Shop General, or to jobs that were already closed. So no one can say how many paid hours turned into billed work.
How I'd fix the data
I'd match timecards to work orders by technician, date and site, and use dispatch times to separate driving from time on site, with set rules for any hour that still doesn't match. Every paid hour then lands in one bucket: billed repair or agreement work, PTO and holidays, drive time, shop and training, warranty and callbacks, or worked and never billed.
How I'd fix the margin
The bridge chart shows where the unbilled time goes. Drive time is the largest gap at 59,000 hours, so I'd route technicians by zone instead of across the whole territory. The 10,344 hours worked and never billed, about $1.54M, would go on a weekly review so each one gets billed or explained. Only 60 percent of paid hours end up as billed work today, so Ridgeline should bill more of the hours it already pays for before it hires anyone.

Why billable hours could not be counted

TechDateHoursCharged toBillable?
M. OrtizMar 46.5WO 18823Yes
M. OrtizMar 41.5Shop GeneralNo: catch-all
D. KimMar 48.0WO 18790No: closed job
D. KimMar 54.0WO 18901Yes
J. PriceMar 57.0Shop GeneralNo: catch-all
Sample timecard lines. Only some tie to a job that can be billed.

From paid hours to billed hours

Each step is paid time that was not billed. The 10,344 hours worked and never billed come to about $1.54M at a $149 hourly rate.

Basin Equipment Rentals (fictional)

Basin rents scissor lifts, boom lifts and other construction equipment to contractors from eight branches. Every machine has a list price per day, and branch managers can discount it to win a job.

The margin problem
Revenue is flat and rental margin has fallen four points in two years. Leadership thinks branches discount too much, but nobody can say how much or where.
Why the data hides it
The billing system keeps one amount per rental, and branches type the delivery fee and any damage charge into that same amount by hand. A five-day scissor lift rental billed at $620 against a $650 list looks like 95 percent of list. Take out the fees and the rental itself went for 74 percent.
How I'd fix the data
I'd split every rental's amount into rental, delivery and damage, using the delivery schedule and damage records. Then each branch's true rental rate can be compared with list by type of equipment, next to how often that equipment is out on rent.
How I'd fix the margin
Four of the eight branches rent below 85 percent of list, and Las Vegas is lowest at 73. Most of that discounting is on machines that are out on rent nearly every day, where a lower price wins no extra work. I'd set a floor at 85 percent of list on equipment that is usually out, with a regional manager approving anything lower, and leave branches room to discount machines that would otherwise sit in the yard. Fees go on their own lines from now on.

What one rental really went out at

One five-day rental of a scissor lift. The billed amount looks close to list until the fees are pulled out.

Realized rate as a share of list, by branch

Rental rate with delivery and damage taken out, as a share of list. The dashed line is a discount floor at 85 percent of list.

Open to a full-time role, and select projects

A full-time role

Commercial finance, operational finance, FP&A or pricing, where finding the margin is part of the job and finance works close to operations. Denver area or remote.

Select projects

Profitability, pricing, billing leakage and operational reporting for CFOs and operating partners who need one of these solved now. I quote a fixed fee after a first call. The model and reports stay with you.

Get in touch

LinkedIn  /  Resume on request  /  Golden, Colorado