Skip to content
OrtmannConsulting
Back to all projects

Service desk, construction chemicals

Four systems, one screen — correcting contact data during the call

The agent sees who is calling, assembled from four systems. Corrections sit as an overlay on top, without anything being changed in SAP or Salesforce.

Year
2026
Services
Communications · Automation
Area
Contact centre
Role
In-house, employed

Delivered in an employed role for an internal department, not under an external consulting contract. The organisation is not named.

4 → 1Source systems on one screen
0Changes written to SAP or Salesforcean overlay, not a second master database

The situation

A read-only “customer view” already displayed caller data inside the agent’s workspace. Its lookup logic, however, was scattered across several source-specific queries, and it could only display — never write. There was no single place to create, search, correct or deduplicate a contact.

What the project folder does not say: what agents actually did when caller data was wrong or missing — corrected it in Salesforce, kept a private list, or ignored it. No before-state measurement exists anywhere.

The approach

A Flask application owning its own contact schema and a central resolution endpoint. Given a phone number it first normalises to international E.164 format and checks its own table across three phone slots. If nothing is found, it queries the four upstream systems in parallel and returns the first hit in a fixed priority order: SAP, then Salesforce, then HubSpot, then the internal address book.

It gets interesting when a managed contact is found. The application then does not return its own record. It fetches the live records from the linked upstream systems and lays the managed values on top field by field: a managed value wins, an empty managed field falls through to the source. Every field in the response carries a marker saying where its value came from, so the interface can distinguish “from Salesforce” from “corrected by an agent”.

Writing follows a deliberate order: search first, create second. Before anyone may create a contact, the application searches all sources for something to link to; a free-standing contact is only allowed when nothing matches. Every changed field writes its own audit row, and updates use a version column so two agents cannot silently overwrite one another.

Where it could have gone the other way

The managed contacts are an overlay, not a new master database.

A managed contact stores only the fields somebody actually changed. Every other field stays empty and is resolved live from the source system on every read. In the schema this is visible in the fact that all identity columns are optional, with a check constraint forcing a full identity only for contacts with no upstream link at all.

It could have gone the other way: copy the source records into the new database and let agents edit a local master. That would have made reads trivial and removed the dependency on four live systems at call time.

It was rejected because it puts the new application in competition with SAP and Salesforce over who owns the truth. The price paid instead is real: every read has to fan out to live sources and merge, and per-field provenance has to be carried through the whole stack.

The result

Around 5,700 lines across roughly 31 files, 18 endpoints, four connected upstream systems, six tables in a new schema. The older customer view was not rewritten — it got a 165-line adapter that calls the new resolver and flattens the response back into the shape its templates already expect. Switchable via an environment variable; rollback is removing that variable.

Deliberately not automated: whether a caller is an existing or a new contact, which record to link to, and whether to override a duplicate warning are all decided by the agent. The system gates and warns — it never merges silently. Phone and email collisions block hard; name similarity produces an overridable warning.

Stated openly: there is no automated test suite; the only defined test is a manual parity check across 100 phone numbers before the feature flag goes on. Duplicates are prevented, not repaired — merging two existing contacts is explicitly out of scope for the first version. And the Salesforce export does not exist yet; it is planned one-way and as a dry run first.

Stack

  • Python / Flask
  • Azure SQL
  • Databricks SQL
  • HubSpot API
  • Twilio Flex
  • Redis

More projects

Group customer service, construction chemicals

2026
11Countries on one platform

One contact centre for eleven countries — one platform, not eleven islands

Customer service across eleven countries over voice and SMS, with data from SAP, Salesforce and the product system surfaced directly in the agent workspace. Country differences are configuration, not separate installations.

  • Twilio Flex
  • Twilio TaskRouter
  • Twilio Studio
  • SAP

Group compliance, construction chemicals

2026
10,872Documents generated

10,872 EU declarations of conformity, not copy-paste

New EU packaging regulation required declarations of conformity in 12 languages for around 900 packaging materials. Instead of filling them in one by one, a pipeline generates and files them in a single run.

  • Python
  • docxtpl / Jinja2
  • Microsoft Word COM
  • Microsoft Graph API

Customer service, construction chemicals

2026
114 → 18Widgets in the call flow

From a 114-widget phone menu to a voice assistant

Callers say what they need in their own words instead of tapping through three menu levels. The language model is never allowed to name a destination — it picks from a list, and the phone system dials.

  • TypeScript / Node.js
  • Azure OpenAI
  • Twilio ConversationRelay
  • Azure App Service

A similar process at your company?

30 minutes, free, no sales pitch. You describe what is costing you time — I tell you honestly whether automation is worth it.