summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/views/basic/basic_model.js
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-04-16 19:50:50 +0200
committerChristophe Simonis <chs@odoo.com>2018-04-16 19:50:50 +0200
commit74033eb007749c88b84ea883b006a5877355306e (patch)
tree8f8b6cb22cc2bf6046ba04e388ea29855a33c597 /addons/web/static/src/js/views/basic/basic_model.js
parent71cdefd9f41881d9720433d5fc7732759098f9a4 (diff)
parent90f8f17fb4fc795c2c12d68d21900e81f3d7a223 (diff)
[MERGE] forward port branch saas-11.2 up to 90f8f17fb4f
Diffstat (limited to 'addons/web/static/src/js/views/basic/basic_model.js')
-rw-r--r--addons/web/static/src/js/views/basic/basic_model.js76
1 files changed, 56 insertions, 20 deletions
diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js
index 4cf6f9fa27b..962bb2899e1 100644
--- a/addons/web/static/src/js/views/basic/basic_model.js
+++ b/addons/web/static/src/js/views/basic/basic_model.js
@@ -386,11 +386,12 @@ var BasicModel = AbstractModel.extend({
duplicateRecord: function (recordID) {
var self = this;
var record = this.localData[recordID];
+ var context = this._getContext(record);
return this._rpc({
model: record.model,
method: 'copy',
args: [record.data.id],
- context: this._getContext(record),
+ context: context,
})
.then(function (res_id) {
var index = record.res_ids.indexOf(record.res_id);
@@ -402,6 +403,7 @@ var BasicModel = AbstractModel.extend({
res_id: res_id,
res_ids: record.res_ids.slice(0),
viewType: record.viewType,
+ context: context,
});
});
},
@@ -578,10 +580,15 @@ var BasicModel = AbstractModel.extend({
return _t("New");
},
/**
- * Returns true if a record can be abandoned from a list datapoint.
+ * Returns true if a record can be abandoned.
+ *
+ * A record can be abandonned if it is a new record, except if
+ * this datapoint has been specifically tagged as "do not abandon".
+ *
+ * Example:
*
- * A record cannot be abandonned if it has been registered as "added"
- * in the parent's savepoint, otherwise it can be abandonned.
+ * - Discard record from "Add an item" => "New" record => abandon
+ * - Discard record from `default_get`/`onchange` => do not abandon
*
* This is useful when discarding changes on this record, as it means that
* we must keep the record even if some fields are invalids (e.g. required
@@ -591,15 +598,7 @@ var BasicModel = AbstractModel.extend({
* @returns {boolean}
*/
canBeAbandoned: function (id) {
- var data = this.localData[id];
- var parent = this.localData[data.parentID];
- var abandonable = true;
- if (parent) {
- abandonable = !_.some(parent._savePoint, function (entry) {
- return entry.operation === 'ADD' && entry.id === id;
- });
- }
- return abandonable;
+ return !this.localData[id]._noAbandon && this.isNew(id);
},
/**
* Returns true if a record is dirty. A record is considered dirty if it has
@@ -960,11 +959,11 @@ var BasicModel = AbstractModel.extend({
* @returns {Deferred}
* Resolved with the list of field names (whose value has been modified)
*/
- save: function (record_id, options) {
+ save: function (recordID, options) {
var self = this;
return this.mutex.exec(function () {
options = options || {};
- var record = self.localData[record_id];
+ var record = self.localData[recordID];
if (options.savePoint) {
self._visitChildren(record, function (rec) {
var newValue = rec._changes || rec.data;
@@ -982,7 +981,7 @@ var BasicModel = AbstractModel.extend({
});
}
var shouldReload = 'reload' in options ? options.reload : true;
- var method = self.isNew(record_id) ? 'create' : 'write';
+ var method = self.isNew(recordID) ? 'create' : 'write';
if (record._changes) {
// id never changes, and should not be written
delete record._changes.id;
@@ -1553,6 +1552,7 @@ var BasicModel = AbstractModel.extend({
list._cache[rec.res_id] = rec.id;
}
+ rec._noAbandon = true;
list._changes.push({operation: 'ADD', id: rec.id});
if (command[0] === 1) {
list._changes.push({operation: 'UPDATE', id: rec.id});
@@ -2029,7 +2029,7 @@ var BasicModel = AbstractModel.extend({
.then(function () {
return $.when(
self._fetchX2Manys(record, options),
- self._fetchReferences(record)
+ self._fetchReferences(record, options)
).then(function () {
return self._postprocess(record, options);
});
@@ -2076,10 +2076,10 @@ var BasicModel = AbstractModel.extend({
* @param {Object} record
* @returns {Deferred}
*/
- _fetchReferences: function (record) {
+ _fetchReferences: function (record, options) {
var self = this;
var defs = [];
- var fieldNames = record.getFieldNames();
+ var fieldNames = options && options.fieldNames || record.getFieldNames();
_.each(fieldNames, function (fieldName) {
var field = record.fields[fieldName];
if (field.type === 'reference') {
@@ -3199,6 +3199,9 @@ var BasicModel = AbstractModel.extend({
* @param {Object} [options]
* @param {string[]} [options.fieldNames] the fields to fetch for a record
* @param {boolean} [options.onlyGroups=false]
+ * @param {boolean} [options.keepEmptyGroups=false] if set, the groups not
+ * present in the read_group anymore (empty groups) will stay in the
+ * datapoint (used to mimic the kanban renderer behaviour for example)
* @returns {Deferred}
*/
_load: function (dataPoint, options) {
@@ -3351,9 +3354,29 @@ var BasicModel = AbstractModel.extend({
*/
_makeDefaultRecord: function (modelName, params) {
var self = this;
+
+ var determineExtraFields = function() {
+ // Fields that are present in the originating view, that need to be initialized
+ // Hence preventing their value to crash when getting back to the originating view
+ var parentRecord = self.localData[params.parentID];
+
+ var originView = parentRecord && parentRecord.fieldsInfo;
+ if (!originView || !originView[parentRecord.viewType])
+ return [];
+
+ var fieldsFromOrigin = _.filter(Object.keys(originView[parentRecord.viewType]),
+ function(fieldname) {
+ return params.fields[fieldname] !== undefined;
+ });
+
+ return fieldsFromOrigin;
+ }
+
var fieldNames = Object.keys(params.fieldsInfo[params.viewType]);
var fields_key = _.without(fieldNames, '__last_update');
+ var extraFields = determineExtraFields();
+
return this._rpc({
model: modelName,
method: 'default_get',
@@ -3371,7 +3394,7 @@ var BasicModel = AbstractModel.extend({
viewType: params.viewType,
});
- return self.applyDefaultValues(record.id, result)
+ return self.applyDefaultValues(record.id, result, {fieldNames: _.union(fieldNames, extraFields)})
.then(function () {
var def = $.Deferred();
self._performOnChange(record, fields_key).always(function () {
@@ -3605,6 +3628,7 @@ var BasicModel = AbstractModel.extend({
parentID: x2manyList.id,
viewType: viewType,
});
+ r._noAbandon = true;
x2manyList._changes.push({operation: 'ADD', id: r.id});
x2manyList._cache[r.res_id] = r.id;
@@ -3634,6 +3658,8 @@ var BasicModel = AbstractModel.extend({
} else if (_.contains(['one2many', 'many2many'], fieldType)) {
var x2mCommands = commands[0][2][fieldName];
defs.push(self._processX2ManyCommands(r, fieldName, x2mCommands));
+ } else {
+ r._changes[fieldName] = self._parseServerValue(field, r._changes[fieldName]);
}
}
}
@@ -3832,6 +3858,16 @@ var BasicModel = AbstractModel.extend({
defs.push(self._load(newGroup, options));
}
});
+ if (options && options.keepEmptyGroups) {
+ // Find the groups that were available in a previous
+ // readGroup but are not there anymore.
+ // Note that these groups are put after existing groups so
+ // the order is not conserved. A sort *might* be useful.
+ var emptyGroupsIDs = _.difference(_.pluck(previousGroups, 'id'), list.data);
+ _.each(emptyGroupsIDs, function (groupID) {
+ list.data.push(groupID);
+ });
+ }
return $.when.apply($, defs).then(function () {
// generate the res_ids of the main list, being the concatenation
// of the fetched res_ids in each group