From raw export to numbers you can defend
Binzagr's proof of value, told with Binzagr's own data: the files as they arrived, how we cleaned them without inventing anything, what we had to simulate, and the anomalies we found on the way.
As received
Eight monthly warehouse exports, Feb to Sep 2026, one block each. Every file also carried the whole first day of the next month: 65,141 rows sent twice, shown in red.
Cleaned
Duplicates removed only where proven at raw-text level; nothing estimated. Every surviving row keeps its file and line number: 4,539,533 rows.
Simulated
Around the scans sits paid time the scans cannot see: 58.9% of paid hours on the payroll head count. That layer is modelled from law, research and stated assumptions, and labelled Simulated.
What Binzagr sent
Twenty-two files, received in October 2026: eight months of the Jeddah warehouse log, Riyadh van sales from 1 March to 20 October with the customer, product and salesman masters, and four mapping files that explain Binzagr's WMS codes. The originals were never edited; every step below works on copies.
Every dataset, as it arrived
Rows as received on a log scale, so a 28-row lookup and a 4.6-million-row log fit on one line. The blue tick marks the row count after cleaning.
Show data
What the raw files actually look like
Real lines, copied character for character from the files Binzagr sent. Only the badge logins are masked. Highlights mark what had to be dealt with.
How we cleaned it
Cleaning here means fixing what the export broke and flagging what looks wrong, without estimating a single value. Anything inferred or modelled lives in chapter 3, under its own label.
The rules every change had to follow
Nothing is filled, smoothed, imputed or inferred in the cleaned layer.
The only rows removed anywhere are second copies proven at raw-text level.
1900 dates and quantities that are really pallet ids become empty, always with a flag.
Badge sharing, identical rows, negative balances and zero-value lines are marked, not changed.
Each cleaned row points back to its source file and line, or its spreadsheet row.
Contact, bank and tax-id columns are dropped; WMS user names are never stored.
Seven steps from export to model-ready tables
Each step runs in order and is re-checked against the raw files by an independent test, so a mistake in one step cannot hide behind the next.
How each problem was solved, and proven
49 smoke tests, written against the raw files
The tests do not reuse pipeline code. They read raw CSV text, raw spreadsheet cells and Binzagr's mapping files, and re-derive each result independently. Select a tile to see what it checks.
One warehouse scan, before and after
The same record as Binzagr exported it and as it sits in the cleaned tables: typed, flagged where needed, joined to Binzagr's own mappings, tied to a person and a work session, and traceable back to its line.
Where the van-sales customers are, and how much they buy
What we had to simulate
Some numbers the proof of value needs are in no file Binzagr has sent yet: what people are paid, when they are on shift, what each client is charged. We filled each gap with a stated model or a published figure, never silently, and every table says which kind of number it holds.
Five labels, on every table and every figure
24 things only Binzagr can give us, and what stands in for each today
Priority 1 items block the Jeddah P&L comparison. Each arrival replaces a simulated table one for one.
What one warehouse operative costs a month
No pay data has arrived yet, so the monthly cost of an expatriate operative is built from Saudi labour law, government fees, published wages and job postings. Each component has a low, base and high value; the Monte Carlo further down draws from all of them.
Sources include GASTAT wage survey, GOSI rates, expat levy and iqama fees, Labour Law articles 84, 98, 101, 107 and 109, and Jeddah and Riyadh job postings.
How a shift turns into paid, observed and earned hours
How long a task should take, from Binzagr's own shifts
For each activity and line size (cases per line), the standard is the median of the badge-month average cycle times, from badge-months with at least 30 such scans. Line size matters: a one-case pick takes about two and a half minutes, an 11 to 25 case pick almost five.
Seconds per line, idle cap 30 minutes. Lenient (P60) and tight (P40) variants feed the Monte Carlo.
Three ways to count who is paid
Scans show who worked, not who was paid. Binzagr's user list shows who holds a login, not who turns up. So paid time is computed three ways, and the middle one is the base: payroll-confirmed people are paid every working day from their first to their last scan.
On that base, 58.9% of paid hours have no scan behind them. No saving is claimed on that time; attendance by payroll number is what can explain it.
The saving comes from Binzagr's own best shifts, not an outside standard
For every full shift (30 scans or more over at least 4 hours), productivity is earned standard hours divided by observed hours. The target is what the top quarter of shifts in the same role already achieves; the gap is captured at 70%. Move the sliders to see how the answer changes.
Annual figures. The base case (top quarter, 70%) is the SAR 639,485 used in the value roll-up. Wage assumptions move it far less than these two choices do.
5,000 versions of the answer
Every uncertain input is drawn from a triangular low-base-high distribution, the standard variant, idle cap and paid-time basis are drawn as well, and the model runs again. Each dot below is one of the 5,000 real draws.
23,589 work sessions, scored by rules and an anomaly model
Each point is one person's work session, placed by its length, its scan rate and an IsolationForest anomaly score (300 trees). Rules then add what the model cannot know: sessions longer than the 12-hour legal limit, two badges of one person active at once, site switches within 2 minutes. Drag to turn it.
Ageing rebuilt from one balance snapshot
Binzagr's customer master holds one outstanding balance per customer, as of 20 Oct 2026, with no invoice behind it. Assuming payments clear the oldest invoices first, each balance is laid over the customer's most recent van-sales invoices, and each invoice's due date comes from its payment term.
The animation replays that for one real customer (code masked). Across all 1,616 credit customers with a balance, SAR 336,231 cannot be matched to any invoice in the window.
Events checked against what the data shows
Ramadan, both Eids, Founding Day and National Day come from official announcements, then are checked against the warehouse log: it closes on 21 to 23 March, 26 to 28 May and 23 September, and runs about 13% above its normal weekday level during Ramadan.
Three cases, and one honest caution
Conservative, base and stretch combine the cost parameters, the paid-time basis, the standard, the target and the capture rate.
The anomalies we raised
Every anomaly is sized, given a severity by what it puts at risk, and turned into one question for Binzagr. Some were fixed in cleaning, some are flagged and kept, and some only Binzagr can answer.
Six inputs from Binzagr replace the largest assumptions
Each one swaps a simulated table for an actual one, one for one, and upgrades every figure that depends on it.
Replaces the cost-recovery P&L that earns 6.5% by construction; makes labour share of revenue a real number.
Explains the 58.9% of paid hours with no scan, and settles badge sharing case by case.
Replaces the researched wage build-up; every SAR figure in the warehouse model scales with it.
Replaces cost-recovery rates with real prices; shows which clients cover their case-picking labour.
Names, temperature zones and the 2100-01 to 2100-07 move, so sites can be benchmarked fairly.
The quickest check of the whole labour model, in Binzagr's own unit.