In my odoo instance I have several calculated fields on the analytic account object. These fields are calculated to ensure the viewer always has the most up to date overview.
Some of these fields depend on other fields that are by themselves calculated fields. The calculations by themselves are fairly simple (field A = field B + field C). Most of the fields are also depending on the underlying child ids. For example, field A on the top object is a summary of all field A values of the child ids. Field A on the children is calculated on their own field B and C combined, as described above.
The situation I currently find myself in is that for some reason the fields seem to be calculated in a random order. I noticed this because when I refresh in rapid succession I get different values for the same record.
Example: Field B and C are both 10. I expect A to be 20 (B+C) but most of the times it's actually 0 because field calculation for A happens before B and C. Sometimes it's 10 since either B or C snuck in before A could finish. On very rare occasions it's actually 20....
Note: - I cannot make the fields stored because they will depend on account move lines which are created at an incredible rate and the database will go absolutely nuts recalculating all records every minute or so. - I already added the @api.depends but this is only useful if you use stored fields to determine that fields should trigger it, which is not applicable in my situation.
Does anyone know of a solution to this? Or have suggestions on alternative ways of calculating?
[EDIT] Added code
Example code:
@api.multi
@api.depends('child_ids','costs_allowed','total_cost')
def _compute_production_result(self):
for rec in self:
rec_prod_cost = 0.0
if rec.usage_type in ['contract','project']:
for child in rec.child_ids:
rec_prod_cost += child.production_result
elif rec.usage_type in ['cost_control','planning']:
rec_prod_cost = rec.costs_allowed - rec.total_cost
rec.production_result = rec_prod_cost
As you can see, if we are on a contract or project we need to look at the children (cost_control accounts) for their results and ADD them together. If we are actually on a cost_control account, then we can get the actual values by taking field B and C and (in this case) subtracting them.
The problem occurs when EITHER the contract records are handled before the cost_control OR the costs_allowed and total_cost fields are 0.0 when evaluating the cost_control accounts.
Mind you: costs_allowed and total_cost are both calculated fields in their own respect!
So I managed to find a colleague and we figured it out together. As it so turns out, when you define a method that calculates a field for both it's own record as well as depending on that field on child records, you need to explicitly mention this in the dependencies.
For example:
@api.multi
@api.depends('a', 'b', 'c')
def _compute_a(self):
for rec in self:
if condition:
rec.a = sum(child_ids.a)
else:
rec.a = rec.b + rec.c
In this example, the self object contains records (1,2,3,4). If you include the dependency but otherwise let the code remain the same, like so:
@api.multi
@api.depends('a', 'b', 'c', 'child_ids.a')
def _compute_a(self):
for rec in self:
if condition:
rec.a = sum(child_ids.a)
else:
rec.a = rec.b + rec.c
will run this method 4 times, starting with the lowest/deepest candidate. So self in this case will be (4), then (3), etc.
Too bad this logic seems to be implied and not really described anywhere (as far as I could see).