Model the business workflow before the module
A good custom Odoo module translates a missing business rule into models, states, permissions, views, and automated actions that cooperate with standard Odoo behavior. It should extend the platform at known seams instead of creating a second application inside the database.
Use Odoo ORM and inheritance intentionally
- Start with actors, states, transitions, validations, and audit requirements.
- Use model inheritance when extending a standard concept; create a new model for genuinely new business entities.
- Implement access rights and record rules alongside UI buttons, never after them.
- Keep computed fields and automated actions deterministic and avoid hidden network calls in model methods.
- Use scheduled jobs/queues for slow integrations instead of blocking form saves.
A controlled record lifecycle
Users transition a record through explicit states; server-side rules validate permission and data, then side effects are queued after the authoritative state is saved.
Custom workflow inside Odoo lifecycle
Users transition a record through explicit states; server-side rules validate permission and data, then side effects are queued after the authoritative state is saved.
Adding a purchase approval extension
Make the state transition explicit
A model action validates the current state and permission before changing the workflow state.
def action_submit_for_approval(self):
for order in self:
if order.state != 'draft':
raise UserError('Only draft orders can be submitted')
order.approval_state = 'pending'Custom-module patterns that fight Odoo
Module checklist
- Draw states and actors first.
- Choose inheritance versus new model deliberately.
- Implement access, record rules, and transition checks server-side.
- Isolate external calls from synchronous model writes.
- Test module install, upgrade, permissions, and standard-flow compatibility.
