[FIX] web: compute aggregate value with valid data

The footer of some lists may contain undesirable values (such as `NaN`)

To reproduce the issue:
1. Install mrp with demo data
2. In Settings, enable "Work Orders"
3. Open the list view of MOs
4. Group by product

Error: The total value for Expected Duration and Real Duration is
`NaN:NaN`

(The below explanation is about Expected Duration
(`production_duration_expected`). This is exactly the same behavior for
Real Duration)

As defined on the list view, if there are several rows on the list,
there must be a sum of all `production_duration_expected`:
https://github.com/odoo/odoo/blob/cddbb76e02c3848819ac1f06948b4e7ab8df4bdd/addons/mrp/views/mrp_production_views.xml#L35
This is correctly working when consulting a standard list of MOs (step
3). However, this is different when using the Group-By feature.

When rendering the list, at some point, `_computeColumnAggregates` is
called to compute the sum of all `production_duration_expected`:
https://github.com/odoo/odoo/blob/4e213f0b93f59cf377271b18eae9765ff9cfbe4f/addons/web/static/src/legacy/js/views/list/list_renderer.js#L178-L185
Here is the issue: the rows in the list `data` are not records (there
are results of `read_group`) and these rows don't have any aggregate
value for `production_duration_expected`, which means that
`d.aggregateValues[attrs.name]` returns `undefined`. As a result, when
performing the sum of `0` and `undefined`, it gives `NaN`.

Some detailed explanations:
`aggregateValues` is completed when processing the result of the
`read_group` RPC:
https://github.com/odoo/odoo/blob/bc79a329a1e1edf964f97886943c0688db2087fd/addons/web/static/src/legacy/js/views/basic/basic_model.js#L4697-L4703
However, on PY-side, `read_group` doesn't provide any value for
`production_duration_expected`. For a `read_group` to provide some
aggregate values, it needs the field to be stored and the
`group_operator` attribute to be defined on this field:
https://github.com/odoo/odoo/blob/5691b126f06c2b200ae507bd6edd8f8f7e68d5f5/odoo/models.py#L2521-L2528
Except that none of the conditions are met:
https://github.com/odoo/odoo/blob/d584ad282178deb40bb036c48f971617b0a41f88/addons/mrp/models/mrp_production.py#L147

OPW-2735181

closes odoo/odoo#84035

X-original-commit: 8bc1c582b626aedb680d59f858c92db9dfe4f357
Signed-off-by: Simon Genin (ges@odoo) <ges@odoo.com>
This commit is contained in:
Adrien Widart
2022-02-07 09:07:00 +00:00
parent 6c086ba6d8
commit 30f4a40e20
2 changed files with 41 additions and 6 deletions
@@ -176,8 +176,11 @@ var ListRenderer = BasicRenderer.extend({
aggregateValue = Infinity;
}
_.each(data, function (d) {
count += 1;
var value = (d.type === 'record') ? d.data[attrs.name] : d.aggregateValues[attrs.name];
if (Number(value) !== value) {
return;
}
count += 1;
if (func === 'avg') {
aggregateValue += value;
} else if (func === 'sum') {
@@ -191,10 +194,14 @@ var ListRenderer = BasicRenderer.extend({
if (func === 'avg') {
aggregateValue = count ? aggregateValue / count : aggregateValue;
}
column.aggregate = {
help: attrs[func],
value: aggregateValue,
};
if (count) {
column.aggregate = {
help: attrs[func],
value: aggregateValue,
};
} else {
delete column.aggregate;
}
}
},
/**
@@ -2405,7 +2405,7 @@ QUnit.module('Views', {
// Let's update the view to dislay NO records
await list.update({domain: ['&', ['bar', '=', false], ['int_field', '>', 0]]});
assert.strictEqual(list.$('tfoot td:nth(2)').text(), "0", "total should have been recomputed to 0");
assert.strictEqual(list.$('tfoot td:nth(2)').text(), "", "No records, so no total.");
list.destroy();
});
@@ -2438,6 +2438,34 @@ QUnit.module('Views', {
list.destroy();
});
QUnit.test('hide aggregated value in grouped lists when no data provided by RPC call', async function(assert) {
assert.expect(1);
var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
groupBy: ['bar'],
arch: '<tree editable="bottom"><field name="foo"/><field name="qux" widget="float_time" sum="Sum"/></tree>',
mockRPC: function (route, args) {
return this._super.apply(this, arguments).then(result => {
// On PY-side, a read_group won't provide any aggregate value
// if the field does not have a `group_operator` attribute.
// (see 5691b126f06/odoo/models.py#L2521-L2528)
// Here, since `qux` does not have such an attribute, we
// remove the value provided by `_mockReadGroup`
_.each(result.groups, function(group) {
delete group.qux
})
return Promise.resolve(result)
});
},
});
assert.strictEqual(list.$('tfoot td:nth(2)').text(), "", "There isn't any aggregated value");
list.destroy();
})
QUnit.test('aggregates are updated when a line is edited', async function (assert) {
assert.expect(2);