# See which roofing jobs actually made money in JobNimbus

> Open one screen every Friday to see contract value, cash collected, material and labor cost, and gross margin on every recent roofing job.

- Workflow type: app
- Services: JobNimbus, Google Sheets
- Categories: Finance, Operations
- Published: 2026-08-24

## What it does

- Lists every job from the last 90 days in one sortable table, with contract value, cash collected, material spend, labor cost and gross margin side by side
- Turns margin red the moment a job falls below the target you set, so the worst jobs surface before you forget the details
- Prices labor from a crew and subcontractor rate sheet you keep in Google Sheets, so the labor number reflects what you actually pay
- Opens a full job detail view with the estimate line items, every material order and work order, and the complete payment history
- Gives every job an Investigate margin button that sends a background agent to find where the money leaked, write the findings back into the app, post a note on the job, and open a follow up task when work was done but never billed

## What you'll need

- A JobNimbus account with permission to read jobs, estimates, invoices, payments, material orders and work orders, and to add notes and tasks
- A Google Sheets rate sheet listing your crews and subcontractors with what each one costs per hour or per square
- A target gross margin you want jobs measured against, and the job statuses you consider finished

## Prompt

Build me an app that my owner and office manager open every Friday to see whether each roofing job actually made money. JobNimbus has no job costing built in, so the app has to assemble it from the records that are already there.

The main surface is a sortable job profitability table covering a lookback window that defaults to the last 90 days. One row per job, pulled with JobNimbus List Jobs. Columns: job name and number, customer, current status, contract value, cash collected, material spend, labor cost, gross profit in dollars, and gross margin percentage. Every column sorts, and the default sort puts the worst margin at the top. The margin cell turns red when it falls below a target margin the user sets in the app. Above the table put a summary strip: jobs scored, total contract value, total cash collected, blended gross margin, and how many jobs came in under target.

Joining the data is the core of this app. Every JobNimbus record carries a jnid, and the records attached to a job are found with the filter DSL clause {"must":[{"term":{"related.id":"<job jnid>"}}]}. The handlers use that clause to scope List Estimates, List Invoices, List Payments, List Material Orders and List Work Orders to each job. Contract value comes from the job's estimates via List Estimates and its invoices via List Invoices: show the estimate total and the invoiced total as separate figures so the office manager can see when the invoice never caught up with the estimate. Cash collected comes from List Payments. Material spend is the sum of the job's material orders from List Material Orders.

Labor is derived, not stored. Read the job's work orders with List Work Orders and price them against a crew and subcontractor rate sheet I keep in Google Sheets, read with Get Values. The rate sheet has one row per crew or subcontractor with the rate and whether it is hourly or per square. Store the spreadsheet id and range in app settings so I can point it at a different tab later. If a work order references a crew that is not on the rate sheet, flag that row as missing a rate rather than silently treating the labor as zero, and exclude it from the summary blend.

Jobs still in production are shown as provisional rather than scored. Let the user pick which job statuses count as finished; anything outside that set gets a provisional badge, a greyed out margin, and is excluded from the summary totals. A job that is half installed and half invoiced should never be presented as a real margin number.

Settings the user controls in the app: the target margin percentage (default it to 35 percent, since roofing labor typically runs 30 to 40 percent of the ticket leaving 20 to 30 percent for overhead and profit), the lookback window in days (default 90), which statuses count as finished, and the rate sheet location. These are shared app settings, not per user, because the owner and the office manager need to be looking at the same numbers.

Clicking a row opens a job detail page. The header repeats the margin math for that job. Below it: the estimate line items, fetched per estimate with Retrieve an Estimate so I can see quantities and prices rather than just a total; every material order on the job with vendor, date and total; every work order with the crew and the priced labor the app calculated; every invoice with its amount and status; and the full payment history with dates and amounts. Include a billed versus collected line so an unpaid balance is obvious at a glance.

Each job also gets an Investigate margin button, on the table row and on the detail page, that kicks off a background agent for that one job. The agent reads the job with Retrieve a Job, then walks its estimates, material orders, work orders, invoices and payments using the same related.id filter, pulling individual estimates with Retrieve an Estimate for line item detail. Its job is to work out where the money leaked. Have it look for the patterns that actually cause this in roofing: an extra material order placed after the estimate that was never billed, a change order that never made it onto an invoice, a second crew trip on the work orders that was never priced into the contract, and payments collected below the invoiced total.

The agent writes its findings back into the app so the owner can read them on the job detail page: a list of findings, each with a dollar impact and the specific records it used as evidence. It posts the same summary onto the job in JobNimbus as a note using Create an Activity. And whenever it finds work that was done but never invoiced, it opens a follow up task with Create a Task, assigned to the office manager with a due date a few days out, naming the amount and exactly what needs to be billed.

Show the agent's state inline on the row and the detail page: idle, running, or last investigated at a given time. Keep previous findings so I can see what an investigation said last month, and do not post a duplicate note on the job if I run the investigation twice on the same day.

## How to customize

- Set the target margin that decides when a job turns red, and the lookback window the table covers
- Choose which JobNimbus job statuses count as finished, so jobs still in production stay provisional instead of being scored
- Point the app at a different rate sheet tab, or add crews and rates to the sheet as your subs change

## FAQ

### Does JobNimbus do job costing on its own?

Not really, which is why most roofing companies end up rebuilding it in a spreadsheet every week. Your jobs, estimates, invoices, payments, material orders and work orders all live in JobNimbus already, but nothing puts them in one row and tells you the margin. This app does that assembly for you.

### What if I do not have a rate sheet yet?

You only need a simple spreadsheet: one row per crew or subcontractor, what they cost, and whether that cost is hourly or per square. The app reads that sheet to price the work orders on each job. If a crew is missing from the sheet, the app flags the row instead of quietly showing zero labor.

### How does it handle jobs that are still in progress?

They show up as provisional. The numbers are still there so you can watch a job as it runs, but the margin is greyed out and left out of your totals, because a job that is half installed and half invoiced will always look wrong. Only jobs in the statuses you mark as finished get scored.

### Does it change anything in JobNimbus?

The table and the job detail view are read only. The only writes happen when you press Investigate margin on a job: the agent adds a note to that job with what it found, and creates a follow up task when it spots work that was done but never invoiced.

### What does the Investigate margin button actually do?

It sends a background agent through that one job: the estimates, the material orders, the work orders, the invoices and the payments. It looks for the usual leaks, like an extra material order that never made it onto an invoice, a change order missing from the final bill, or a second crew trip nobody priced. It writes what it found back into the app so you can read it, and puts the same summary on the job in JobNimbus.

Use this prompt in General Input: https://www.generalinput.com/prompts/see-which-roofing-jobs-actually-made-money-in-jobnimbus