BFBambooForge Labs

Approval Workflow for Odoo Community

Multi-step approval workflow for Odoo Community: who says yes, in what order, how many of them, and a decision trail nobody can edit.

Buy on the Odoo Apps StoreOpen the live demoHuman Resources€174Community & Enterprise

Available for Odoo 16.0, Odoo 17.0, Odoo 18.0, Odoo 19.0. Technical name bambooforge_approvals.

Odoo 16.0Odoo 17.0Odoo 18.0Odoo 19.0
Full walkthrough on a live Odoo 19.0 database, with subtitles. It ends with what this app deliberately does not do.

Approval Workflow for Odoo Community

Odoo Community has no approvals app. What people do instead is an email thread — and six weeks later nobody can say who agreed to the fifteen thousand, or whether the number they agreed to is the number that was spent.

This is multi-step approvals for Community, built so that the trail it leaves is worth reading a year later.

A type, and the ladder under it

Approvals › Configuration › Approval Types.

A type is a kind of thing that needs signing off — spending, time off, a new starter, access to a system. It says what its form asks for (a period, an amount, a quantity, a contact, a reference, an attachment), and carries the ladder of approvers underneath.

A step is a group, some named people, the requester's manager, or all three at once — plus how many of them have to say yes. Steps run in order: the second opens when the first is satisfied. One refusal at any step refuses the request, with a reason that the person who raised it reads.

Two worked examples are installed, built on groups every database already has, so they do something on the first run.

Nobody approves their own request

Not by being in the approving group, not by being their own manager, not through a delegation, and not by being added by hand afterwards. The requester is removed from every step's approvers when the ladder is built, and the same rule is repeated as a database constraint — because a rule enforced only where the buttons are is a rule that holds until somebody imports a file.

If removing the requester leaves a step with nobody on it, the request cannot be submitted and says so. That is better than the alternative, which is a request that sits in a queue nobody can clear.

The ladder is frozen when it is submitted

Each step is copied onto the request at submission, with the people it resolved to at that moment. A reorganisation, somebody leaving the approving group, or an administrator editing the type afterwards does not rewrite who was asked.

An approval trail that changes retrospectively is not a trail. It is a report of what the org chart looks like today.

What was approved cannot change under the approval

Once anybody has said yes, the amount, the currency, the dates, the quantity, the contact and the reference are locked. Change them and the approval that was granted quietly becomes an approval of something else — which is the single most common way one of these systems turns out to have been decorative.

To change them, withdraw the request and raise it again. That costs somebody thirty seconds and leaves a trail that is true.

The decision log is read-only to everybody

Including the approvers. Nobody has write access to bf.approval.entry at all; every change goes through the workflow, which writes it under sudo.

An approval log that approvers can edit answers "who agreed to this?" with whatever suits today.

Each decision records who was asked and who actually clicked — they differ when somebody was standing in.

Delegation ends, and does not pass on

Approvals › Delegation. Hand your approvals to somebody while you are away. It has an end date, because a delegation without one is how somebody is still signing things off two years after the holiday.

It cannot be chained. If B is covering for A and then B goes away and hands it to C, C ends up with A's say — and nobody chose C. That is refused when it is set up, not discovered afterwards.

A stand-in never inherits the right to approve their own request either.

Confidential types

A confidential type is seen only by the person who raised it, the people it is waiting on, and an approval administrator. Use it for anything about money or people.

A confidential type cannot be delegated, and that is a deliberate pairing rather than a missing feature: lending somebody your say would lend them the reading of it, to somebody nobody chose.

It chases

Give a type a number of days and any step that has been waiting longer puts an activity on everybody who can clear it — an activity, not an email, because an activity is the only thing in Odoo that shows up as a number somebody has to clear.

An approval queue nobody is reminded of is a drawer.

Who can do what

  • Approvals › User — everybody has it. Raise requests, act on the ones waiting on you, arrange your own cover.

  • Approvals › Administrator — defines the types and the steps, sees every request including confidential ones, and can withdraw one on somebody's behalf.

An administrator cannot edit a decision. Nobody can.

Nothing from Enterprise

The module depends on mail and nothing else. hr is used if it happens to be installed, to find who somebody reports to.

Without it — and for anybody at the top of the tree, who reports to nobody — "the requester's manager" resolves to nobody. A step is asked to name somebody who is not the manager as well, and a step that ends up with nobody on it stops the request from being submitted and says why. Both examples shipped with the module are built that way.

Screens

Decisions - bambooforge_approvals
Decisions
Ladder - bambooforge_approvals
Ladder
Queue - bambooforge_approvals
Queue
Request - bambooforge_approvals
Request