Every stalled ERP project we've rescued traces back to the same thing: someone tried to make the company work the way the demo worked. That never holds. A demo is generic by design. Your business isn't, and that's the whole reason it makes money.
The 80/20 of Odoo
Out of the box, Odoo handles the universal 80%: sales orders, inventory moves, invoices, the chart of accounts. Don't customize that part. The other 20% is the reason you're competitive. It's the pricing rule nobody else has, the approval path your auditor insists on, the report your operations lead rebuilds in a spreadsheet every Friday because the standard one doesn't quite fit.
That 20% is exactly what custom addons are for.
What a good addon looks like
A good Odoo addon is small, framework-native, and upgrade-safe:
- It extends models with the ORM rather than patching core.
- It keeps business logic in Python and presentation in QWeb/OWL.
- It ships with access rules and record rules built in from the start.
- It's tested against the target Odoo version before anyone touches production.
class SaleOrder(models.Model):
_inherit = "sale.order"
priority_tier = fields.Selection(
[("std", "Standard"), ("exp", "Expedited")],
default="std",
)
def action_confirm(self):
# your rule, expressed once, in the framework's grain
for order in self.filtered(lambda o: o.priority_tier == "exp"):
order._reserve_priority_stock()
return super().action_confirm()
The payoff
When the 20% lives in clean modules, upgrades stop being something to dread and your team stops doing by hand what the system should be doing for them. That's what an ERP is for. It's also why we write the addon instead of asking you to bend your process to fit the software.