[IMP] web: improve eval context dates
This commit handles 2 things: 1) the merging of the `py_utils.context()` into the evaluation context returned by `BasicModel._getEvalContext` to access the same time-related keys, 2) the addition of 2 new keys into the `py_utils.context` (thus transmitted to the basic model): `today` (an alias for the already present `current_date`) and `now` which represents the current date and time value. Task 2269697
This commit is contained in:
@@ -254,14 +254,29 @@ function tz_offset() {
|
||||
|
||||
|
||||
function pycontext() {
|
||||
const d = new Date();
|
||||
const today = `${
|
||||
String(d.getFullYear()).padStart(4, "0")}-${
|
||||
String(d.getMonth() + 1).padStart(2, "0")}-${
|
||||
String(d.getDate()).padStart(2, "0")}`;
|
||||
const now = `${
|
||||
String(d.getUTCFullYear()).padStart(4, "0")}-${
|
||||
String(d.getUTCMonth() + 1).padStart(2, "0")}-${
|
||||
String(d.getUTCDate()).padStart(2, "0")} ${
|
||||
String(d.getUTCHours()).padStart(2, "0")}:${
|
||||
String(d.getUTCMinutes()).padStart(2, "0")}:${
|
||||
String(d.getUTCSeconds()).padStart(2, "0")}`;
|
||||
|
||||
const { datetime, relativedelta, time } = py.extras;
|
||||
return {
|
||||
datetime: py.extras.datetime,
|
||||
context_today: context_today,
|
||||
time: py.extras.time,
|
||||
relativedelta: py.extras.relativedelta,
|
||||
current_date: py.PY_call(
|
||||
py.extras.time.strftime, [py.str.fromJSON('%Y-%m-%d')]),
|
||||
tz_offset: tz_offset,
|
||||
current_date: today,
|
||||
datetime,
|
||||
time,
|
||||
now,
|
||||
today,
|
||||
relativedelta,
|
||||
context_today,
|
||||
tz_offset,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ var concurrency = require('web.concurrency');
|
||||
var Context = require('web.Context');
|
||||
var core = require('web.core');
|
||||
var Domain = require('web.Domain');
|
||||
const pyUtils = require('web.py_utils');
|
||||
var session = require('web.session');
|
||||
var utils = require('web.utils');
|
||||
var viewUtils = require('web.viewUtils');
|
||||
@@ -3696,19 +3697,27 @@ var BasicModel = AbstractModel.extend({
|
||||
}
|
||||
// Uses "current_company_id" because "company_id" would conflict with all the company_id fields
|
||||
// in general, the actual "company_id" field of the form should be used for m2o domains, not this fallback
|
||||
let current_company_id;
|
||||
if (session.user_context.allowed_company_ids) {
|
||||
var current_company = session.user_context.allowed_company_ids[0];
|
||||
current_company_id = session.user_context.allowed_company_ids[0];
|
||||
} else {
|
||||
var current_company = session.user_companies ? session.user_companies.current_company[0] : false;
|
||||
current_company_id = session.user_companies ?
|
||||
session.user_companies.current_company[0] :
|
||||
false;
|
||||
}
|
||||
return _.extend({
|
||||
active_id: evalContext.id || false,
|
||||
active_ids: evalContext.id ? [evalContext.id] : [],
|
||||
active_model: element.model,
|
||||
current_date: moment().format('YYYY-MM-DD'),
|
||||
id: evalContext.id || false,
|
||||
current_company_id: current_company,
|
||||
}, session.user_context, element.context, evalContext);
|
||||
return Object.assign(
|
||||
{
|
||||
active_id: evalContext.id || false,
|
||||
active_ids: evalContext.id ? [evalContext.id] : [],
|
||||
active_model: element.model,
|
||||
current_company_id,
|
||||
id: evalContext.id || false,
|
||||
},
|
||||
pyUtils.context(),
|
||||
session.user_context,
|
||||
element.context,
|
||||
evalContext,
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Returns the list of field names of the given element according to its
|
||||
|
||||
@@ -2037,8 +2037,9 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
});
|
||||
|
||||
QUnit.test('has a proper evaluation context', async function (assert) {
|
||||
assert.expect(1);
|
||||
assert.expect(6);
|
||||
|
||||
const unpatchDate = testUtils.mock.patchDate(1997, 0, 9, 12, 0, 0);
|
||||
this.params.fieldNames = Object.keys(this.data.partner.fields);
|
||||
this.params.res_id = 1;
|
||||
|
||||
@@ -2048,8 +2049,24 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
});
|
||||
|
||||
var resultID = await model.load(this.params);
|
||||
var record = model.get(resultID);
|
||||
assert.deepEqual(record.evalContext, {
|
||||
const { evalContext } = model.get(resultID);
|
||||
assert.strictEqual(typeof evalContext.datetime, "object");
|
||||
assert.strictEqual(typeof evalContext.relativedelta, "object");
|
||||
assert.strictEqual(typeof evalContext.time, "object");
|
||||
assert.strictEqual(typeof evalContext.context_today, "function");
|
||||
assert.strictEqual(typeof evalContext.tz_offset, "function");
|
||||
const blackListedKeys = [
|
||||
"time",
|
||||
"datetime",
|
||||
"relativedelta",
|
||||
"context_today",
|
||||
"tz_offset",
|
||||
];
|
||||
// Remove uncomparable values from the evaluation context
|
||||
for (const key of blackListedKeys) {
|
||||
delete evalContext[key];
|
||||
}
|
||||
assert.deepEqual(evalContext, {
|
||||
active: true,
|
||||
active_id: 1,
|
||||
active_ids: [1],
|
||||
@@ -2058,6 +2075,8 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
category: [12],
|
||||
current_company_id: false,
|
||||
current_date: moment().format('YYYY-MM-DD'),
|
||||
today: moment().format('YYYY-MM-DD'),
|
||||
now: moment().utc().format('YYYY-MM-DD HH:mm:ss'),
|
||||
date: "2017-01-25",
|
||||
display_name: "first partner",
|
||||
foo: "blip",
|
||||
@@ -2070,6 +2089,7 @@ odoo.define('web.basic_model_tests', function (require) {
|
||||
x_active: true,
|
||||
}, "should use the proper eval context");
|
||||
model.destroy();
|
||||
unpatchDate();
|
||||
});
|
||||
|
||||
QUnit.test('x2manys in contexts and domains are correctly evaluated', async function (assert) {
|
||||
|
||||
@@ -10320,6 +10320,95 @@ QUnit.module('Views', {
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("Date in evaluation context works with date field", async function (assert) {
|
||||
assert.expect(11);
|
||||
|
||||
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
||||
const unpatchDate = testUtils.mock.patchDate(1997, 0, 9, 12, 0, 0);
|
||||
testUtils.mock.patch(BasicModel, {
|
||||
_getEvalContext() {
|
||||
const evalContext = this._super(...arguments);
|
||||
assert.ok(dateRegex.test(evalContext.today));
|
||||
assert.strictEqual(evalContext.current_date, evalContext.today);
|
||||
return evalContext;
|
||||
},
|
||||
});
|
||||
|
||||
this.data.foo.fields.birthday = { string: "Birthday", type: 'date' };
|
||||
this.data.foo.records[0].birthday = "1997-01-08";
|
||||
this.data.foo.records[1].birthday = "1997-01-09";
|
||||
this.data.foo.records[2].birthday = "1997-01-10";
|
||||
|
||||
const list = await createView({
|
||||
arch: `
|
||||
<tree>
|
||||
<field name="birthday" decoration-danger="birthday > today"/>
|
||||
</tree>`,
|
||||
data: this.data,
|
||||
model: 'foo',
|
||||
View: ListView,
|
||||
});
|
||||
|
||||
assert.containsOnce(list, ".o_data_row .text-danger");
|
||||
|
||||
list.destroy();
|
||||
unpatchDate();
|
||||
testUtils.mock.unpatch(BasicModel);
|
||||
});
|
||||
|
||||
QUnit.test("Datetime in evaluation context works with datetime field", async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const datetimeRegex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
|
||||
const unpatchDate = testUtils.mock.patchDate(1997, 0, 9, 12, 0, 0);
|
||||
testUtils.mock.patch(BasicModel, {
|
||||
_getEvalContext() {
|
||||
const evalContext = this._super(...arguments);
|
||||
assert.ok(datetimeRegex.test(evalContext.now));
|
||||
return evalContext;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns "1997-01-DD HH:MM:00" with D, H and M holding current UTC values
|
||||
* from patched date + (deltaMinutes) minutes.
|
||||
* This is done to allow testing from any timezone since UTC values are
|
||||
* calculated with the offset of the current browser.
|
||||
*/
|
||||
function dateStringDelta(deltaMinutes) {
|
||||
const d = new Date(Date.now() + 1000 * 60 * deltaMinutes);
|
||||
return `1997-01-${
|
||||
String(d.getUTCDate()).padStart(2, '0')
|
||||
} ${
|
||||
String(d.getUTCHours()).padStart(2, '0')
|
||||
}:${
|
||||
String(d.getUTCMinutes()).padStart(2, '0')
|
||||
}:00`;
|
||||
}
|
||||
|
||||
// "datetime" field may collide with "datetime" object in context
|
||||
this.data.foo.fields.birthday = { string: "Birthday", type: 'datetime' };
|
||||
this.data.foo.records[0].birthday = dateStringDelta(-30);
|
||||
this.data.foo.records[1].birthday = dateStringDelta(0);
|
||||
this.data.foo.records[2].birthday = dateStringDelta(+30);
|
||||
|
||||
const list = await createView({
|
||||
arch: `
|
||||
<tree>
|
||||
<field name="birthday" decoration-danger="birthday > now"/>
|
||||
</tree>`,
|
||||
data: this.data,
|
||||
model: 'foo',
|
||||
View: ListView,
|
||||
});
|
||||
|
||||
assert.containsOnce(list, ".o_data_row .text-danger");
|
||||
|
||||
list.destroy();
|
||||
unpatchDate();
|
||||
testUtils.mock.unpatch(BasicModel);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -36,6 +36,8 @@ def _get_attrs_symbols():
|
||||
'datetime',
|
||||
'relativedelta',
|
||||
'current_date',
|
||||
'today',
|
||||
'now',
|
||||
'abs',
|
||||
'len',
|
||||
'bool',
|
||||
|
||||
Reference in New Issue
Block a user