D-02
OTIF / Customer Service
The weekly service review, as one pattern: a master-detail wireframe on top of a single order-line fulfillment fact. Every tile is a projection of the same components, so switching OTIF definitions changes a SELECT, not the dashboard. This page carries the wireframe, the dimensional design, and the source tables — the definition itself, switch by switch, lives in the OTIF entry of the KPI Dictionary.
Last verified August 2026.
What it answers
Two jobs, one instrument. The weekly service review: is the service promise being kept, where is it slipping, and what changed since last week. And the retail-compliance defense: when a scorecard customer disputes a month, the path from their number to your order lines has to be minutes, not a data pull. Both jobs are the same drill — from "OTIF dipped to 91%" to "these 40 order lines, at this DC, for this customer."
One prerequisite, stated bluntly: a dashboard displays a definition — it doesn't create one. Before this gets built, the six switches of the OTIF definition — grain, date basis, ship vs arrival, first attempt vs cumulative, tolerance, exclusions — must already be set. That conversation is the switchboard, and it comes first. Build the dashboard before the definition and every review becomes an argument about the number instead of the operation.
The wireframe
This is the master-detail layout — pattern 03 in the layout reference, the workhorse for going from signal to SKU. The trend is interactive: clicking a month filters the cuts and the detail table below it, so the review walks the same path every week.
OTIF customer service dashboard wireframe: four KPI tiles, OTIF trend against target, cuts by customer and ship-from site, failing-lines table with failure-reason context panel
What each region reads from the schema below:
- KPI row — four
count_ifratios over the same fact — each tile is annotated with its formula, because a tile whose formula can't be stated is a tile nobody should trust. Change a switch setting and the SELECT changes; the dashboard doesn't. - Trend vs target — the joint pass flag aggregated by promise month from the role-playing
dim_date— which date role anchors it is the date-basis switch, stated on the axis label. The target line is the number the business agreed to, drawn on the chart, not implied. - Cuts — the same joint flag grouped by
dim_customeranddim_ship_from— the two questions every review asks next: who is affected, and which site owns it. - Failing lines — the fact's own grain, filtered to failures — the degenerate order and line numbers carry the drill all the way to the document in the ERP.
- Failure reason — late vs short vs both, derived from the same
on_timeandin_fullflags the tiles use — the panel that turns a score into an action.
The star schema underneath
This is the same fact the OTIF Dictionary entry lands — one fct_order_line_fulfillment at order-line grain carrying the components: requested / first-confirmed / current promise dates, first-ship and last-ship (and, where captured, arrival) dates, ordered / shipped / canceled quantities, the delivery count, and a first-attempt-complete flag. No OTIF column anywhere. The full bronze → silver → gold walk is in the landing pattern.
Grain one row per order line
Stored components
- requested / first_confirmed / current_promise dates
- first_ship / last_ship (arrival, where captured) dates
- ordered / shipped / canceled quantities
- delivery_count
- first_attempt_complete flag
Foreign keys
- → dim_customer
- → dim_product
- → dim_ship_from
- → dim_date
- sold_to
- channel
- compliance_program
The cut the review always reaches for — and where scorecard customers are flagged.
- site
- dc
- region
Warehouse accountability — the ship-basis view cuts here.
- order_number
- line_number
Degenerate dimensions on the fact — the drill path from any tile to the exact line.
- item
- category
- franchise
Conformed with the rest of the gold layer, so service cuts line up with inventory cuts.
- requested
- promised
- shipped
One date dimension, three roles — which role anchors the trend is the date-basis switch.
Where the snapshot fact on the inventory pattern photographs a population on a schedule, this fact accumulates: one row per order line, its dates and quantities filling in as the line moves through confirmation, shipping, and delivery. Together the two patterns are the two fundamental Kimball fact types every supply chain gold layer is built from.
Measures & additivity
Every tile is a count_if over the fact — all non-additive, all recomputed at whatever grain the view needs:
| Measure | Formula | Additivity | Note |
|---|---|---|---|
| otif_pct | count_if(on_time AND in_full) / count(*) | Non-additive | The joint test computed per line and aggregated as a flag — never on_time_pct × in_full_pct. |
| on_time_pct | count_if(on_time) / count(*) | Non-additive | on_time compares a ship or arrival date to the promise date the date-basis switch selects. |
| in_full_pct | count_if(in_full) / count(*) | Non-additive | shipped quantity against ordered less canceled — first-attempt or cumulative per the switch. |
| split_line_pct | count_if(delivery_count > 1) / count(*) | Non-additive | Published next to OTIF so first-attempt scoring is honest about how often lines split. |
| rebooking_rate | count_if(current_promise_date <> first_confirmed_date) / count(*) | Non-additive | The integrity companion — if renegotiated dates are honored, show how often dates move. |
Each measure moves with the switches it depends on: on_time with date basis and ship vs arrival and tolerance, in_full with first attempt vs cumulative and exclusions, and the whole denominator with grain. That is the payoff of storing components: the customer's scorecard configuration and your internal view are two SELECTs over one fact, reconciled by construction.
Sourcing it from SAP
Order lines from VBAK / VBAP carry the requested date, ordered quantity, and rejection status; the first-confirmed promise comes from the VBEP schedule lines; deliveries and actual goods issue from LIKP / LIPS — aggregated to the order line before comparing, because every delivery split is its own row — and KNA1 feeds dim_customer. The switch-by-switch Databricks SQL lives on the OTIF entry →
Sourcing it from JD Edwards
Sales lines from F4211 plus the F42119 history — lines move at sales update, so the union is mandatory — with headers in F4201. JDE keeps all three promise dates on the line, which is what makes the rebooking rate computable at all; the F42199 change ledger records every date edit, F4209 the held orders, and F4215 / F4941 / F4942 carry the arrival-side dates. The switch-by-switch Databricks SQL lives on the OTIF entry →
Sourcing it from Dynamics 365
Promises on SalesTable / SalesLine (requested vs confirmed as a column swap), posted shipments in the packing-slip journal CustPackingSlipJour and invoices in CustInvoiceJour / CustInvoiceTrans, with warehouse-true ship timestamps in WHSShipmentTable and WHSLoadTable / WHSLoadLine tying loads back to source lines — company pinned and sentinel dates NULL-wrapped throughout. The switch-by-switch Databricks SQL lives on the OTIF entry →
Sourcing it from Infor M3
Order lines and promises in OOHEAD / OOLINE, the delivery trail in MHDISH / MHDISL (one row per order line per delivery — the split-shipment record), and the invoiced ledger in ODHEAD / ODLINE — CONO pinned in every join, status ladders deciding what counts as canceled. The switch-by-switch Databricks SQL lives on the OTIF entry →
Running the workshop
Two conversations, in a fixed order:
- The switchboard conversation first. Walk the six switches with the business and write the settings down. This is the definition the dashboard will display — and if a scorecard customer exists, their configuration is a second view over the same fact, agreed in the same meeting.
- Then the layout conversation. Agree the target line (drawn on the trend, not implied), and which cut leads — customer for a compliance-driven business, ship-from site for an operations-driven one. The wireframe above is the starting point to react to, not a spec to accept.
And the anti-patterns to name out loud before anyone builds: storing the ratio (an OTIF column in a table is a definition frozen at build time), measuring against the current promise (every reschedule launders lateness — the date-basis switch), and dashboards with no path to the failing line — a service score nobody can drill into is a number, not an instrument.