The 40-minute Friday report nobody wanted to own
A finance team was losing four hours every Friday to a manual export. Here is exactly how we cut it to four minutes, and the part that mattered more than the automation.
2 min read
Every Friday afternoon, one person on a mid-sized finance team in Kathmandu spent about four hours assembling the same weekly report. They had done it for three years. Nobody else in the office could do it, which meant nobody else could cover for them, which meant it was a single point of failure disguised as a routine task.
The actual report was not complicated. Seven numbers, one comparison against last week, and a short written summary. What made it slow was that the numbers lived in three places, and none of them talked to each other.
What the process actually looked like
When I start an engagement I write down the current process before I touch anything, because the current process is the specification. Even when it’s ugly, it encodes decisions somebody made for a reason.
- 01
Export from the billing system
A CSV pulled by hand, filtered to the week, columns deleted and reordered. Roughly 25 minutes.
- 02
Export from the accounting package
A second CSV, different column names, different date format, one extra week of rows that always needed trimming. Roughly 30 minutes.
- 03
Paste into a spreadsheet
SUMIFS chains across three tabs, then manual adjustment for two known data-quality issues. Roughly 60 minutes.
- 04
Write the summary
Read the numbers, interpret them, type four sentences. Roughly 40 minutes.
Notice that the work is about fifteen minutes. The other three hours and forty-five minutes is re-establishing context every week.
The parts I refused to automate
This is the part most automation proposals skip.
I automated the mechanical work — the exports, the join, the aggregation — and left a small, clearly labelled slot for the human input that requires judgement. The human now spends their forty minutes reading the output instead of producing it. Same time cost, completely different value.
What it runs on
Nothing exotic. That was a deliberate constraint, because the person inheriting this in a year should not need to learn a platform.
- Python for the extraction and transformation
- SQLite on disk as the intermediate store — a file, not a server
- cron on the existing Linux box that already runs their other jobs
- A static HTML report generated at the end, readable on a phone
from pathlib import Path
import sqlite3
DB = Path(__file__).parent / "weekly.db"
def upsert_week(conn, week, rows):
conn.executemany(
"""
INSERT INTO weekly_facts (week, account, amount)
VALUES (?, ?, ?)
ON CONFLICT(week, account) DO UPDATE SET amount = excluded.amount
""",
[(week, r["account"], r["amount"]) for r in rows],
)
conn.commit()
The database is a single file. If it is ever deleted the next run rebuilds it from source, because source systems remain the truth. Nothing important lives only in the derived store.
The uncomfortable finding
Three months in, the finance lead told me the more valuable change had nothing to do with the script.
They had started reviewing the numbers during the week instead of only producing the report on Friday. The four hours had been a forcing function that structured their entire week, and removing it changed when problems got noticed.
Before
- One person owns the process end to end
- Errors surface on Friday afternoon
- The report is the deliverable
- Understanding happens once a week, under time pressure
After
- Anyone can run it; the steps are documented
- Errors surface on the same day as the data
- The summary is the deliverable
- Understanding happens continuously, without the deadline
If I had been asked to define success as “report generation time”, I would have hit the target and missed the point.
What I would do differently
- Ask who reads the report before asking how it’s made. Half the columns nobody read. We deleted them in week one.
- Write the runbook on day one, not week nine. I left documentation until the end and it was the least accurate part.
- Time-box the manual slot explicitly. “Forty minutes of judgement” needs a name or it gets absorbed and quietly deleted.