Case study
How We Streamlined Customer Forecast Data for Production Planning
Vehicle makers send suppliers updated estimates of the parts they will need. For one automotive parts manufacturer, KS AI & Cloud Solutions built a workflow that compares each new forecast with the last one and flags large changes. Planners can then check the change against schedules, orders and stock before they change a plan.
Who this is for: manufacturing leaders, demand and production planners, purchasing teams, and data/IT teams. The first sections explain the business problem and planning decisions. The technical deep dive is for readers who want implementation detail.
- Industry
- Automotive parts manufacturing
- Data source
- Customer demand forecasts from SPS Commerce
- Tools used
- SharePoint, Power BI, Power Automate and Python
- When it runs
- On a schedule based on customer forecast updates
- Time per forecast cycle
- Almost 5 days before; less than 1 day after
What changed since the previous forecast
- Previous forecast
- Latest forecast
- Moved more than 20%
Swipe sideways to see all six months.
Project at a glance
The challenge
Each vehicle maker sends forecasts in a different file format and may use its own part numbers. Planners had to compare new files with old files by hand. That made important changes hard to spot quickly. It was also hard to tell a real production-plan change from a shift in timing, a short-lived forecast swing, or a data problem.
What we built
We built a scheduled workflow using Microsoft 365 tools. Our team collects each forecast from SPS Commerce. A Python script puts the file into a common format in SharePoint. Power BI compares the latest forecast with the previous one, and Power Automate emails the planning and data teams about large changes or customer part numbers that are not mapped yet.
The result
A forecast cycle went from almost five days to less than one day (how this was measured). The workflow also gives planners a clear list of changes, keeps past forecasts, and flags customer part numbers that need to be mapped.
The challenge: customer forecasts keep changing, and nobody could see what changed
Vehicle makers send suppliers more than firm orders. They also send a rolling forecast: an updated estimate of the parts they may need in the coming months. Suppliers use it to plan production, materials and staffing. In this case, an automotive parts manufacturer received forecasts from several vehicle makers through SPS Commerce, a platform for sharing forecasts and orders.
A forecast is useful, but the key question is: what changed since the last version? For example, a 25% rise in a group of related parts two months from now is a signal to investigate—not an automatic instruction to buy more. Check the customer's production schedule, firm orders, stock on hand and supplier lead times first. A sharp drop should also trigger a check before you cut production or cancel material orders.
Key terms, in plain English
- Trading partner
- A customer that sends forecasts. In this case, a vehicle maker.
- Forecast version
- A copy of a customer's forecast as it stood on the date it was issued. Each new file becomes a new version.
- Customer part number (SKU)
- The code a customer uses to identify a part. Different customers may use different codes for the same part. Here, SKU means the customer's part number.
- Internal part number
- The code the manufacturer uses for that part in its own production and planning systems.
- Part family
- A group of related parts. Planners can review the group's demand before looking at each part one by one.
- Reference table (Part)
- A lookup table in SharePoint that links each customer part number to the manufacturer's internal part number and part family. The client's data team maintains it.
- Supplier lead time
- How long it usually takes a supplier to deliver material after an order is placed.
Getting that signal was hard work:
- Each customer used a different file layout, so the files could not be compared directly.
- Customer part numbers had to be linked to the manufacturer's part numbers before planners could trust part-level totals.
- Earlier forecasts were often overwritten or hard to find, so there was no clear history.
- Planners had to compare versions for every customer, part family and part number by hand.
- When a customer used a new part number, the team might miss it. That demand could be left out of part-level reports.
A different layout per customer
Customers sent large files in different layouts. The same information appeared in different places and formats.
Part numbers that don't match
Each customer part number must be linked to the manufacturer's part number. If a new code is not linked, its demand can be missing from reports for individual parts.
No memory of past forecasts
Old forecasts were hard to find. Planners could not tell whether a change was new or part of a longer pattern.
Changes spotted late
Large changes were found late, leaving less time to adjust material orders, staffing or production plans.
One forecast cycle, before and after
Every step the team used to do by hand, and what happens now. The biggest difference is time.
Connecting customer forecasts to production planning
Customer forecast files give a manufacturer an early view of the parts and quantities a customer may need. We streamlined these inputs into a repeatable reporting workflow so the planning team could compare each new forecast with the previous version, see where demand had changed, and review the impact across 30-, 90- and 120-day horizons. This gives production and materials teams a clearer, shared view of expected demand for planning decisions.
The workflow turns incoming customer forecast data into information planners can review consistently. Comparing versions helps the team see what changed, by how much, and when the demand is expected. The 30-, 90- and 120-day views make near-term and longer-range changes easier to spot. The comparison does not automatically identify the reason for a change, or make production decisions on its own. Planners validate significant changes against customer schedules, firm orders, inventory, supplier lead times and source files before adjusting production or material plans.
| Look-ahead period | What the change may mean | What to check |
|---|---|---|
| 30 days | A near-term change may mean the vehicle maker changed its schedule, moved demand earlier or later, or has a parts-supply issue. | Check firm orders, the current production schedule, stock on hand, open purchase orders and capacity for the next few weeks. |
| 90 days | A change may mean the production plan has changed, or demand has moved from one month to another. | Compare the months side by side. Check supplier lead times and planned shifts. Did total demand change, or only its timing? |
| 120 days | A longer-range change may reflect a revised production plan, a model change, or demand that is still uncertain. | Check the customer plan, materials with long lead times, supplier commitments, stock risk and earlier forecast versions. |
Possible reasons to check before changing the plan
- Vehicle-maker plan changed: the customer may have changed its build schedule or the number of vehicles it plans to make.
- Demand moved between months: one month may go up while another goes down, even if the total changes very little.
- Short-lived forecast swing: a spike may reverse in the next version. Compare several versions before treating it as a trend.
- Supplier lead time: material that takes a long time to arrive may need to be ordered before the demand date.
- Stock and order timing: the amount needed may stay similar while the date to order material changes.
- New or unmapped part number: a new customer code may not be linked to the correct internal part.
- File or data problem: a missing file, duplicate row or changed layout may create a false change—or hide a real one.
How to connect the dots: from alert to planning action
Illustrative example: a part family's forecast is 25% higher in the 90-day view than it was in the previous version. The alert points to a change; it does not tell the planner what to do.
- Confirm the comparison. Make sure both versions cover the same future months and use the same part mapping.
- Check the cause. Compare the customer's production schedule and firm orders. Check stock, open purchase orders, supplier lead times and the source file.
- Choose the right action. If extra demand is confirmed, review material supply, order dates, capacity and shifts. If demand only moved between months, the timing may need to change more than the total quantity.
- Record and monitor. Note what evidence supported the decision, then see whether the next forecast confirms or reverses the change.
Important: an alert is a prompt to investigate, not an automatic instruction to buy, cancel an order or change production.
What to check next: start with the largest changes. Compare the same future months in both versions. Check for missing part mappings, then compare the result with orders, stock, supplier lead times and production schedules. Treat each possible cause as unconfirmed until the evidence supports it.
The solution in plain English
Think of it as track changes for customer forecasts. Each new file is saved. Power BI compares it with the previous version and shows where expected demand changed. An automated email flags changes that pass the agreed limits. A planner checks the alert before changing production or material plans.
-
Each forecast cycle
Collect
Our team downloads each customer's latest forecast from SPS Commerce. A Python script cleans the file and puts it into a common format. We save it in that customer's SharePoint folder and confirm the upload to the data team.
-
Scheduled, automatic
Refresh
Power BI reads the files, aligns their layouts and uses the reference table to link each customer part number to the manufacturer's internal part number and part family.
-
Any time
Compare
Planners compare the latest forecast with the previous one for upcoming months. They can review totals by customer, part family or individual part number.
-
About an hour later
Alert
Power Automate checks for large changes and missing part mappings, then emails the results to the planning and data teams.
Change % = ( Latest forecast − Previous forecast ) ÷ Previous forecast This calculation shows the percentage change. It does not explain the cause. In this example, alerts are sent when total demand by customer changes by more than 15%, or a part family or part number changes by more than 20%. Set and test thresholds for the risks in each business.
Why we keep every forecast version
Keeping old forecast versions helps planners see whether a change is a one-off swing or part of a steady trend.
For example, two part families may both show lower demand in the latest forecast. One may have fallen steadily over six versions. The other may have moved up and down. The latest numbers alone look similar, but the planning response may be different.
Swipe sideways to see both views.
What the history makes possible
- Tell a trend from noiseCompare the latest forecast with any earlier version and see whether demand is drifting steadily or just bouncing around.
- Know each customer's habitsSome trading partners revise a lot, others hardly at all. History shows whose forecasts to plan on, and how much safety stock each one really needs.
- Measure forecast accuracyOld versions can be checked against what customers actually bought later. Calculating forecast accuracy also requires actual sales or shipment data and a defined error metric; forecast history alone is not enough.
- Back up customer conversationsWhen a customer cuts demand after material was bought, the stored versions show exactly what was forecast and when.
What goes wrong without it
- Every change can look equally urgent, even when it reflects a timing shift, temporary volatility or a data issue.
- Slow, steady drifts that stay under the alert line are never noticed.
- There's nothing to measure forecast accuracy against.
- There's no evidence to share when a customer's numbers move after commitments were made.
- Buffers and safety stock are set by gut feel.
- Knowledge lives in inboxes and leaves with the person who kept them.
Who uses it, and who does what
The workflow connects three jobs: planners decide how to respond, the client's data team keeps part mappings correct, and our team maintains the file collection and reporting workflow. Automation handles the repeated comparison and email steps.
- Planning teamClient: demand and production planners
Read the alert email after every refresh, open the report to drill from trading partner down to part number, and adjust production and material plans.
Main report users - Supply chain and purchasingClient
Use confirmed changes to bring material orders forward or push them back, before a swing reaches their own suppliers.
Report users - Customer account managersClient
Follow up with a trading partner when its forecast swings sharply or keeps reversing from one version to the next.
Report users - Data teamClient
Checks the upload confirmation and alert email. Adds each missing customer part number to the reference table, with its internal part number and part family. Keeps the location list up to date.
Maintains the reference table - Our teamKS AI & Cloud Solutions
Downloads each forecast, uses a Python script to standardise it, uploads it to SharePoint and confirms the upload. Our team also maintains the data model, report and alert flow.
Collection and support - AutomationPower BI and Power Automate
Refreshes on schedule, compares the versions, runs the four checks and sends the email. Nobody has to press a button.
Runs on its own
Swipe sideways to see every lane.
Solution architecture
Follow the diagram from left to right: customer forecast, file collection and cleanup, SharePoint, Power BI, then the alert email. The loop back is important: the data team fixes missing part mappings, and Power BI uses those fixes at the next refresh. The next section explains the technical setup for data and IT teams.
Swipe sideways to explore the diagram.
Technical deep dive (for data and IT teams)
This section explains how the workflow is built. It covers file collection, the Power BI model and automated alerts. Manufacturing leaders and planners who only need the business process can skip to the results section.
Part 1: Collecting and standardising forecasts into SharePoint
SPS Commerce, a Python script and SharePoint Online. Run by our team.
The pipeline starts with the files themselves. On every forecast cycle, our team downloads the latest forecasts for each trading partner from SPS Commerce, using access the client provides. A Python script then puts every customer's file into one consistent, predictable format, and each file is uploaded to its partner's folder in a dedicated SharePoint site.
- Download from SPS CommerceIn the transactions search, our team picks one trading partner and its plants, filters to forecast documents in a recent date range, ticks the latest versions and downloads them as CSV files.
Swipe sideways to see the full screen.
- Standardise with a Python scriptEvery customer exports its forecast differently: extra header rows, multi-record layouts, dates written in different ways, one file or several per plant. A Python script does the heavy lifting with a small rule set for each trading partner, and writes clean files for each partner in a consistent format, cycle after cycle.
- Name by forecast dateThe script names each file with the date the forecast was issued, for example
PartnerA_forecast_2026-10-12.csv. The model reads the date from the name, so nobody has to type it anywhere. - Upload to the partner's folderThere's one folder per trading partner. Earlier versions stay where they are, and that is what builds the history.
- Confirm the upload to the data teamA second Python script counts the files for each trading partner and lists every file's name and size. Our team emails the result to the primary contact in the client's data team, as a final check before the scheduled refresh.
- Keep the reference data alongsideThe reference table (Part), which maps each customer part number (SKU) to the internal part number and part family, and a location-to-country list live in the same site. The client's data team maintains both.
Python: standardising a partner's files, simplified
from pathlib import Path
import pandas as pd
# One small rule set per trading partner
RULES = {
"PartnerA": {"skip": 2, "fmt": "%m/%d/%Y",
"dates": ["Forecast Start Date"]},
"PartnerB": {"skip": 0, "fmt": "%Y%m%d",
"dates": ["Ship Date"]},
}
def standardise(partner, downloads, forecast_date, out_dir):
rule = RULES[partner]
# one or more downloaded files per partner
frames = [pd.read_csv(f, dtype=str, skiprows=rule["skip"])
for f in downloads]
data = pd.concat(frames, ignore_index=True).dropna(how="all")
data.columns = data.columns.str.strip() # predictable headers
for col in rule["dates"]: # one date format
data[col] = (pd.to_datetime(data[col], format=rule["fmt"])
.dt.strftime("%Y-%m-%d"))
name = f"{partner}_forecast_{forecast_date}.csv"
data.to_csv(Path(out_dir) / partner / name, index=False)
A confirmation before the refresh deadline
Power BI refreshes on a schedule, and the alert flow runs about an hour later. Both only see what is in SharePoint at that moment, so the upload has a deadline: every file has to be in place before the refresh starts. Once the upload is done, a second Python script counts the files for each trading partner and lists every file's name and size, and our team sends the result to the primary contact in the client's data team.
It takes seconds to read, and it catches problems while there's still time to fix them. A partner with zero files, or a file far smaller than usual, stands out before the refresh rather than in the alert email afterwards.
Python: the confirmation report, simplified
import os
TRADING_PARTNERS = ["PartnerA", "PartnerB", "PartnerC", "PartnerD",
"PartnerE", "PartnerF", "PartnerG"]
def get_files_by_partner(folder):
"""File names and sizes for each trading partner in the folder."""
details = {partner: [] for partner in TRADING_PARTNERS}
for root, _, files in os.walk(folder):
for file in files:
size_kb = os.path.getsize(os.path.join(root, file)) / 1024
for partner in TRADING_PARTNERS:
if partner.lower() in file.lower():
details[partner].append((file, f"{size_kb:.2f} KB"))
return details
def generate_email(details, dt):
"""Confirmation email: a count per partner, then every file."""
body = (f"Subject: Demand forecast file report - {dt}\n\n"
"Dear Team,\n\nPlease find below the details for the "
f"folder with date {dt}:\n\n")
for partner, files in details.items():
noun = "file" if len(files) == 1 else "files"
body += f"🔹 {partner}: {len(files)} {noun}\n"
if files:
body += " 📂 Files:\n"
for name, size in files:
body += f" - {name} ({size})\n"
body += "\n"
return body + "Best Regards,\nAutomated Report System\n"
Dear Team,
Please find below the details for the folder with date 10-12-2026:
- Partner A: 1 fileFiles:- PartnerA_forecast_2026-10-12.csv (64.10 KB)
- Partner B: 2 filesFiles:- PartnerB_forecast_2026-10-12.csv (371.25 KB)- PartnerB_plant2_forecast_2026-10-12.csv (31.40 KB)
- Partner C: 1 fileFiles:- PartnerC_forecast_2026-10-12.csv (179.82 KB)
- Partner D: 1 fileFiles:- PartnerD_forecast_2026-10-12.csv (2.74 KB)
- Partner E: 1 fileFiles:- PartnerE_forecast_2026-10-12.csv (8.05 KB)
- Partner F: 0 files Stands out before the refresh
- Partner G: 1 fileFiles:- PartnerG_forecast_2026-10-12.csv (82.33 KB)
Best Regards,
Automated Report System
Swipe sideways to see the full email.
Why SharePoint is the right landing zone
We could have pushed files straight into a database. For a file-based process owned by business users, SharePoint gave us more:
- Every forecast version, keptEach file stays in its folder, so the model holds every past version. That is the foundation of the history described above.
- Add a partner without a rebuildA new trading partner means a new folder, one new rule set in the script and one new query. Nothing downstream changes.
- Maintained by the businessThe data team updates the reference table in Excel, in SharePoint, without ever opening Power BI.
- Easy collaborationOur team, the data team and the planners all open the same CSV files, from SPS Commerce download to Power BI source, so everyone sees exactly what the report is built on.
- No gateway, no stored passwordsSharePoint Online is a cloud source, so the Power BI service refreshes it with organizational sign-in and no on-premises gateway.
- An audit trail for freeEvery file is a record of what each customer sent, kept separate from the logic that interprets it.
Part 2: The Power BI model and report
Power Query, data modeling, DAX and report design. Refreshes automatically.
This is the heart of the solution. The model has to turn a pile of differently shaped files into one question: how did each customer's view of the coming months change since its previous forecast? Four problems stood between the raw files and that answer.
Problem 1: many partner files, one table
Because the Python script has already done the heavy lifting, Power Query only has light work left. Each partner folder has its own short query that does four things: a light clean-up, renaming columns to the common names, adding a Trading Partner column taken from the file name so every row knows which customer it came from, and giving the table exactly the same columns and order as every other query. Where a partner dates its forecast buckets differently, its query also shifts the start date so every partner lines up on the same calendar.
That identical structure is what makes the next step possible: one append stacks every partner into a single forecast table.
Swipe sideways to see the full table.
Power Query (M), simplified
// Each partner query: trading partner from the file name...
#"Added Partner" = Table.AddColumn(#"Kept Columns", "Trading Partner",
each Text.BeforeDelimiter([Source.Name], "_"), type text),
// ...common column names...
#"Renamed Columns" = Table.RenameColumns(#"Added Partner", {
{"Buyer Part", "SKU"},
{"Forecast Qty", "QTY"},
{"Forecast Start Date", "Start Date"}
}),
// ...and the same columns, in the same order, as every other query
#"Same Structure" = Table.SelectColumns(#"Renamed Columns", {
"Trading Partner", "SKU", "Location", "QTY", "Start Date", "Source.Name"
}),
// Identical structures, so one append builds the forecast table
Source = Table.Combine({PartnerA, PartnerB, PartnerC, PartnerD, PartnerE}),
#"Removed Errors" = Table.RemoveRowsWithErrors(Source)
Problem 2: which forecast version is this row from?
Each file holds forecast quantities by delivery date, but the model also needs to know which version a row belongs to. We made the file name the source of truth. A calculated column reads the ten-character date just before the file extension, so every row is stamped with its forecast date the moment it loads.
DAX calculated column
Forecast Date =
VAR FileName = TRIM ( 'OEM forecast Table'[Source.Name] )
RETURN
// "PartnerA_forecast_2026-10-12.csv" → 12 Oct 2026
DATEVALUE ( MID ( FileName, LEN ( FileName ) - 13, 10 ) )
Problem 3: customer part numbers (SKUs) aren't internal part numbers
Customers forecast against their own part numbers (SKUs), and the manufacturer plans against its own. The reference table (Part), an Excel workbook in SharePoint that the client's data team maintains, maps each SKU to its internal part number and part family, and becomes the Part dimension. Plant and location tables add the plant name and country, and a calendar table with a rolling next-six-months flag keeps every view focused on the planning horizon. Kit part families are filtered out of the part-level pages and alerts.
Swipe sideways to see the full model.
Problem 4: comparing any two forecast versions
Two small calculated tables, Forecast Versions and Previous Versions, list every forecast date and have no relationships at all. They feed two slicers, and the measures read the selections. By default the current version is the latest file and the previous version is the one before it, but a planner can pick any earlier version to compare against. This is where the stored history pays off.
DAX, names simplified
Previous Forecast Demand =
VAR CurrentVersion =
SELECTEDVALUE (
'Forecast Versions'[Forecast Date],
MAX ( 'Forecast Versions'[Forecast Date] )
)
VAR VersionBefore =
CALCULATE (
MAX ( 'OEM forecast Table'[Forecast Date] ),
FILTER (
ALL ( 'OEM forecast Table' ),
'OEM forecast Table'[Forecast Date] < CurrentVersion
)
)
VAR Compared =
SELECTEDVALUE ( 'Previous Versions'[Forecast Date], VersionBefore )
RETURN
CALCULATE (
SUM ( 'OEM forecast Table'[QTY] ),
'OEM forecast Table'[Forecast Date] = Compared
)
The headline cards compare the two versions over three fixed windows of 30, 90 and 120 days, each starting on the first day of the month after the current forecast. Fixed windows keep the comparison fair: both versions are judged on exactly the same future dates.
Swipe sideways to see the full timeline.
Three levels of detail, one layout
The report opens on a home page that shows when the data last refreshed, then offers three analysis pages with the same layout. Planners start broad and drill down: trading partner, then part family, then internal part number. Because every page looks the same, nobody has to relearn where things are.
Swipe sideways to see the full page.
Part 3: Automated alerts with Power Automate
Power Automate, the Power BI connector and Office 365 Outlook. Runs on its own.
A report only helps if someone opens it. The alert flow makes sure the important changes reach the team either way. It runs about an hour after each scheduled refresh, and instead of exporting visuals it asks the published semantic model direct questions in DAX, using the Run a query against a dataset action of the Power BI connector.
- RecurrenceScheduled to match the forecast cycle, about an hour after the refresh.
- Run a query against a dataset, four timesFour DAX queries run against the published semantic model, one per check.
- Parse JSONEach result is parsed so its columns can be used in later steps.
- Create HTML table and ComposeEach result becomes a bordered HTML table.
- Send an email (V2)One email to the planning team and the data team, with all four tables and a link to the reference table workbook.
Four checks on every new forecast
- Trading partner±15%Total demand per partner, largest change first
- Part family±20%Kit families excluded, largest change first
- Part number±20%Internal part numbers, kit parts excluded, largest change first
- Missing mappingAny new SKUCustomer part numbers (SKUs) not yet in the reference table (Part)
What the alert email looks like
All four checks land in one email, always in the same order, so readers know exactly where to look. The numbers below match the markers in the sample.
- Subject and recipients. A fixed subject, sent automatically to the planning team and the data team after each refresh.
- Link to the reference table. One click opens the Excel workbook where the data team adds missing mappings.
- Missing part numbers. Each customer part number (SKU) not yet in the reference table, with the trading partner that sent it.
- Trading partner changes. Partners whose total demand moved more than ±15%.
- Part family changes. Families that moved more than ±20%, kit families excluded.
- Part number changes. Internal part numbers that moved more than ±20%, kit parts excluded.
Every change table has the same columns: current forecast, previous forecast, change in % and the difference in units, sorted by the largest difference first.
Hello team,
Please check below for missing part numbers and significant changes in the trading partner, part family and part number analysis.
3Missing part numbers in the reference table (Part) 2 new
| Customer part number (SKU) | Trading partner |
|---|---|
| CX-48213 | Partner B |
| 77-1290-A | Partner D |
4Trading partner change, threshold ±15%
| Trading partner | Current forecast | Previous forecast | Change (%) | Difference |
|---|---|---|---|---|
| Partner C | 6,240 | 5,180 | +20.46 | 1,060 |
5Part family change, threshold ±20%
| Part family | Current forecast | Previous forecast | Change (%) | Difference |
|---|---|---|---|---|
| Family K2 | 1,980 | 1,590 | +24.53 | 390 |
| Family M7 | 640 | 842 | −23.99 | −202 |
6Part number change, threshold ±20%
| Internal part number | Current forecast | Previous forecast | Change (%) | Difference |
|---|---|---|---|---|
| 40-2271 | 410 | 318 | +28.93 | 92 |
| 40-1185 | 96 | 132 | −27.27 | −36 |
Regards,
System generated
Swipe sideways to see the full email.
The queries behind the email
Because the queries call the same measures as the report, the email and the dashboard can never disagree. Changing a threshold is a one-line edit in the flow.
DAX query: trading partner changes beyond ±15%
EVALUATE
FILTER (
SUMMARIZE (
'OEM forecast Table', 'OEM forecast Table'[Trading Partner],
"Current Forecast", [Current Forecast Demand],
"Previous Forecast", [Previous Forecast Demand],
"Change", ROUND ( [% Chg] * 100, 2 ),
"Diff", [Current Forecast Demand] - [Previous Forecast Demand]
),
[Change] > 15 || [Change] < -15
)
ORDER BY ABS ( [Diff] ) DESC
Catching part numbers that aren't mapped yet
When a customer starts forecasting a part number (SKU) that isn't in the reference table (Part), its demand still counts in the trading partner totals, but it has no internal part number or part family, so it drops out of the part-level pages. The fourth query catches this with a set difference: every SKU in the forecasts, minus every customer part number already in the reference table.
DAX query: unmapped SKUs
EVALUATE
VAR Unmapped =
EXCEPT (
VALUES ( 'OEM forecast Table'[SKU] ),
VALUES ( Part[Customer P/N] )
)
RETURN
SUMMARIZE (
FILTER (
'OEM forecast Table',
'OEM forecast Table'[SKU] IN Unmapped
),
'OEM forecast Table'[SKU],
'OEM forecast Table'[Trading Partner]
)
The email lists each unmapped SKU with its trading partner and links to the reference table workbook. The client's data team fills in the internal part number and part family, and from the next refresh that part's demand rolls up correctly.
Swipe sideways to see the full loop.
The results
The time for one forecast cycle fell from almost five days to less than one day. A cycle here means the elapsed time from downloading the customer forecasts to the planning team knowing what had changed. The reported time saving reflects the project team's account of the implementation. Detailed time-study records have not been published, so the result has not been independently verified.
The workflow also gives planners a change summary, flags unmapped customer part numbers and keeps past forecast versions for review.
- Calmer, proportionate planningPlanners respond to measured changes and fixed rules, then validate the likely cause before changing production or purchasing plans.
- Faster forecast cyclesFrom almost five days to under one day per cycle, with the alert email arriving about an hour after each refresh.
- Trend versus noiseEvery version is kept, so a steady drift stands out from a spike that reverses next time.
- A shared calculation pathThe email and report use the same model and measures. Their results still depend on a successful, sufficiently recent refresh and a successful flow run.
- Unmapped customer parts surfacedCustomer part numbers missing from the reference table are flagged for follow-up. Mapping coverage still depends on the data team maintaining the reference data.
- Designed to extendNew partners, checks, thresholds or schedules can often be added, subject to source-file differences, model changes, testing and capacity constraints.
Evidence, methodology and limitations
KS AI & Cloud Solutions OPC Pvt Ltd published this implementation case study. The client's name, customer names and part identifiers are withheld for confidentiality. This section explains what the case study is based on and what readers should check for their own situation.
Implementation described
The workflow described here uses forecast files from SPS Commerce, Python-based standardisation, SharePoint, Power BI, DAX and Power Automate. These details are the publisher's account of the solution; the client's identity and production records are not published.
Illustrative chart data
The month-by-month quantities and percentage changes in the chart are illustrative examples, not customer production records. The 20% alert threshold is shown as an example rule in this case study; a deployment should set and document thresholds for its own risks and planning process.
Cycle-time outcome
The cycle went from almost five days to less than one day, measured as elapsed time from downloading the forecasts to the planning team knowing what had changed. This is the project team's account. Detailed time-study records have not been published, so the result has not been independently verified.
Demand-change hypotheses
A comparison identifies the size and location of a forecast change, but does not prove its cause. Production-plan changes, demand shifting between months, volatility, lead-time effects, inventory timing and mapping or source-data issues should be tested against customer schedules, purchase orders, inventory, lead times and source files.
Primary technical references
The following Microsoft documentation supports the connector, API permission, licensing-context and query-limit statements in this article. Platform details can change; verify them against the target tenant before implementation.
- Microsoft Learn: Power BI connectorConnector classification, available actions and connector throttling limits.
- Microsoft Learn: Datasets — Execute Queries REST APITenant setting, read/build permissions, supported queries and documented response limits.
- Microsoft Learn: Best practices for the Execute DAX Queries REST APIComparison of the Execute Queries API and the newer Execute DAX Queries API, including capacity requirements.
- Microsoft Learn: Semantic model permissionsWorkspace access and licensing conditions that can affect a deployment.
Technical documentation links checked on 24 October 2026.
Where else this approach works
This approach can also help other manufacturers and businesses that receive regular updates from customers, suppliers or internal systems. The goal is the same: compare each new file with an earlier one, find important changes and give the right team time to respond.
- Automotive and truck suppliersSuppliers receiving rolling forecasts and release schedules from vehicle makers.
- Aerospace and defenceSuppliers tracking rolling demand from prime contractors, part by part.
- Consumer goodsBrands comparing retailer forecasts by customer and SKU.
- Industrial distributionDistributors watching demand shifts by branch, customer and product family.
- Electronics manufacturingContract manufacturers comparing customer build forecasts version by version.
- Any recurring data dropPrice lists, inventory snapshots or order books where the change matters more than the total.
Frequently asked questions
What could explain changes across 30-, 90- and 120-day forecasts?
Possible causes include a revised vehicle production plan, demand moving between months, a forecast swing that may reverse, supplier lead times, stock or order timing, new part numbers, or a file/mapping problem. Check the forecast history, customer schedule, firm orders, stock and source files before treating any cause as confirmed.
How does this solution help investigate forecast changes?
It compares the new forecast with the previous version for the same future periods. It keeps old versions, flags large changes and identifies customer part numbers that are not mapped. Planners still need to check schedules, orders, stock, supplier lead times and source files to confirm the cause.
Why keep old forecast versions?
Old versions help planners tell a steady trend from a one-off swing and show how often each customer changes its forecast. They also support later forecast-accuracy checks when actual orders or shipments are available. Without history, every change can look equally urgent.
How often can it run?
The workflow can be scheduled around each customer's forecast cycle, subject to Microsoft refresh, connector, licensing and flow limits. In this design, the refresh and email run on a schedule. The alert is not instant unless the file collection and automation are built for immediate updates.
Who keeps the part mapping up to date?
The client's data team. The alert email lists customer part numbers that are missing from the reference table. The team adds the matching internal part number and part family. Power BI picks up the change at the next refresh.
Can Power Automate read data from a Power BI report?
Yes. Power Automate can run a query against a published Power BI data model and return the matching rows. The flow can then put those rows into an email, table or file. The required setup and permissions must be checked for your environment.
Do we need Power BI Premium for this?
There is no single yes/no answer for every company. The Power BI connector is listed as Standard in Power Automate, but the query API, workspace, user access and sharing rules still affect licensing. Before rollout, have the Microsoft 365 or Power BI administrator confirm the licences and permissions for the exact workspace and users. The required tenant setting must also be enabled.
What happens if a customer's file is missing?
Before a refresh, our team sends the data team a file check. It lists how many files arrived for each customer, plus each file's name and size. A zero count or a file that is much smaller than usual can be checked before the report refreshes. A late file is picked up by the next scheduled refresh if it arrives in time.
Will this work with our forecast source or ERP exports?
Usually, yes—if the source can provide the forecast as a file or through an API. The collection step would change to fit that source. The comparison model, report and alert process may stay similar, but they still need to be tested with the new data.
Still comparing forecasts by hand?
KS AI & Cloud Solutions builds Power BI, Power Automate and Microsoft Fabric solutions that turn recurring data drops into decisions. Tell us which forecasts you receive and how often, and we'll show you what they look like automated.
Our team includes Microsoft-certified Power BI practitioners. Meet the team.