The implementation is done. The consultants closed the project. On Monday, a sales rep opens the same spreadsheet they used before.
The usual reaction is to ban the spreadsheet. A more useful one is to treat it as the most honest requirements document you have. Somebody keeps maintaining that file because it solves a problem the new CRM or ERP does not. This post shows a small, repeatable way to read it.
Step 1: get a copy and profile it
Ask for the actual file, not a description of it. Then look at what is really in it. A few lines of pandas are enough:
import pandas as pd df = pd.read_excel("shadow.xlsx", sheet_name=None) # every tab for tab, data in df.items(): print(f"\n== {tab}: {len(data)} rows") profile = pd.DataFrame({ "filled_pct": (data.notna().mean() * 100).round(1), "distinct": data.nunique(), "example": data.apply(lambda c: c.dropna().iloc[0] if c.notna().any() else None), }) print(profile.sort_values("filled_pct", ascending=False)) Columns that are almost always filled are the ones the person actually needs. Columns with few distinct values are usually statuses or categories the system may already have under another name.
Step 2: map every column to the system
Build a simple table with one row per column:
| Spreadsheet column | Exists in the system? | Where | Why they still use the sheet |
|---|---|---|---|
| Customer | Yes | Account | Faster to type than to search |
| Expected delivery | Partly | Order, but filled by operations | Rep cannot see it, has to ask |
| Paid? | Yes | ERP invoice status | Rep has no access to that screen |
| Notes for the boss | No | none | Not a system problem, a reporting habit |
The values above are an example of the format, not a real company. The last column is the one that matters. It usually falls into one of four buckets:
- Too many steps. The field exists, but entering it takes longer than the spreadsheet.
- Not visible. The data exists, but this role cannot see it, so they ask someone and write it down.
- Bad data. The migrated data was never cleaned, so the person keeps their own version.
- Missing. The system really does not cover it.
Step 3: turn buckets into backlog items
Each bucket leads to a different kind of work:
- Too many steps: simplify the layout, remove fields nobody uses, add defaults. This is often a small change.
- Not visible: review permissions and page layouts so the role can see the order, invoice or payment status it needs.
- Bad data: schedule the cleanup that was "left for later", with an owner and a date.
- Missing: this is the only bucket that may justify new customization, and it should go through the same review as any other change.
Notice that only one of the four buckets is about building something new. Most of the work is removing friction.
Step 4: sit next to the person
None of this replaces a conversation. Three questions are enough to start: show me what you do here, what is missing in the system, and what takes you longer since we implemented it. Often that person already said it during the project and nobody followed up.
Where a single platform helps
When the sales team already works in Salesforce, having the ERP native to the same org removes a lot of the not visible bucket: the rep can check the order, invoice or payment status from the account, based on their permissions. That is why we build EGA Futura ERP natively on Salesforce. It does not remove the other three buckets. If entering an order is painful, someone will still find a way around it.
I wrote the business side of this, in Spanish, as why your team is still in Excel after implementing an ERP or CRM.
Juan Manuel Garrido, founder of EGA Futura.