YannickB / odoo-hosting

Other
64 stars 50 forks source link

[RFC] Billing and Deploy Flow #157

Open lasley opened 7 years ago

lasley commented 7 years ago

Overview

I've been thinking about this for a while, and I think I have a plan for selling Clouder instances. We have a lot of framework built already, but it's duplicating a lot of what Odoo can already do for us in some instances. My goal will be to offload as much logic out of our scope as possible.

For this plan to work, we need a job queue. I will assume that we will depend on either connector or the base queue_job in order to accomplish this, but I guess it could also be built from scratch to allow the LGPL licensing on this module. Lots of work though.

From what I'm seeing/thinking, we have three independent concepts for billing:

Whatever we decide to actually bill on will likely be a combination of all three types of billing concepts. Some of these fees would repeat, and some would be one-time. Both pre- and post-billing cycles are represented in these concepts.

We also need some of these fees to come with an action, such as:

Sale

Each of the fees will be a product.product, just like normal Odoo. We will need to add the following onto product.product:

Products representing an instance itself will be set to go through an Infrastructure Manufacture Warehouse Route, and have an associated Bill of Materials including all products that are considered a part of initial creation.

Manufacture

Each server, or maybe runner, will be a Manufacturing Work Center. We could figure out a way to determine the efficiency factor & capacity on the fly, but that's not important now. I think that we would need to add Infrastructure for use as the Resource Type of the Work Center.

When a Product is purchased, the Bill of Materials will generate the Manufacturing Order with the products that are contained as part of the kit. Creation of a Manufacturer Order from the Infrastructure Manufacture Route will trigger a Job Queue addition for Production of all Applications linked to Products in the Order. The sequence of the Manufacturing Order will be respected, which will determine the build order - This sequence is the same as in the Bill of Materials for the Product.

Bill

Recurrence

Use new recur_interval on Product to create a subscription.document, or identify an existing subscription.document on the same interval to append to. This would be triggered upon either confirmation of the sale, or perhaps the validation of the first invoice.

We would need to add a link between Clouder Application and the Subscription Document Line in order to later identify which instance belongs to which line.

Flat Fee

This is easy. Sell the product.

Usage

This is reliant on our plan for metrics ingestion. I will update later.

Threshold

This is reliant on our plan for metrics ingestion. I will update later.

Cancel

I haven't thought this far yet. It will definitely be linked to MRP Unbuild Orders, but how is TBD. Possibly using a Subscription Document in order to destroy at the right time.

Instance Environment

Something not considered here is how to determine which environment to launch applications under. I think this kind of falls into the scope of security and instance isolation though, so I left it out of here.


Nice to have

YannickB commented 7 years ago

Thanks for the RFC, I agree with most of the problem description (especially Thresholds/Usage/Flat price)

Regarding Sale, I'm not sure the price shall be configure in product.product itself. Look at listprice in Odoo, there is good reason why they are not defined in product.product itself. I'm also not sure that a product shall be mandatory to be only one of Thresholds/Usage/Flat, I think it shall be able to be a combination of them. For theses reasons, I'm still in favor to keep price configuration in clouder.application because in Clouder an application is in fact the product being sold (this is what you select in subscription form). Of course an application shall still be linked to a product.product, which will be used when we generate invoice. I may be missing something though.

Regarding MRP, I didn't thought of that and it's indeed interesting. I'm not sure to see the whole picture though not what we really have to gain, and it'll add a lot of complex logic, this is risky and I'm also afraid we'd need to refactor some of Clouder core for that. Currently when for example we create a container, the container is created and execute the system commands. If we want queue, we just have to install asynchronous feature which will alert us is something goes wrong in the automatic process. I'm really not sure what MRP can bring us here. The only thing I see is for manual action, like a visitor asking for an upgrade through a button which create a task for operator. But we'll probably want to automatize this kind of things as much as possible anyway.

Honestly regarding MRP I think there is something to gain here, but we should not do it right now this is not clear enough. I don't think this is required to start and it'll be easier to do it when we'll have some real case in production. If you still think it's a priority, please make a PR with the model changes so we can better understand where you want to go.

According to me we should focus on the sale part for now. I think the current invoicing model on Odoo here is not so bad, but there is still a lot of work to do on the metrics this is where we should focus. As usual, thanks for everything.

lasley commented 7 years ago

Ok so I had to simmer on this a bit, and look more into what already exists. I agree that MRP isn't required for this first push, so I'll drop that thought for the moment. There are some advantages from a resource management perspective, but we can discuss that later in context once we have the more important things handled. It's more for the planning of mass scaling anyways, which won't be an immediate need.

I'm not sure the price shall be configure in product.product itself

Actually I propose the prices themselves are stored in product.pricelist and product.pricelist.item. Only the type of billing (threshold, usage, flat) and clouder applications to build would be defined on the product, to complement things like Unit of Measure.

Or maybe we push the billing type forward into product.attribute or product.pricelist.item, and only determine which application(s) is built based on the product. We would just tag the product with the attributes (5 users, etc), which would then be used as the billing identifiers.

I'm also not sure that a product shall be mandatory to be only one of Thresholds/Usage/Flat

This is kind of where MRP was going to come in with kitting, but I think it will be possible without implementing the resource side of things. Basically one "service" is a combination of multiple products. Say for example an Odoo instance (completely made up numbers):

In all instances the same application would be created, as determined by the application ids linked to any product in the kit. This creates an isolation of what billing is for, while still grouping under the main asset.

I am having some trouble figuring out a proper interface spec for the metrics and usage thresholds. I'll likely do that in another RFC though in order to limit this one's scope to the data structure as opposed to actions.

YannickB commented 7 years ago

Ok I think I finally got the visualisation in my mind, and how we should properly use product.product. Your config examples helped a lot. I agree for all your recommendations.

In the end, base price shall be stored in the product.product and specific price/ periodic price/ promotion in listprice, just like we usually do in Odoo. I didn't thought we could find for Clouder a model which use the core pricing of Odoo, good job :).

I agree, let's keep this RFC about data structure.

lasley commented 7 years ago

So it looks like we can nail down some of our requirements using some existing OCA modules, and this will also allow us to completely strip out MRP from the plans.

We can use the contract module, which is a forward port of the old 8.0 module. This will allow our recurring billing, as well as the encapsulation of the products to allow for our billing configurations (instead of using Work Orders/Bill of Materials to kit them).

Icing on the cake is contract_variable_quantity, which will allow us to define Python code for the quantity of items before billing. This is the key to allowing our Usage based billing, just by calling whatever metrics interface we define.

So the only things we'll need to worry about is the actual gathering and capping of the usage metrics. Well and all the product/pricelist reconfigs. But yes this is great news I think.

Re OCA/sale-workflow#364

YannickB commented 7 years ago

Yep I agree with that, way to go !

lasley commented 7 years ago

@YannickB Looking at the existing invoice stuff, I see a supplier invoice. Can you elaborate on the intent?

YannickB commented 7 years ago

The idea was to manage the case when you have a Clouder deployed by another Clouder. In this case when the first Clouder generate a customer invoice (charging the hosting fee of the second Clouder), a corresponding supplier invoice is automatically generated in the second Clouder. The second Clouder can still generate customer invoices.

Look also at clouder_invoicing_master in unfinished, it's the module which was intended to be run in the first Clouder to manage this feature.

cc @nicolas-petit : Did I forget anything ? Also I'd like to have your opinion on this RFC proposed by @lasley

lasley commented 7 years ago

FYI RFC for base_elasticsearch is up in OCA. It'll be interesting to see how the hell I end up accomplishing the no document data storage 😉