| Component | Location | Purpose |
|---|---|---|
| Cloudflare Worker | mes-api.mes-bot.workers.dev |
API proxy — fetches from simPRO + SharePoint |
| GitHub Pages | mes-bot-maker.github.io/mes-dashboards/ |
Hosts the dashboard HTML files |
| GitHub Repo | github.com/mes-bot-maker/mes-dashboards |
Source for dashboards |
| Dashboard | URL | File |
|---|---|---|
| BD Dashboard | /bd/ |
bd/index.html |
| Quotes Pipeline | /quotes/ |
quotes/index.html |
| Projects (TODO) | /projects/ |
projects/index.html |
| Endpoint | Returns |
|---|---|
/api/all |
quotes + targets (parallel, no leads — keeps fast) |
/api/quotes |
Quotes from 2024-01-01, cols: ID,Name,Stage,Total,DateIssued,DateApproved,DueDate,IsClosed |
/api/jobs |
Jobs from 2026-01-01, cols: ID,ConvertedFromQuote,DateIssued |
/api/leads |
Leads from 2026-01-01, cols: ID,LeadName,Stage,DateCreated |
/api/targets |
Targets from SharePoint MES sheet (falls back to hardcoded if SP fails) |
Go to: Workers → mes-api → Settings → Variables & Secrets
| Name | Type | Value / Notes |
|---|---|---|
SIMPRO_BASE_URL |
Text | https://mes-power.simprosuite.com |
SIMPRO_API_KEY |
Secret | simPRO API key |
AZURE_CLIENT_ID |
Text | Azure app client ID |
AZURE_TENANT_ID |
Text | Azure tenant ID |
AZURE_CLIENT_SECRET |
Secret | Azure app secret |
SP_DRIVE_ID |
Text | b!lqS9e4ABZEG8zi3gJ_wIpiQ6SCO-alRNodHfLjoj1fV1igdVlSgxRJ9wvEbU93fF |
SP_ITEM_ID |
Text | 01RTE6GZ65M3IYZ63CSJCLOGCRJINH6OQN |
SP_SHEET_NAME |
Text | MES |
File: 2026 Sales Targets North.xlsx
Location: Commercial site → Shared Documents/Targets (DO NOT DELETE)/
Sheet: MES
Structure the worker expects:
Market | Annual Target | Jan-26 | Feb-26 | ... | Dec-26| Total row: blank | £9,000,000 | £360,000 | £630,000 | … |
Won = Quote has a job raised against it (job appears in /api/jobs with ConvertedFromQuote.ID matching quote ID)
JobNo column rejected by simPRO REST API (422) — use jobs endpoint insteadArchived = IsClosed=true AND not in jobsLookup (no job raised)
Both dashboards auto-refresh every 5 minutes via setInterval — no manual refresh needed on TV.
All year filters use new Date().getFullYear() — auto-updates at new year.
Worker CORS must always be CORS.headers not CORS:
const CORS = { headers: { 'Access-Control-Allow-Origin': '*', ... } };
return new Response(null, { status: 204, headers: CORS.headers });
function json(data, status = 200) { return new Response(JSON.stringify(data), { status, headers: CORS.headers }); }
If dashboards show “Failed to fetch” — check this first.
https://mes-power.simprosuite.comgithub.com/mes-bot-maker/mes-dashboardsbd/index.html)TV dashboard for projects team — active jobs and order book.
SimproJobs — open/active jobs, no date filter (rolling, may include 2024 starts).
Banner KPIs:
Main Table — Active Projects (sorted by value):
Chart — Order Book by Month Issued:
Invoicing Targets — Recommendation:
What NOT to include:
New endpoint /api/projects:
Name — job nameDateIssued — when raisedTotal_ExTax — estimated valueStage — current stageConvertedFromQuoteID — source quoteProjectManagerID — PMCustomerID — customerCompletedDate — completion dateProblem: Some cost centres have materials ordered through them as “billable” when they should be “non-billable” (e.g. Fuel, Cabins, Transport, Safety Fencing on job 5098 Bedesway Jarrow EV Hub R2). This causes TotalsMaterialsCost_Actual and TotalsMaterialsCost_Committed to massively exceed the Total_ExTax cost centre value.
Example — cost centre “Making good around substation” (job 5098):
Why it cannot be fixed: Cost centres are locked (ItemsLocked: true) once invoiced. simPRO enforces this server-side — neither the UI nor the API (PATCH) can change billable/non-billable status on locked items. The only simPRO-supported fix would be to void all invoices, correct the items, and recreate invoices — not practical with live clients.
Impact on dashboards:
Total_ExTax at job level is NOT affected — it reflects the original contract value agreed with the client and is correctTotalsMaterialsCost_Actual/Committed are inflated and unreliable for cost reportingTotal_ExTax only — never derive order book from materials costsProcess fix needed: Train staff to use non-billable cost centres when ordering materials that are not being passed to the client (fuel, transport, site facilities, consumables etc). This only affects cost reporting visibility — it does not affect what the client is charged.
Order Book Value = Sum of Total_ExTax for all Progress + Pending jobs
Remaining to Invoice = Total_ExTax - TotalsInvoicedValue per job
Do NOT use:
Prepaid jobs: Invoiced upfront but work not yet done — TotalsInvoicedValue will be high but Total_ExTax remains the correct contract value. These ARE still in the order book as the work commitment exists.
| Stage | Include? | Rationale | |——-|———-|———–| | Progress | ✅ Yes | Active delivery | | Pending | ✅ Yes | Awarded, not yet started | | Complete | ✅ Yes | Done, may still have remaining invoice | | Invoiced | ⚠️ Optional | Fully invoiced — technically out of order book but still open | | Archived | ❌ No | Closed out |
/api/projects — no dateFrom filter (rolling, all time):
Columns: ID, Name, CustomerID, DateIssued, Stage, Total_ExTax, TotalsInvoicedValue, ProjectManagerID
Filter: Stage NOT IN (Archived)