Case study · HVAC manufacturer’s representation

The 2016 server is gone, and one system carries a job from quote to commission.

Infrastructure modernization and a quote-to-commission CRM/ERP for an HVAC manufacturer’s rep.

MW Equipment · HVAC manufacturer’s rep, New York City, 20 staff

As an independent consultant (MikeG 3D LLC)

  • IT Systems
  • Custom Software

Free · 30 minutes · No pitch. Ask me about work like this.

  • 2016toGone the server that ran everything, retired
  • 1 system quote, order, POs, invoice and commission
  • No 2FAtoEntra ID Conditional Access and Intune on every device
  • 98% fulltoOff-site the data drive; now Synology to Backblaze B2

The short version

MW Equipment, a 20-staff HVAC manufacturer’s rep, relied on one 2016 server, on its original drives, for everything from sign-in to accounting. I replaced it with Microsoft 365 and a hardened edge, and built them one application from quote to commission. Quotes, orders, POs, invoices and commission reports now come off one set of records.

At a glance

What changed, line by line.

The client’s systems before and after the engagement
Before After
Server One 2016 host running AD, DHCP, DNS, file shares and accounting, on original drives in RAID 5 Switched off once nothing depended on it
Storage & backups A failed cache battery and a data drive 98% full Synology Active Backup, copied off-site to Backblaze B2
Edge The firewall’s management portal open to the internet Protectli running OPNsense with a Cloudflare allow-list; services behind Cloudflare Zero Trust
Identity On-prem Active Directory; no one on 2FA; old accounts active with passwords that never expired Entra ID, with Intune baselines and Conditional Access
Email & documents Google Workspace, paid for and under-used Microsoft 365 and SharePoint
Workstations Staff PCs on the on-prem domain 8 new PCs, enrolled in Intune, encrypted with BitLocker, local admin passwords by LAPS
Sales process No single system for quotes, orders, POs, invoices and commissions One application from quote to commission report, on records that agree: Django 5.2, PostgreSQL and HTMX

One server, and everything on it.

MW Equipment is an HVAC manufacturer’s rep firm in New York City. At the time of the migration it had 20 staff, and everything ran on one 2016 server: Active Directory, DHCP, DNS, file shares and the accounting software, on the original drives in RAID 5, with a failed cache battery and a data drive 98% full. One disk failure during a rebuild would have taken the office down for days.

The assessment found more. The firewall’s management portal was open to the internet. Google Workspace was paid for and under-used, with no one enrolled in two-factor authentication. Old accounts were still active with passwords that never expired, and the domain had no DMARC record.

The sales side needed the same attention. They bid HVAC packages into the New York City market, send the same quote to several competing contractors, and then carry the job they win through ordering, purchasing, invoicing and commission. All of that had to live in one system, on records that agree with each other. They had no in-house IT and wanted one person to take the whole thing on.

A new edge, Microsoft 365, and one application.

Google Workspace moved to Microsoft 365 and SharePoint. The on-prem Active Directory domain was retired in favor of Entra ID, and the staff moved onto eight new PCs. Once nothing depended on them, the 2016 host and the old firewall were switched off.

The new edge is a Protectli appliance running OPNsense with a Cloudflare allow-list. Published services sit behind Nginx Proxy Manager and Cloudflare Zero Trust, remote access runs over WireGuard, and MeshCentral is deployed to every endpoint through Intune. Intune baselines and Conditional Access govern the devices; BitLocker and LAPS cover disk encryption and local administrator passwords. A Synology NAS handles on-site storage with Active Backup and copies to a Backblaze B2 bucket off-site.

The sales side runs on a quote-to-commission application I built for them. It is Django 5.2 and PostgreSQL, server-rendered with HTMX, with WeasyPrint for the report PDFs, and it ships as a single-tenant Docker deployment.

The application follows the way they actually bid. A quote holds one row per manufacturer: equipment cost, shipping, startup and a bid markup percent. The bid value adds itself up as you type. Each quote also tracks the contractors bidding on that job, and one button converts the won quote into an order.

An order carries the contractor POs whose sum is its total sale, and the purchase orders the firm sends to manufacturers. Below those sit the cost add-ons and the firm’s own invoices, each with its paid amount and balance. Payments are allocated against them.

The money panel derives the rest. Deductions, gross profit and margin come off those records. So does the commission pool, split between the contractor and engineer sales reps by percentage, and then net profit. That math lives in exactly one place in the code.

Roles decide what each person may change, and a sales rep sees their own book. Every record keeps a change history written in words. Records link out to their SharePoint folder and to the same folder on the staff machine. There is a global search, and eight reports that export to CSV and PDF.

Diagram · The edge and backups after

Internet

  • Cloudflare Zero Trust

In front of every published service

Protectli · OPNsense

  • Cloudflare allow-list at the edge
  • Nginx Proxy Manager for published services

Replaced a firewall whose portal was open to the internet

Office

  • 8 PCs Intune, BitLocker, LAPS
  • Synology NAS Active Backup

Also The NAS copies off-site to a Backblaze B2 bucket. Remote access runs over WireGuard; MeshCentral reaches every endpoint through Intune.

The edge and backups as built. The 2016 host and the old firewall were switched off once nothing depended on them.

Order · J-number

Order screen: job name and address, contractor and engineer with their sales reps and percentage splits, contractor purchase-order rows, and a money panel listing total sale, deductions, gross profit, margin, commission pool, each rep’s share and net profit.
Screenshot · The order screen An order: job and parties, the contractor and engineer split, and the money panel · test data Open full size

Quote · Manufacturer rows

Two of a quote’s manufacturer rows, each with a bid markup percent and a row total, above the total of every row on the quote.
Screenshot · A quote’s manufacturer rows Two of the quote’s manufacturer rows, over the total of every row · test data Open full size

Quotes · Filterable list

Quotes list with a filter bar and a table of quote number, date, job, address, engineer, job type, system, grade, who quoted it, sales reps and a status badge.
Screenshot · The quotes list Every quote, filterable by status, rep, engineer, job type and bidder · test data Open full size

The result: a locked-down edge, and one set of numbers.

MW Equipment runs on one identity platform and one document platform, with the 2016 host retired and no management ports open to the internet. Every one of the eight workstations is enrolled in Intune, encrypted and configured by policy, so a replacement is set up the same way as the rest.

Commission questions are answered from the commission report. The same records produce the quote, the purchase orders, the invoice and the commission report, so the numbers agree by construction.

Keep reading

Next case study

All 3 case studies

Case study 02 / 03

Re-keyedto20+ flows carrying customers, quotes, orders, stock and prices

Security camera distributor · 180 users · 11 locations

IT director · In-house

Three systems, one set of data.

  • Automation & Data
  • IT Systems
Before
Acumatica, Salesforce and WooCommerce each kept their own customers, products, prices and stock.
After
One set of data. Customers, quotes, orders, stock by warehouse and prices move between all three.

Next step

Talk to the engineer who will do the work.

One call, thirty minutes, no pitch deck. I listen first, then I tell you what I would do about it.

Rather write it down? [email protected]

Mon–Fri 9am–5pm ET · Islip, NY