Odoo out of the box does a lot of great things, but there are some things you are going to want to watch out for.
Contact Merging
By default anyone can merge contacts. What Odoo does is take the res_partner id, then do a lookup in tables like ir_model_field or ir_model_relation to locate any other models in the system that have any links back to the res_partner.
Then it will take one of these partners, and overwrite all links in the system with that one, so that all the other related objects now point to just one of the contacts. It will also merge fields (like email, phone etc) onto that contact and delete the rest.
This operation is completely IRREVERSIBLE. What can happen is people without knowledge of the system may see two customers like: JIMMY FREIGHT US and JIMMY FREIGHT and think they are typos or duplicate contacts, then "helpfully" merge them.
This merges all account transaction history, everything. So that's really not fun and often only shows up well after launch. My recommendation is to disable this privilege for any non-admins, or assign one person to be a "master data" authority and only allow them to do that.
One2many create
In Odoo, for one2many relations (like contact tags), you can type the value you are looking for and if it does not exist, Odoo will offer to quick create it for you. This can be a helpful time-saver, but what happens quite often with these fields is someone will do a typo, then tab to the next field and Odoo will auto-create the incorrectly spelled item.
Often these tags are not changed frequently, and again is better to be managed by someone on the team. So the excellent OCA module base_optional_quick_create allows you to configure which models this is enabled or disabled on.
User Role Management
Odoo has an extremely complex and sophisticated security and permissions configuration available. You can control read, write, update and delete access on each model, as well as controlling visibility of individual fields and whether users can edit them.
Managing this can be made somewhat easier using Odoo groups, but managing which user belongs to which groups can also become quite difficult. Especially in larger companies where many users will have highly similar permissions (for example customer support agents).
Using a module like base_user_role allows you to group permissions into roles, then simply assign each user to a role thereby granting them all the associated permissions.
This also makes updating the role much easier in the future, as granting an additional permissions to the role deploys that updated permission to all users in the role.
Database and environment management
You will often have different Odoo environments. Ones for User Acceptance Testing (UAT), or maybe called "test" or "staging" environments. You will also be running a production environment.
You can end up testing different Odoo configuration in UAT for example, then have to replicate that same setup in production. This can often be quite complex (like warehouse routes), or complex product configuration or migrations from other systems.
Reliably replicating that in production can be challenging. Also due to the large number of postgres foreign key constraints on the res_partner model, it is often nearly impossible to migrate only parts of the database, or to roll back testing data so you have a "cleaner" environment to deploy to production (via exporting and importing the db and filestore).
To get around these potential issues, I would recommend having a module with scripts you can run to do all the Odoo setup. So for example, enabling different feature sets within Odoo (like product variants), or setup data like warehouse routes or product categories.
A lot of this can be done in Python, or in XML (using the noupdate option). This way, using this module, you can always take a clean DB environment, run this, and have a completely setup environment, that is then ready for users to go in and do testing, or to do data imports from other systems.
Having things repeatable means that if there are any issues with say, a data import, you can just wipe the database clean, re-run the setup, then try the import again. This is much better than trying to roll back the import, or have to manually reconfigure things over and over again.
Use a meta package
I always create a single package that does only 1 thing - lists all the other modules for the system in the manifest depends.
This way, you can take a blank database, install only this module, and all other modules will get installed.
This is good for test automation, since you can then trigger your CI pipeline to run all tests, knowing that all the tests will run because everything has been correctly installed.
Module Organisation
I find one huge folder with tons of modules in can become quite difficult to navigate.
I would recommend grouping those logically, for example you might have a folder structure like:
- Marketing
- Inventory
- eCommerce
- Accounting
addons_path=/mnt/marketing,/mnt/inventory,/mnt/ecommerce,/mnt/accounting
as an example. This just makes your git repository cleaner and easier to navigate.
Small modules
I would also recommend avoiding making your custom modules too large.
I've seen modules with model files hundreds of lines long, with large functions handling many different edge cases.
Better to make smaller, more focused modules that do one thing, and do it very well. Then you can create more sophisticated features by combining lots of smaller modules, rather than having very large, difficult to maintain ones.
Naming things well is important too, as it helps future developers find and understand what you've done. So you might have a customer that wants to ingest pdf invoices into the accounting module, have some kind of validation process then trigger an external banking API to make the payment if it passes.
Rather than build a single module that meets this need, I would build 3 modules. One for pdf ingestion (which could then be used for other workflows). Then a module for the invoice approval process (which might then be able to be used for non-pdf invoices as well), and finally some kind of payments module.
This makes each module easier to build and maintain, whilst giving the same functionality. You can take this too far of course, but a good rule of thumb is, if a module would take more than 2 weeks to rebuild from scratch, it's probably too large.
I think if you apply these rules you should have an easier time launching your Odoo implementation!