Every data quality team has a version of this task: “these 400 accounts need the same field corrected”. In SAP that means opening the record, changing the field, saving, and doing it again 399 times. It is slow, it is boring, and — this is the part that matters — it produces new errors while you fix the old ones. After the second afternoon of this I wrote a tool. This is how it works and what I would tell someone who wants to build the same thing.
The options I did not take
- LSMW, BAPIs, mass-maintenance transactions. The right tools when you have them. We did not have access to them for these objects, and getting it was a project in itself.
- RPA (UiPath and friends). They automate exactly this, but a licence and a bot server for one team’s occasional batches was out of proportion.
- VBS macros recorded from the SAP GUI. SAP GUI can record your clicks as a script. Great for a demo, terrible in practice: no validation, no error handling, and the moment a screen changes the recording breaks.
What I wanted was in between: no new systems, no licences, but real code with tests, validation and a log.
SAP GUI Scripting, driven from Python
SAP GUI Scripting is an automation interface built into the SAP GUI for Windows. When your admins enable it (server-side parameter sapgui/user_scripting, plus the client option), the running GUI exposes a COM object you can control: sessions, windows, fields, buttons, grids. Anything a user can click, a script can click — with the same permissions as the logged-in user, which is exactly what you want for auditability.
From Python the only dependency is pywin32. A minimal, generic example — open a transaction, fill a field, press Enter, read the status bar:
import win32com.client
sap = win32com.client.GetObject("SAPGUI").GetScriptingEngine
session = sap.Children(0).Children(0) # first connection, first session
session.findById("wnd[0]/tbar[0]/okcd").text = "/nXD03" # transaction code
session.findById("wnd[0]").sendVKey(0) # Enter
session.findById("wnd[0]/usr/ctxtRF02D-KUNNR").text = "0000123456"
session.findById("wnd[0]").sendVKey(0)
status = session.findById("wnd[0]/sbar").text # "Customer 123456 displayed" or an error
print(status)
The findById paths come from the GUI’s own recorder or from the scripting tracker; you read them once and keep them in a small map. That is all the “magic” there is. The real work is everything around it.
What makes it usable by other people
The first version was a script only I could run. The version other departments use has four things the script did not:
- Excel in, Excel out. A template with one row per record: key, field, new value. The tool reads it, executes it, and writes the outcome next to each row (“changed”, “skipped: already had that value”, “error: record locked”). Nobody has to read a console.
- Dry-run first. Same code path, but it stops before saving: it navigates, reads the current value and reports what would change. Every batch runs in dry-run before it runs for real, and the report is what the requester signs off on.
- Per-row validation against the GUI. Spreadsheets go stale. Before writing, the tool compares the value on screen with the “old value” column; if they differ, the row is skipped and flagged. This single check has prevented more damage than any other feature.
- A change log. Before/after value, record key, user, timestamp, batch id. It makes the batch auditable, and it makes it reversible: a batch can be replayed backwards.
Plus the boring but decisive part: error messages in plain language, because the user is a colleague from Revenue or Finance, not a developer.
What it taught me about data quality
- Automation without validation is a faster way to make mistakes. The clicking is 20 % of the code; checks, dry-run and logging are the other 80 %.
- Do not automate what you cannot undo. The log existed before the first real batch. If a change cannot be reverted, it goes through a human.
- The template is the interface. Most support requests were about the spreadsheet, not the tool. Clear column names and a “notes” column saved hours.
- Keep permissions honest. Running under the user’s own session means the tool can only do what that person can do. That is a feature.
When this approach makes sense — and when it does not
It makes sense for occasional, medium-sized batches (tens to a few thousand records) on objects you do not have a proper mass-maintenance path for, in a team without an RPA platform. It does not make sense for high-volume recurring loads (use the proper integration), for changes that touch financial postings (get the right transaction and approvals), or if the GUI screens change often (the paths will drift).
If you are in that middle ground, a few hundred lines of Python and a spreadsheet template will save your team real afternoons — as long as you build the dry-run and the log before you build the clicks.