McCorvey Companies — Mechanical / Plumbing Fabrication
Author: Alex Argumedo | Last Updated: April 2026 | AI-Assisted: GitHub Copilot (Claude Sonnet 4.6)
The WAY Companies Production Tracking System is an automated pipeline that captures the full lifecycle of every fabrication batch produced for WAY Companies projects. Data is sourced from two places:
All data lands in MCDATA1 on MSM-DYNSQLTEST\mcdata and is surfaced in PowerBI through a set of purpose-built views.
Smartsheet Report (ID 5642706326867844)
"WAY In-Progress Batches"
└──► way_production_log_sync.py [Task Scheduler · every 15 min]
├── INSERT dbo.WAY_ProductionBatches (new batches)
├── UPDATE dbo.WAY_ProductionBatches (field changes)
├── INSERT dbo.WAY_ProductionStatusHistory (status transitions)
├── UPDATE dbo.WAY_ProductionStatusHistory (close open records)
└── INSERT dbo.CAM_RunStats (run audit)
Revit Model (WAY projects)
└── A_script.py [PyRevit — run manually by detailer]
└── exports CSVs → \\mccorvey.com\DFS\WAY\Detailing\08 - REPORTS\<ProjectNumber>\
└──► piping_processor.py [Task Scheduler — on new file]
├── INSERT/UPDATE dbo.Pip_Submission
├── UPSERT dbo.Pip_Element
├── UPSERT dbo.Pip_Hanger
└── REPLACE dbo.Pip_HangerAncillary
dbo.WAY_ProductionBatches
dbo.WAY_ProductionStatusHistory
dbo.Pip_Element / Pip_Hanger
dbo.Project / dbo.Project_Details
└──► dbo.vw_WAY_SpoolingAgg (batch-level element + hanger aggregates)
└──► dbo.vw_WAY_ProductionReport (batch grain — primary PowerBI source)
└──► dbo.vw_WAY_SpoolDetail (VicSequence grain)
└──► dbo.vw_WAY_MetalReport (element grain — mirrors vw_CAM_MetalReport)
The shop team maintains individual project production log sheets in Smartsheet. A single Smartsheet Report (ID 5642706326867844) aggregates all in-progress batches from all project sheets into one filtered view. Only batches that are actively in production appear in this report — once a batch ships, it is filtered out automatically by the report criteria.
The sync script fetches all rows from the report via the Smartsheet REST API. For each row:
WAY_ProductionBatches; first status history record opened.IsInReport = 0, RemovedFromReportDT stamped, open history record closed with ExitReason = 'RemovedFromReport'.A backfill pass runs at the start of every sync to fix any rows with NULL ProjectNumber or BatchNumber (handles rows inserted before the current regex logic, or removed batches the normal UPDATE path never touches).
When a detailer finishes spooling a WAY project, they run the PyRevit export script (A_script.py) inside Revit. This exports CSV files to the project folder on the network. The Piping Processor picks them up and upserts element and hanger data into the database.
PowerBI connects to the views. vw_WAY_ProductionReport is always populated (batch data only requires the Smartsheet sync). The spooling columns (BatchPipeElementCount, BatchTotalLinearFt, BatchHangerCount) return 0 until Revit data is loaded — they auto-populate once Pip_Element is populated.
| Property | Value |
|---|---|
| Location (server) | C:\Scripting\Python\Scripts\Production Log Sync\way_production_log_sync.py |
| Location (dev) | D:\Scripting\Python\Scripts\Metal_Report\way_production_log_sync.py |
| Python | C:\Python\Python314\python.exe |
| Schedule | Windows Task Scheduler — every 15 minutes |
| Smartsheet source | Report ID 5642706326867844 — WAY In-Progress Batches |
| SQL target | MSM-DYNSQLTEST\mcdata / MCDATA1 |
| Log directory | P:\CAM_Reports\logs\ (falls back to .\logs\ on the server if P: is not mapped) |
| Log file pattern | way_prod_sync_YYYYMMDD.log |
| Log rotation | 60 days |
The Smartsheet Report endpoint behaves differently from the Sheet endpoint:
virtualId (not id)virtualColumnId (not columnId)The script parses ProjectNumber and BatchNumber from the Batch ID column using the following priority:
BATCH_ID_RE (see Section 5)SheetName (e.g. "71000012 - Production Log" → 71000012)The Primary column encodes building level, service, and area in the format:
L02 - DWV Hangers - Area J
The script parses this into three separate columns: Level, Service, Area. Rows that don't match the pattern store NULL in all three and the raw value in PrimaryField.
Every status transition writes to WAY_ProductionStatusHistory:
StatusEnteredDT = nowExitReason = 'StatusChange'), open new recordExitReason = 'RemovedFromReport')Runs at startup each sync. Selects all rows in WAY_ProductionBatches where ProjectNumber IS NULL, BatchNumber IS NULL, or BatchNumber = BatchName (incorrect old fallback value), and re-parses them using the current regex. Safe to run repeatedly — uses COALESCE on ProjectNumber to never overwrite good data.
Each run writes one row to dbo.CAM_RunStats:
ScriptName = 'way_production_log_sync' RunStartDT, RunEndDT, DurationSec, SheetsProcessed=1, RowsUpdated, RowsInserted
| Property | Value |
|---|---|
| Location | D:\Scripting\Python\Scripts\Metal_Report\piping_processor.py |
| Trigger | Windows Task Scheduler or manual run after A_script export |
| Input path | \\mccorvey.com\DFS\WAY\Detailing\08 - REPORTS\<ProjectNumber>\ |
| Input files | PInfo.csv (project info), Elements.csv (pipe/fittings), Hangers.csv (hangers) |
| SQL target | MSM-DYNSQLTEST\mcdata / MCDATA1 |
dbo.Pip_Submission (one per script run)dbo.Pip_Element on (ProjectNumber, RevitElementId); child dimensions in Pip_ElementDim are fully replaced (DELETE + INSERT)dbo.Pip_Hanger on (ProjectNumber, RevitElementId); ancillaries in Pip_HangerAncillary are fully replacedPip_Element.VicSequence comes from the Revit parameter Vic_Sequence stamped by the detailer. This value must match WAY_ProductionBatches.BatchName exactly for the join in the PowerBI views to resolve. The detailer must use the correct batch name when assigning sequences in Revit.
Primary tracking table. One row per batch ever seen in the WAY in-progress Smartsheet report.
| Column | Type | Description |
|---|---|---|
BatchPK | INT IDENTITY PK | Surrogate key |
ReportID | BIGINT | Smartsheet report ID (5642706326867844) |
SourceSheetID | BIGINT | Originating sheet ID (from row.sheetId) |
SourceRowID | BIGINT | Smartsheet row ID (same in report and source sheet) |
BatchName | VARCHAR(50) | Full Batch ID (e.g. 10000132B0438) — join key to CAM_Batch.JobName and Pip_Element.VicSequence |
ProjectNumber | VARCHAR(20) | Parsed from BatchName — join key to Project tables |
BatchNumber | VARCHAR(20) | Parsed from BatchName (e.g. B0438) |
SheetName | VARCHAR(200) | Source Smartsheet name (e.g. 10000132 - Production Log) |
ProductionStatus | VARCHAR(100) | Current/last-known status |
FabPctComplete | DECIMAL(5,2) | Fabrication % (0.00 – 100.00) |
PrimaryField | VARCHAR(300) | Raw Primary cell value |
Level | VARCHAR(50) | Parsed building level (e.g. L02) |
Service | VARCHAR(200) | Parsed service (e.g. DWV Hangers) |
Area | VARCHAR(50) | Parsed area code (e.g. J) |
Notes | VARCHAR(500) | Free-text notes from Smartsheet |
IsInReport | BIT | 1 = active in report, 0 = removed (fabrication complete) |
FirstSeenDT | DATETIME | First sync run the batch appeared |
LastSeenInReportDT | DATETIME | Last sync run the batch was present |
RemovedFromReportDT | DATETIME | First sync run the batch was absent (lower bound for completion) |
LastCheckedDT | DATETIME | Last sync run that evaluated this row |
LastUpdatedDT | DATETIME | Last sync run that changed a data field |
Full audit timeline of status changes. One row per status period per batch.
| Column | Type | Description |
|---|---|---|
HistoryPK | INT IDENTITY PK | |
BatchPK | INT FK | → WAY_ProductionBatches |
Status | VARCHAR(100) | Status value for this period |
StatusEnteredDT | DATETIME | When this status was first observed |
StatusExitedDT | DATETIME NULL | When this status ended (NULL = still open) |
DurationMinutes | AS DATEDIFF(...) PERSISTED | Computed: minutes in this status (NULL while open) |
ExitReason | VARCHAR(50) | 'StatusChange' or 'RemovedFromReport' |
One row per Revit export run (from PInfo.csv). Provides project context for every element.
One row per pipe / fitting element. Upsert key: (ProjectNumber, RevitElementId). Key field: VicSequence — must match WAY_ProductionBatches.BatchName.
One row per fabrication hanger. Same upsert key pattern. Also carries VicSequence.
Child dimension rows. Fully replaced (DELETE + INSERT) on every parent upsert.
| View | Grain | Data available | Primary use |
|---|---|---|---|
vw_WAY_ProductionReport |
One row per batch | Now | Main PowerBI source — batch status, stage durations, project info, spooling aggregates |
vw_WAY_SpoolingAgg |
One row per VicSequence | After Revit export | Intermediate view — feeds element/hanger counts into vw_WAY_ProductionReport |
vw_WAY_SpoolDetail |
One row per VicSequence | After Revit export | Spool-level detail for PowerBI drill-through |
vw_WAY_MetalReport |
One row per pipe element | After Revit export | Element-grain view — mirrors vw_CAM_MetalReport column aliases for cross-company PowerBI measures |
The join between Revit data and Smartsheet batch data uses:
Pip_Element.ProjectNumber = WAY_ProductionBatches.ProjectNumber Pip_Element.VicSequence = WAY_ProductionBatches.BatchName
This is the confirmed match between Revit's Vic_Sequence parameter and the WAY Batch ID in Smartsheet.
| Measure | Source Column | Expression |
|---|---|---|
| Active Batches | IsInReport | COUNTROWS(FILTER(... IsInReport = 1)) |
| Avg Fabrication % | FabPctComplete | AVERAGE(FabPctComplete) |
| Batches Completed | IsInReport | COUNTROWS(FILTER(... IsInReport = 0)) |
| Avg Days in System | DaysInSystem | AVERAGE(DaysInSystem) |
| Avg Minutes per Stage | DurationMinutes | From WAY_ProductionStatusHistory |
| Pipe Elements | BatchPipeElementCount | SUM(BatchPipeElementCount) |
| Total Linear Ft | BatchTotalLinearFt | SUM(BatchTotalLinearFt) |
FirstSeenYear, FirstSeenMonth, FirstSeenMonthLabel (e.g. Apr 2026), FirstSeenMonthSort (YYYYMM integer, use as sort-by for month label).
| Format | Example | ProjectNumber | BatchNumber | Source |
|---|---|---|---|---|
| A Dash | 18312-001 |
18312 |
001 |
Older projects |
| B Prefix+Letter | 10000132B0438 |
10000132 |
B0438 |
Standard WAY format |
| C MISC prefix | MISCB1471 |
MISC |
B1471 |
Miscellaneous / shop jobs |
| D Bare batch (no project) | B0002 |
From SheetName (e.g. 71000012) |
B0002 |
Some newer entries |
ProjectNumber), update BATCH_ID_RE in way_production_log_sync.py and re-run — the backfill function will automatically fix existing rows.
| Item | Value |
|---|---|
| Report ID | 5642706326867844 |
| Report Name | WAY In-Progress Batches (Production Log) |
| Access | Smartsheet account with SMARTSHEET_ACCESS_TOKEN env var |
| Smartsheet Column | DB Column | Required? |
|---|---|---|
Batch ID | BatchName | ✅ Required |
Production Status | ProductionStatus | ✅ Required |
Primary | PrimaryField / Level / Service / Area | Optional |
Sheet Name | SheetName (also used as ProjectNumber fallback) | Optional |
Fabrication % Complete | FabPctComplete | Optional |
Notes | Notes | Optional |
Facility | (stored, not currently used in views) | Optional |
Project Number | ProjectNumber (overrides regex parse) | Optional — not present in this report |
System Properties → Advanced → Environment Variables → System Variables, then restart the Task Scheduler service.
| Variable | Used By | Description |
|---|---|---|
SMARTSHEET_ACCESS_TOKEN | way_production_log_sync.py production_log_sync.py | Smartsheet API bearer token |
mcd_usr | All scripts | SQL Server login username |
sqlro_McData | All scripts | SQL Server login password |
[System.Environment]::GetEnvironmentVariable('SMARTSHEET_ACCESS_TOKEN', 'Machine')
[System.Environment]::GetEnvironmentVariable('mcd_usr', 'Machine')
[System.Environment]::GetEnvironmentVariable('sqlro_McData', 'Machine')
| Path | Purpose |
|---|---|
C:\Scripting\Python\Scripts\Production Log Sync\way_production_log_sync.py | Script location on server (Task Scheduler target) |
D:\Scripting\Python\Scripts\Metal_Report\way_production_log_sync.py | Development / source copy (this workspace) |
P:\CAM_Reports\logs\way_prod_sync_YYYYMMDD.log | Log file (workstation) |
C:\Scripting\Python\Scripts\Production Log Sync\logs\way_prod_sync_YYYYMMDD.log | Log file (server fallback when P: not mapped) |
\\mccorvey.com\DFS\WAY\Detailing\08 - REPORTS\<ProjectNumber>\ | Revit CSV export drop zone (input to piping_processor.py) |
| Setting | Value |
|---|---|
| Name | WAY Production Log Sync |
| Program | C:\Python\Python314\python.exe |
| Arguments | "C:\Scripting\Python\Scripts\Production Log Sync\way_production_log_sync.py" |
| Start in | C:\Scripting\Python\Scripts\Production Log Sync\ |
| Trigger | Daily, repeat every 15 minutes indefinitely |
| Run As | Service account with system-level env vars and network access to P:\ and SQL Server |
| Run whether logged on or not | ✅ Checked |
| Do not store password | ❌ Unchecked (must store credentials) |
SMARTSHEET_ACCESS_TOKEN is empty or expired. Verify the machine-level env var is set (see Section 7). If the token is expired, generate a new one in Smartsheet (Account → Apps & Integrations → API Access) and update the system env var.
Check that mcd_usr and sqlro_McData are set at machine level. Verify the server can reach MSM-DYNSQLTEST\mcdata — run ping MSM-DYNSQLTEST from the server. Confirm ODBC Driver 17 is installed: Get-OdbcDriver -Name "ODBC Driver 17*"
The backfill runs automatically on every sync. If rows remain NULL after a run, check the log for Backfill: fixed X row(s). If the BatchName format is new and unrecognized, update BATCH_ID_RE or the SHEET_NAME_PROJECT_RE fallback in the script and re-sync.
The view requires WAY_ProductionBatches to be populated by at least one successful sync run. Check the log file for errors. Confirm the view was created successfully by running:
SELECT name, create_date FROM sys.views WHERE name LIKE 'vw_WAY%'
Expected — Pip_Element is empty until a detailer runs A_script.py inside Revit and the piping processor processes the exported CSVs. No action required.
The script falls back to .\logs\ (next to the script) when the P: drive is not accessible. On the server, logs will be at C:\Scripting\Python\Scripts\Production Log Sync\logs\.
Edit the file in the workspace (D:\Scripting\Python\Scripts\Metal_Report\way_production_log_sync.py), then copy to the server using one of:
# Via admin share (if accessible):
Copy-Item "D:\Scripting\Python\Scripts\Metal_Report\way_production_log_sync.py" `
"\\<ServerName>\C$\Scripting\Python\Scripts\Production Log Sync\" -Force
# Via PSRemoting:
$s = New-PSSession -ComputerName <ServerName>
Copy-Item "D:\...\way_production_log_sync.py" `
-Destination "C:\Scripting\Python\Scripts\Production Log Sync\" -ToSession $s
This system is part of a broader fabrication tracking platform. The table below shows how components relate:
| Component | Company | Script | Primary Table | PowerBI View |
|---|---|---|---|---|
| Sheet Metal CAM Processor | MSM / MIF / Duct Direct | metal_report_processor.py |
CAM_Batch / CAM_Pieces |
vw_CAM_MetalReport |
| MSM Production Log Sync | MSM / MIF / Duct Direct | production_log_sync.py |
CAM_ProductionBatches |
vw_CAM_MetalReport |
| WAY Production Log Sync | WAY Companies | way_production_log_sync.py |
WAY_ProductionBatches |
vw_WAY_ProductionReport |
| Piping Processor | WAY Companies | piping_processor.py |
Pip_Element / Pip_Hanger |
vw_WAY_MetalReport |
All systems share: dbo.Project, dbo.Project_Details, dbo.CAM_RunStats, and the environment variables mcd_usr / sqlro_McData.
McCorvey Companies © 2026 — Internal use only. For support contact the IT / BI team. Alex Argumedo
