Code Agency
5 min read

From timesheet to invoice in Odoo: billing transparent to the minute

We bill seven minutes when we work seven minutes. The timesheet-to-invoice pipeline in Odoo — billable rules, approval flows, and the client-facing detail line that makes the number defensible.

"Where did these eleven hours come from?" is the question that ends time-and-materials relationships. Not because the hours were wrong — usually they weren't — but because the client had no way to check before the invoice landed. Odoo's timesheet-to-invoice pipeline exists to make that question answerable in the app, not in a Friday-afternoon phone call. Most implementations wire up timesheets and wire up invoicing; fewer wire up the part in between that decides what crosses from one to the other, and that gap is where trust in the number goes to die.

The timesheet is the source document, not a formality

Every billable hour in Odoo starts as a timesheet line against a task, tied to a project and, through the project, to a sales order line. That chain is the whole mechanism: it's what lets Odoo answer "how many hours have we logged against this order" without anyone exporting to a spreadsheet. Teams that treat timesheets as an HR compliance exercise — filled in Friday afternoon, three days late, rounded to the nearest hour — get exactly the invoice quality that process deserves. Teams that log at the task, same day, in real increments get a pipeline that runs itself.

The discipline that actually matters is granularity. Rounding every entry to 0.5h "to keep it simple" doesn't simplify anything — it just moves the imprecision from the timesheet into the invoice, where the client can see it and you can't explain it. Log seven minutes as seven minutes. The invoice line will say so, and that specificity is what makes the total believable.

Billable rules: not every hour reaches the invoice

A sales order line in Odoo carries an invoicing policy, and for services that policy is usually "based on delivered quantity" — the quantity being timesheet hours, not a manual estimate. That single setting is what turns logged time into an invoiceable quantity automatically, with no one running a report and copying numbers across.

But "automatically invoiceable" and "should be invoiced" are different questions, and conflating them is the most common billing mistake we see:

  • Internal meetings and admin time get their own non-billable project, never a task under the client's order — so they can't accidentally leak onto a line.
  • Rework on our own mistakes gets logged against the same task for internal visibility, then explicitly marked non-billable before invoicing, not silently dropped — the client should see we track it even where we absorb the cost.
  • Scope overruns get flagged at the task level the moment they're visible, not discovered at invoice time. A timesheet entry is not a change-order conversation; it's a symptom that one is needed.

Configuring this correctly at project setup — which tasks are billable, which sales order line each maps to, what the default invoicing policy is — is ten minutes of work that prevents the alternative: someone in finance manually deciding, per line, what "feels right" to bill. That's not a billing process, that's a guess with a due date.

Approval flow: a checkpoint that doesn't slow billing down

Auto-invoicing every logged hour the moment it's entered sounds efficient and is how uncontested billing disputes start. The fix isn't removing automation, it's putting one human checkpoint before the invoice generates — the project lead or account manager reviews the week's timesheet-to-invoice draft, catches the entry logged against the wrong task, confirms the scope-overrun hours are expected, and approves.

We keep that review to a defined cadence — weekly, tied to the client's own billing cycle — rather than ad hoc, so it's a five-minute habit instead of a fire drill at month-end. The approval step is cheap precisely because everything upstream of it (the billable rules, the task-to-order mapping) already did the sorting. The human is checking judgment calls, not re-deriving the whole invoice from raw hours.

The client-facing detail line

This is the part that actually earns trust, and it's the part most implementations skip because it looks like extra work: the invoice line description should say what was done, not just "consulting services — 7.5h." Odoo lets the timesheet description flow through to the invoice line, task by task, so the client reading the PDF sees "Bugfix: checkout redirect on mobile — 1.2h" next to the number, not an opaque total they have to take on faith.

That level of detail is also the fastest way to kill a billing dispute before it starts. A client who can see the seven-minute entry for the Slack thread they remember has no follow-up question. A client who sees "Development — 32h" for the month has several, and every one of them costs you a day of someone's attention to answer after the fact.

Where this earns its keep

None of this is exotic Odoo configuration — invoicing policies, project-to-sales-order links, and timesheet descriptions are stock features. The value is entirely in the discipline of wiring them together deliberately: log real time against the right task, decide billability at the task level instead of at invoice time, put one review step before the client sees a number, and let the detail line do the explaining. It's the same principle we apply across every Odoo implementation we deliver — surfaced early in the fit-gap analysis, the same way we treat recurring billing and reconciliation automation: the finance process is only as trustworthy as the operational process feeding it.

Bill seven minutes when you work seven minutes. Clients don't dispute precision — they dispute the absence of it.

Want us to publish something specific?

Tell us what you'd like to read and we'll add it to our writing queue.

Get the next one in your inbox

New articles, videos and the occasional engineering note — a short mail when there’s something worth reading, nothing else.