VG Reference Document

Cost Code & Work Order System

How VG categorizes every dollar spent on a project — QB band, phase, decimal suffix conventions.

Source: reference/cost-codes/cost-code-system.md Generated: 2026-06-08

VG Cost Code, Segment & Work Order System

Overview

VG's business-wide system has THREE layers:

Layer What it is Lives at Used by
Cost Code Atomic line-item category (e.g., 52.1 Framing Materials) Cost Code Unified.csv QB Products/Services
Segment Accounting category (e.g., 52 Framing) segments.yaml + cost-code-overrides.yaml budgets; estimates; actualsboard matrix
Work Order Operational packet a PM issues to a contractor (e.g., P1WO6 Framing) work-orders.yaml QB sub-customers (Customer:Project); PM scheduling; contractor docs

Flow: Cost Code → (exactly one) Segment. Work Order is a separate operational packet that a PM issues to a contractor; vendors post expenses to a WO sub-customer in QB. The WO-to-Segment relationship is 1:1, but cost codes are shared across WOs within the same Segment (e.g., 71.1 Tile Materials appears on both the Backsplash WO and the Tile Installation WO).

Phase (P0/P1/P2/P3/P4) is a Work Order scheduling concept only. It does NOT affect Segment categorization.

Segments

39 total: 32 construction + 7 non-construction.

Construction (32): 16 Project Prep, 18 Site Management, 20 Site Systems, 32 Demolition, 42 Foundation, 44 Site Work, 52 Framing, 53 Roofing, 54 Windows & Exterior Doors & Garage, 56 Interior Stairs, 58 Siding & Shutters, 62 HVAC, 63 Plumbing, 64 Electrical, 65 Security & Technology, 66 Fireplaces, 67 Insulation & Soundproofing, 69 Drywall, 71 Tile, 72 Flooring, 73 Cabinetry & Countertops, 74 Interior Carpentry, 75 Painting Wallpaper & Stain, 76 Accessories, 77 Appliances, 82 Exterior Carpentry, 84 Exterior Masonry, 85 Exterior Painting, 86 Fencing, 88 Landscape & Grounds, 92 Punch List, 94 Other Expenses-Con

Non-construction (7): 12 Buying, 13 Financing, 14 Holding Costs, 93 Sale Preparation, 95 Other Expenses-NonCon, 96 Selling, 99 Sale

Canonical registry: segments.yaml.

Cost Code -> Segment Resolution

Default: leading 2 digits of the cost code is the segment code, IF that segment exists.

Overrides (cost-code-overrides.yaml):

by_code (specific code -> segment): 30.0 -> 44; 40.0 -> 44; 50.0 -> 52; 60.0/70.0/80.0 -> 94; 72.8 -> 74; 90.0 -> 93; 92.0/92.7/92.8/92.9 -> 93; 92.4 -> 92; 96.1/96.8 -> 99.

by_prefix (prefix range -> segment): 22/24/26/28/29 -> 20 (Site Systems rollup); 68 -> 67 (Sound Proofing merged into Insulation & Soundproofing).

Order: by_code, by_prefix, default 2-digit, otherwise unmapped.

Work Orders

39 operational packets across phases P1/P2/P3. P0/P4 have no WOs (they're financial). Canonical registry: work-orders.yaml.

1:1 invariant: every WO's cost_codes resolve to the same Segment. PMs can add/subtract WOs from a Segment budget unambiguously.

Not every cost code is on a WO. Band-parent codes like 30.0, 60.0, 70.0, 80.0 resolve to a Segment but typically appear on no WO packet — they're catch-alls for miscoded/ad-hoc expenses.

Cost code can appear on multiple WOs (e.g., 74.1 is on both P3WO5 Interior Doors and P3WO13 Hardware). Both resolve to Segment 74; PM picks the right WO at expense time.

Field manager is assigned per WO at issue time by the PM. Not pre-populated.

Files

File Role
segments.yaml Segment registry (39)
cost-code-overrides.yaml Cost code -> segment exceptions
work-orders.yaml Operational WO roster
Cost Code Unified.csv Per-cost-code table with derived Segment + Operational WOs columns
phases.yaml Phase definitions (P0–P4) — used by Work Orders only

Adding a new cost code

  1. Add a row to Cost Code Unified.csv
  2. If the leading 2 digits aren't a Segment in segments.yaml, add an entry to cost-code-overrides.yaml
  3. If the code should appear on a WO, add it to that WO's cost_codes list in work-orders.yaml
  4. Run python3 tools/regenerate_cost_code_csv.py to refresh derived columns
  5. Run python3 -m pytest tools/test_*.py to verify invariants

QB Sub-customer Architecture

Work Orders are QB sub-customers (Customer:Project) under the property parent customer. Segments are derived automatically from cost codes and are NOT separate QB projects.

<Property Customer>         ← QB Customer
  ├── P1WO6 Framing         ← QB Sub-customer (Work Order)
  ├── P1WO7 Roofing
  └── ...  (43 WOs total)

When a vendor submits expenses, they tag them to a WO sub-customer. The actualsboard reads this from the QB transaction's CustomerRef field (raw_customer_ref) to populate the WO actuals section.

Provisioning: tools/qb_replace_segments_with_wos.py — replaces Segment sub-customers with WO sub-customers on a given property. Run --dry-run first, then --apply to confirm with the user. Line items categorized via tools/qb_categorize_lines.py.