@André Arnaud de Cal... I do agree that we shouldn't do CRUD operations on many related tables in a single entity, but that's not the topic. The topic of this thread is when we should choose a Custom service or Odata. It doesn't have about CRUD operations at all.
I corrected your statements that “With OData you are bound to one main table”, which is true only in some cases (using the /data/ endpoint to make CRUD operations on data entities, not other uses of OData protocol) and “With OData you can add […] actions, but limited to one main source table”, which isn't true, especially for static actions, as I demonstrated with standard code that not only isn't limited to a single main table, but it's not related to any table at all.
You can call any arbitrary logic by both custom services and OData actions. Whether you use a custom service or an OData action is a design choice, not something driven by limitation of the OData protocol or the implementation of OData services in F&O. Preferring OData actions has its benefits, such as having them exposed in Dataverse by virtual entities.
To give another example from the standard application, we have two similar APIs for data management. One implemented as a custom service (DMFService), another as an OData service (DataManagementDefinitionGroupEntity). It could be done differently, e.g. OData actions like GetAzureWriteUrl() could have been custom services. As I said, it's a design choice to make. You may think that Microsoft should have used custom services in this case (rather then adding actions to an entity) and we could argue about it (I don't want), but it's clear that OData actions can be used this way.
I trust you that you know these things. I wanted to clarity for others, who would read the reply and believed that OData services “are bound to one main table” and you must use custom services for logic that isn't “bound to one main table”.