mirror of https://github.com/OCA/web.git
[IMP] web_widget_one2many_product_picker: Control record per page by group and fix to two the number of decimals
parent
dd9a97bc65
commit
0543c48c56
|
@ -47,7 +47,6 @@ You need to define the view fields. The view must be of ``form`` type.
|
|||
Widget options:
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
* product_per_page > Integer -> Used to control the load more behaviour (16 by default)
|
||||
* groups > Array of dictionaries -> Declare the groups
|
||||
|
||||
* name -> The group name
|
||||
|
@ -58,6 +57,9 @@ Widget options:
|
|||
* name -> The field name to order
|
||||
* asc -> Flag to use 'asc' order
|
||||
|
||||
* records_per_page > Integer -> Used to control the load more behaviour (16 by default)
|
||||
* active -> Boolean -> Select the default group to use ('false' by default = 'All' group)
|
||||
|
||||
* currency_field > Model field used to format monetary values ('currency_id' by default)
|
||||
* field_map > Dictionary:
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ You need to define the view fields. The view must be of ``form`` type.
|
|||
Widget options:
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
* product_per_page > Integer -> Used to control the load more behaviour (16 by default)
|
||||
* groups > Array of dictionaries -> Declare the groups
|
||||
|
||||
* name -> The group name
|
||||
|
@ -16,6 +15,9 @@ Widget options:
|
|||
* name -> The field name to order
|
||||
* asc -> Flag to use 'asc' order
|
||||
|
||||
* records_per_page > Integer -> Used to control the load more behaviour (16 by default)
|
||||
* active -> Boolean -> Select the default group to use ('false' by default = 'All' group)
|
||||
|
||||
* currency_field > Model field used to format monetary values ('currency_id' by default)
|
||||
* field_map > Dictionary:
|
||||
|
||||
|
|
|
@ -406,8 +406,6 @@ You need to define the view fields. The view must be of <tt class="docutils lite
|
|||
<div class="section" id="widget-options">
|
||||
<h2><a class="toc-backref" href="#id3">Widget options:</a></h2>
|
||||
<ul>
|
||||
<li><p class="first">product_per_page > Integer -> Used to control the load more behaviour (16 by default)</p>
|
||||
</li>
|
||||
<li><p class="first">groups > Array of dictionaries -> Declare the groups</p>
|
||||
<blockquote>
|
||||
<ul>
|
||||
|
@ -425,6 +423,10 @@ You need to define the view fields. The view must be of <tt class="docutils lite
|
|||
</ul>
|
||||
</blockquote>
|
||||
</li>
|
||||
<li><p class="first">records_per_page > Integer -> Used to control the load more behaviour (16 by default)</p>
|
||||
</li>
|
||||
<li><p class="first">active -> Boolean -> Select the default group to use (‘false’ by default = ‘All’ group)</p>
|
||||
</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
</li>
|
||||
|
|
|
@ -34,8 +34,15 @@ odoo.define("web_widget_one2many_product_picker.tools", function(require) {
|
|||
});
|
||||
}
|
||||
|
||||
function float(value, field_info, digits) {
|
||||
return field_utils.format.float(value, field_info, {
|
||||
digits: digits,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
monetary: monetary,
|
||||
float: float,
|
||||
priceReduce: priceReduce,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -28,6 +28,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
},
|
||||
|
||||
_click_card_delayed_time: 250,
|
||||
_onchange_delay: 250,
|
||||
|
||||
/**
|
||||
* @override
|
||||
|
@ -48,6 +49,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
/**
|
||||
* Generates a new virtual state and recreates the product card
|
||||
*
|
||||
* @param {Boolean} simple_mode
|
||||
* @returns {Object}
|
||||
*/
|
||||
generateVirtualState: function(simple_mode) {
|
||||
|
@ -186,6 +188,19 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Prints the given field value using the selected format
|
||||
*
|
||||
* @private
|
||||
* @param {String} price_field
|
||||
* @returns {String}
|
||||
*/
|
||||
_getFloatFieldValue: function(field) {
|
||||
const field_name = this.options.fieldMap[field];
|
||||
const value = this.state.data[field_name];
|
||||
return tools.float(value, this.state.fields[field_name]);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {String} d a stringified domain
|
||||
|
@ -241,6 +256,10 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
this._setMasterUomMap();
|
||||
},
|
||||
|
||||
/**
|
||||
* Used to know what is the "main" uom
|
||||
* @private
|
||||
*/
|
||||
_setMasterUomMap: function() {
|
||||
this.master_uom_map = {
|
||||
field_uom: "product_uom",
|
||||
|
@ -269,9 +288,13 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
field_map: this.options.fieldMap,
|
||||
widget: this,
|
||||
monetary: this._getMonetaryFieldValue.bind(this),
|
||||
floatFixed: this._getFloatFieldValue.bind(this),
|
||||
show_discount: this.options.showDiscount,
|
||||
is_virtual: this.is_virtual,
|
||||
modified: record && record.context.product_picker_modified,
|
||||
modified:
|
||||
record &&
|
||||
model.hasChanges(record.id) &&
|
||||
!model.isPureVirtual(record.id),
|
||||
active_model: "",
|
||||
auto_save: this.options.autoSave,
|
||||
is_saving: record && record.context.saving,
|
||||
|
@ -310,6 +333,15 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
return {};
|
||||
},
|
||||
|
||||
/**
|
||||
* This generates a virtual record with delayed call to "get_default" & "onchange"
|
||||
* used in "instant search" mode
|
||||
*
|
||||
* @private
|
||||
* @param {Object} context
|
||||
* @param {Object} def_values
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_generateVirtualStateSimple: function(context, def_values) {
|
||||
const model = this.options.basicFieldParams.model;
|
||||
return new Promise(resolve => {
|
||||
|
@ -349,7 +381,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
(current_batch_id, record_def) => {
|
||||
this._timerOnChange = false;
|
||||
if (
|
||||
current_batch_id !=
|
||||
current_batch_id !==
|
||||
this.options.basicFieldParams
|
||||
.current_batch_id ||
|
||||
record_def.record.context.aborted
|
||||
|
@ -376,7 +408,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
);
|
||||
});
|
||||
},
|
||||
750,
|
||||
this._onchange_delay,
|
||||
this.options.basicFieldParams.current_batch_id,
|
||||
record_def
|
||||
);
|
||||
|
@ -387,6 +419,15 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates a complete virtual record
|
||||
*
|
||||
* @private
|
||||
* @param {Object} data
|
||||
* @param {Object} context
|
||||
* @param {Object} def_values
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_generateVirtualStateFull: function(data, context, def_values) {
|
||||
const model = this.options.basicFieldParams.model;
|
||||
return new Promise(resolve => {
|
||||
|
@ -441,6 +482,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
* @private
|
||||
* @param {Object} data
|
||||
* @param {Object} context
|
||||
* @param {Boolean} simple_mode
|
||||
* @returns {Object}
|
||||
*/
|
||||
_generateVirtualState: function(data, context, simple_mode) {
|
||||
|
@ -468,6 +510,7 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
* @param {Integer/String} record_id
|
||||
* @param {Object} changes
|
||||
* @param {Object} options
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_applyChanges: function(record_id, changes, options) {
|
||||
const model = this.options.basicFieldParams.model;
|
||||
|
@ -479,6 +522,9 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_detachAllWidgets: function() {
|
||||
_.invoke(this.widgets.front, "on_detach_callback");
|
||||
_.invoke(this.widgets.back, "on_detach_callback");
|
||||
|
@ -633,6 +679,9 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_updateLazyQty: function() {
|
||||
var model = this.options.basicFieldParams.model;
|
||||
var record = model.get(this.state.id);
|
||||
|
@ -664,12 +713,12 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
|
|||
const state_data = record.data;
|
||||
|
||||
let to_find = [];
|
||||
if (!_.isEmpty(fields)) {
|
||||
if (_.isEmpty(fields)) {
|
||||
to_find = ["[data-field]"];
|
||||
} else {
|
||||
to_find = _.map(fields, field => {
|
||||
return _.str.sprintf("[data-field=%s]", [field]);
|
||||
});
|
||||
} else {
|
||||
to_find = ["[data-field]"];
|
||||
}
|
||||
|
||||
this.$el.find(to_find.join()).each((key, value) => {
|
||||
|
|
|
@ -107,6 +107,14 @@ odoo.define(
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Because this widget doesn't support comments/sections line types
|
||||
* we need check if the line is valid to be shown.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} state
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
_isValidLineState: function(state) {
|
||||
return (
|
||||
state.data[this.options.field_map.product] &&
|
||||
|
@ -114,6 +122,12 @@ odoo.define(
|
|||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} state_a
|
||||
* @param {Object} state_b
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
_isEqualState: function(state_a, state_b) {
|
||||
if (state_a.id === state_b.id) {
|
||||
return true;
|
||||
|
@ -133,6 +147,11 @@ odoo.define(
|
|||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} state
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
_existsWidgetWithState: function(state) {
|
||||
for (let eb = this.widgets.length - 1; eb >= 0; --eb) {
|
||||
const widget = this.widgets[eb];
|
||||
|
@ -388,6 +407,7 @@ odoo.define(
|
|||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Array} datas
|
||||
* @returns {Array}
|
||||
*/
|
||||
|
@ -540,8 +560,7 @@ odoo.define(
|
|||
*
|
||||
* @private
|
||||
* @param {Array} search_records
|
||||
* @param {Boolean} no_process_records
|
||||
* @param {Number} position
|
||||
* @param {Object} options
|
||||
*/
|
||||
_appendSearchRecords: function(search_records, options) {
|
||||
const processed_info = options.no_process_records
|
||||
|
@ -569,8 +588,8 @@ odoo.define(
|
|||
}
|
||||
|
||||
// At this point the widget will use the existing state (line) or
|
||||
// the search data. Using search data instead of waiting for
|
||||
// simulated state gives a low FCP time.
|
||||
// a simple state data. Using simple state data instead of waiting for
|
||||
// complete state (default + onchange) gives a low FCP time.
|
||||
const def = $.Deferred();
|
||||
ProductPickerRecord.appendTo(this.$recordsContainer).then(
|
||||
function(widget, widget_position) {
|
||||
|
@ -622,9 +641,7 @@ odoo.define(
|
|||
* Append search records to the view
|
||||
*
|
||||
* @param {Array} search_records
|
||||
* @param {Boolean} no_attach_widgets
|
||||
* @param {Boolean} no_process_records
|
||||
* @param {Number} position
|
||||
* @param {Object} options
|
||||
* @returns {Array}
|
||||
*/
|
||||
appendSearchRecords: function(search_records, options = {}) {
|
||||
|
@ -690,6 +707,7 @@ odoo.define(
|
|||
* Handle card flip.
|
||||
* Used to create/update the record
|
||||
*
|
||||
* @private
|
||||
* @param {CustomEvent} evt
|
||||
*/
|
||||
_onRecordFlip: function(evt) {
|
||||
|
|
|
@ -12,22 +12,19 @@ odoo.define("web_widget_one2many_product_picker.BasicController", function(requi
|
|||
* @override
|
||||
*/
|
||||
_confirmChange: function(id, fields, e) {
|
||||
id = id || this.handle;
|
||||
return this._super.apply(this, arguments).then(() => {
|
||||
const product_picker_widgets = _.filter(
|
||||
this.renderer.allFieldWidgets[this.handle],
|
||||
item => item.attrs.widget === "one2many_product_picker"
|
||||
);
|
||||
for (const widget of product_picker_widgets) {
|
||||
const trigger_fields = widget.options.trigger_refresh_fields || [];
|
||||
if (
|
||||
_.difference(trigger_fields, fields).length !==
|
||||
trigger_fields.length
|
||||
) {
|
||||
widget._reset(this.model.get(this.handle), e);
|
||||
// Force re-launch onchanges on 'pure virtual' records
|
||||
widget.renderer.clearRecords();
|
||||
widget._render();
|
||||
}
|
||||
if (this.renderer && !_.isEmpty(this.renderer.allFieldWidgets)) {
|
||||
const product_picker_widgets = _.filter(
|
||||
this.renderer.allFieldWidgets[id],
|
||||
item => item.attrs.widget === "one2many_product_picker"
|
||||
);
|
||||
_.invoke(
|
||||
product_picker_widgets,
|
||||
"onDocumentConfirmChanges",
|
||||
fields,
|
||||
e
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
@ -74,6 +74,7 @@ odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
|
|||
* elements so can be removed safesly
|
||||
*
|
||||
* @param {String} id
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
removeVirtualRecord: function(id) {
|
||||
if (!this.isPureVirtual(id)) {
|
||||
|
@ -91,6 +92,7 @@ odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
|
|||
this.removeLine(remove_id);
|
||||
delete this.localData[remove_id];
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -158,6 +160,10 @@ odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
|
|||
return Promise.reject();
|
||||
}
|
||||
var def = new Promise(function(resolve, reject) {
|
||||
// Interrupt point (used in instant search)
|
||||
if (!self.exists(record.id)) {
|
||||
return Promise.reject();
|
||||
}
|
||||
var always = function() {
|
||||
if (record._warning) {
|
||||
if (params.allowWarning) {
|
||||
|
@ -329,28 +335,142 @@ odoo.define("web_widget_one2many_product_picker.BasicModel", function(require) {
|
|||
},
|
||||
|
||||
/**
|
||||
* This happens when the user discard main document changes (isn't a rollback)
|
||||
* Because records can be removed at any time we
|
||||
* need check if the record still existing.
|
||||
* Necessary for 'instant search' feature.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
discardChanges: function(id, options) {
|
||||
this._super.apply(this, arguments);
|
||||
options = options || {};
|
||||
var isNew = this.isNew(id);
|
||||
var rollback = "rollback" in options ? options.rollback : isNew;
|
||||
if (rollback) {
|
||||
return;
|
||||
_applyOnChange: function(values, record) {
|
||||
if (!this.exists(record.id)) {
|
||||
return Promise.reject();
|
||||
}
|
||||
const element = this.localData[id];
|
||||
this._visitChildren(element, function(elem) {
|
||||
if (
|
||||
elem &&
|
||||
elem.context &&
|
||||
elem.context.product_picker_modified &&
|
||||
_.isEmpty(elem._changes)
|
||||
) {
|
||||
elem.context.product_picker_modified = false;
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} recordID
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
hasChanges: function(recordID) {
|
||||
const record = this.localData[recordID];
|
||||
return record && !_.isEmpty(record._changes);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Object} model_fields
|
||||
* @param {String} model
|
||||
* @param {String} search_val
|
||||
* @param {Array} domain
|
||||
* @param {Array} fields
|
||||
* @param {Object} orderby
|
||||
* @param {String} operator
|
||||
* @param {Number} limit
|
||||
* @param {Number} offset
|
||||
* @param {Object} context
|
||||
* @returns {Promise}
|
||||
*/
|
||||
fetchNameSearchFull: function(
|
||||
model_fields,
|
||||
model,
|
||||
search_val,
|
||||
domain,
|
||||
fields,
|
||||
orderby,
|
||||
operator,
|
||||
limit,
|
||||
offset,
|
||||
context
|
||||
) {
|
||||
return this._rpc({
|
||||
model: model,
|
||||
method: "name_search",
|
||||
kwargs: {
|
||||
name: search_val,
|
||||
args: domain || [],
|
||||
operator: operator || "ilike",
|
||||
limit: this.limit,
|
||||
context: context || {},
|
||||
},
|
||||
}).then(results => {
|
||||
const record_ids = results.map(item => item[0]);
|
||||
return this.fetchGenericRecords(
|
||||
model_fields,
|
||||
model,
|
||||
[["id", "in", record_ids]],
|
||||
fields,
|
||||
orderby,
|
||||
limit,
|
||||
offset,
|
||||
context
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Object} model_fields
|
||||
* @param {String} model
|
||||
* @param {Array} domain
|
||||
* @param {Array} fields
|
||||
* @param {Array} orderby
|
||||
* @param {Number} limit
|
||||
* @param {Number} offset
|
||||
* @param {Object} context
|
||||
* @returns {Promise}
|
||||
*/
|
||||
fetchGenericRecords: function(
|
||||
model_fields,
|
||||
model,
|
||||
domain,
|
||||
fields,
|
||||
orderby,
|
||||
limit,
|
||||
offset,
|
||||
context
|
||||
) {
|
||||
return this._rpc({
|
||||
model: model,
|
||||
method: "search_read",
|
||||
fields: fields,
|
||||
domain: domain,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
orderBy: orderby,
|
||||
kwargs: {context: context},
|
||||
}).then(result => {
|
||||
for (const index in result) {
|
||||
const record = result[index];
|
||||
for (const fieldName in record) {
|
||||
const field = model_fields[fieldName];
|
||||
if (field.type !== "many2one") {
|
||||
record[fieldName] = this._parseServerValue(
|
||||
model_fields[fieldName],
|
||||
record[fieldName]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
},
|
||||
|
||||
fetchModelFieldsInfo: function(model) {
|
||||
return this._rpc({
|
||||
model: model,
|
||||
method: "fields_get",
|
||||
args: [
|
||||
false,
|
||||
[
|
||||
"store",
|
||||
"searchable",
|
||||
"type",
|
||||
"string",
|
||||
"relation",
|
||||
"selection",
|
||||
"related",
|
||||
],
|
||||
],
|
||||
context: this.getSession().user_context,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -42,7 +42,7 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
}),
|
||||
|
||||
_auto_search_delay: 450,
|
||||
_input_instant_search_time: 150,
|
||||
_input_instant_search_time: 100,
|
||||
|
||||
// Model product.product fields
|
||||
search_read_fields: ["id", "display_name", "uom_id"],
|
||||
|
@ -88,14 +88,25 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
},
|
||||
|
||||
willStart: function() {
|
||||
return this._super.apply(this, arguments).then(() => {
|
||||
if (this.isReadonly) {
|
||||
// Show Lines
|
||||
this._updateSearchContext(-1);
|
||||
} else {
|
||||
this._updateSearchContext(0);
|
||||
}
|
||||
});
|
||||
return this._super
|
||||
.apply(this, arguments)
|
||||
.then(() => {
|
||||
const arch = this.view.arch;
|
||||
const field_name = this.options.field_map.product;
|
||||
const field_info = this.view.fieldsInfo[arch.tag][field_name];
|
||||
const model = this.view.viewFields[field_info.name].relation;
|
||||
this._modelName = model;
|
||||
return this.parent_controller.model.fetchModelFieldsInfo(model);
|
||||
})
|
||||
.then(fields_info => {
|
||||
this._fieldsInfo = fields_info;
|
||||
if (this.isReadonly) {
|
||||
// Show Lines
|
||||
this._updateSearchContext(-1);
|
||||
} else {
|
||||
this._updateSearchContext(0);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -169,6 +180,26 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Because the widget shows "pure virtual" information, we don't have any 'onchange' linked.
|
||||
* This method forces 'refresh' the widget if the selected fields was changed.
|
||||
*
|
||||
* @param {Array} fields
|
||||
* @param {Event} e
|
||||
*/
|
||||
onDocumentConfirmChanges: function(fields, e) {
|
||||
const trigger_fields = this.options.trigger_refresh_fields || [];
|
||||
if (_.difference(trigger_fields, fields).length !== trigger_fields.length) {
|
||||
this._reset(
|
||||
this.parent_controller.model.get(this.parent_controller.handle),
|
||||
e
|
||||
);
|
||||
// Force re-launch onchanges on 'pure virtual' records
|
||||
this.renderer.clearRecords();
|
||||
this._render();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
|
@ -191,6 +222,9 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
group_def.active = !hasUserActive;
|
||||
hasUserActive = true;
|
||||
}
|
||||
if (!group_def.records_per_page) {
|
||||
group_def.records_per_page = 16;
|
||||
}
|
||||
this.searchGroups.push(group_def);
|
||||
}
|
||||
|
||||
|
@ -200,6 +234,7 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
domain: this.options.all_domain,
|
||||
order: false,
|
||||
active: !hasUserActive,
|
||||
records_per_page: 16,
|
||||
});
|
||||
this._activeSearchGroup = this.searchGroups[0];
|
||||
},
|
||||
|
@ -305,6 +340,16 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
this.updateSubtotalPrice();
|
||||
},
|
||||
|
||||
/**
|
||||
* Replace placeholders for search
|
||||
* - $number_search -> Is a number
|
||||
* - $search -> Is a string
|
||||
*
|
||||
* @private
|
||||
* @param {Number/String} value
|
||||
* @param {String} format
|
||||
* @returns {Number/String}
|
||||
*/
|
||||
_getSearchValue: function(value, format) {
|
||||
if (format === "$number_search") {
|
||||
return Number(value);
|
||||
|
@ -320,15 +365,10 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
*
|
||||
* @private
|
||||
* @param {Dictionary} options
|
||||
* @param {Boolean} merge
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
_getSearchRecords: function(options) {
|
||||
const arch = this.view.arch;
|
||||
const search_mode = this.options.search[this._searchMode];
|
||||
const field_name = this.options.field_map.product;
|
||||
const field_info = this.view.fieldsInfo[arch.tag][field_name];
|
||||
const model = this.view.viewFields[field_info.name].relation;
|
||||
const orderby = this._searchContext.order;
|
||||
const fields = this.search_read_fields;
|
||||
|
||||
|
@ -344,7 +384,7 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
},
|
||||
this.value.getContext()
|
||||
);
|
||||
const limit = soptions.limit || this.options.records_per_page;
|
||||
const limit = soptions.limit || this._activeSearchGroup.records_per_page;
|
||||
const offset = soptions.offset || 0;
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
@ -355,8 +395,9 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
search_mode.name_search_value
|
||||
);
|
||||
const operator = search_mode.operator;
|
||||
task = this._doSearchRecordsNameSearch(
|
||||
model,
|
||||
task = this.parent_controller.model.fetchNameSearchFull(
|
||||
this._fieldsInfo,
|
||||
this._modelName,
|
||||
search_val,
|
||||
domain,
|
||||
fields,
|
||||
|
@ -367,8 +408,9 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
context
|
||||
);
|
||||
} else {
|
||||
task = this._doSearchRecords(
|
||||
model,
|
||||
task = this.parent_controller.model.fetchGenericRecords(
|
||||
this._fieldsInfo,
|
||||
this._modelName,
|
||||
domain,
|
||||
fields,
|
||||
orderby,
|
||||
|
@ -386,76 +428,6 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
});
|
||||
},
|
||||
|
||||
_doSearchRecordsNameSearch: function(
|
||||
model,
|
||||
search_val,
|
||||
domain,
|
||||
fields,
|
||||
orderby,
|
||||
operator,
|
||||
limit,
|
||||
offset,
|
||||
context
|
||||
) {
|
||||
return new Promise(resolve => {
|
||||
this._rpc({
|
||||
model: model,
|
||||
method: "name_search",
|
||||
kwargs: {
|
||||
name: search_val,
|
||||
args: domain || [],
|
||||
operator: operator || "ilike",
|
||||
limit: this.limit,
|
||||
context: context || {},
|
||||
},
|
||||
}).then(results => {
|
||||
const record_ids = results.map(item => item[0]);
|
||||
this._doSearchRecords(
|
||||
model,
|
||||
[["id", "in", record_ids]],
|
||||
fields,
|
||||
orderby,
|
||||
limit,
|
||||
offset,
|
||||
context
|
||||
).then(records => {
|
||||
resolve(records);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} model
|
||||
* @param {Array} domain
|
||||
* @param {Array} fields
|
||||
* @param {Array} orderby
|
||||
* @param {Number} limit
|
||||
* @param {Number} offset
|
||||
* @param {Object} context
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_doSearchRecords: function(
|
||||
model,
|
||||
domain,
|
||||
fields,
|
||||
orderby,
|
||||
limit,
|
||||
offset,
|
||||
context
|
||||
) {
|
||||
return this._rpc({
|
||||
model: model,
|
||||
method: "search_read",
|
||||
fields: fields,
|
||||
domain: domain,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
orderBy: orderby,
|
||||
kwargs: {context: context},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} evt
|
||||
|
@ -514,7 +486,6 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
_getDefaultOptions: function() {
|
||||
return {
|
||||
currency_field: "currency_id",
|
||||
records_per_page: 16,
|
||||
show_subtotal: true,
|
||||
show_discount: false,
|
||||
edit_discount: false,
|
||||
|
@ -540,7 +511,7 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
* This domain is used to get the records to display.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} active_search
|
||||
* @param {Object} search_mode
|
||||
* @returns {Array}
|
||||
*/
|
||||
_getFullSearchDomain: function(search_mode) {
|
||||
|
@ -671,18 +642,24 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {SearchEvent} evt
|
||||
*/
|
||||
_onSearch: function(evt) {
|
||||
this._searchContext.text = evt.target.value;
|
||||
this.doRenderSearchRecords();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {InputEvent} evt
|
||||
*/
|
||||
_onInputSearch: function(evt) {
|
||||
if (!this.options.instant_search) {
|
||||
return;
|
||||
if (this.options.instant_search) {
|
||||
this._searchContext.text = evt.target.value;
|
||||
this._lazyRenderSearchRecords();
|
||||
}
|
||||
this._searchContext.text = evt.target.value;
|
||||
this._lazyRenderSearchRecords();
|
||||
// This.doRenderSearchRecords()
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -751,10 +728,6 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
}
|
||||
});
|
||||
} else {
|
||||
// This is used to know when need use 'yellow' color
|
||||
this.parent_controller.model.updateRecordContext(evt.data.id, {
|
||||
product_picker_modified: true,
|
||||
});
|
||||
// This will trigger an "state" update
|
||||
this._setValue({operation: "ADD", id: evt.data.id}).then(() => {
|
||||
if (evt.data.callback) {
|
||||
|
@ -764,6 +737,11 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Number} id
|
||||
* @param {Object} data
|
||||
* @param {Function} callback
|
||||
*/
|
||||
_doUpdateQuickRecord: function(id, data, callback) {
|
||||
if (this.options.auto_save) {
|
||||
var self = this;
|
||||
|
@ -790,10 +768,6 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
|
|||
}
|
||||
});
|
||||
} else {
|
||||
// This is used to know when need use 'yellow' color
|
||||
this.parent_controller.model.updateRecordContext(id, {
|
||||
product_picker_modified: true,
|
||||
});
|
||||
// This will trigger an "state" update
|
||||
this._setValue({operation: "UPDATE", id: id, data: data}).then(
|
||||
function() {
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
<t t-elif="!is_virtual">
|
||||
<span
|
||||
t-att-data-field="field_map[field_uom_qty]"
|
||||
t-attf-data-esc="str({{field_map[field_uom_qty]}}) + ' x ' + {{field_map[field_uom]}}.data.display_name"
|
||||
t-attf-data-esc="str({{floatFixed(field_map[field_uom_qty])}}) + ' x ' + {{field_map[field_uom]}}.data.display_name"
|
||||
t-attf-class="badge {{modified && 'badge-warning' || 'badge-success'}} font-weight-bold rounded-0 mt-0 px-2 py-3 product_qty"
|
||||
/>
|
||||
</t>
|
||||
|
|
Loading…
Reference in New Issue