diff --git a/web_widget_one2many_product_picker/README.rst b/web_widget_one2many_product_picker/README.rst
index 21ec5ffbe..c8969bdfe 100644
--- a/web_widget_one2many_product_picker/README.rst
+++ b/web_widget_one2many_product_picker/README.rst
@@ -23,7 +23,7 @@ Web Widget One2Many Product Picker
:target: https://runbot.odoo-community.org/runbot/162/13.0
:alt: Try me on Runbot
-|badge1| |badge2| |badge3| |badge4| |badge5|
+|badge1| |badge2| |badge3| |badge4| |badge5|
Adds the 'one2many_product_picker' friendly mobile widget to create one2many lines linked with product.product records.
@@ -68,7 +68,7 @@ Widget options:
* price_unit -> The field that represent a price_unit ('price_unit' by default)
* discount -> The field that represent a discount ('discount' by default)
-* search > Array of dictionaries or Array of 'triplets' ([[field_map.name, 'ilike', '$search']] by default)
+* search > Array of dictionaries (defines to use name_search by default)
* name -> The name to display
* domain -> The domain to use
@@ -76,6 +76,9 @@ Widget options:
* $search -> Replaces it with the current value of the searchbox
* $number_search -> Replaces all the leaf with the current value of the searchbox as a number
+ * name_search_value -> Enables the use of 'name_search' instead of 'search_read' and defines the value to search ('$search' by default)
+ * operator -> Operator used in 'name_search' ('ilike' by default)
+
* edit_discount > Enable/Disable discount edits (False by default)
* edit_price > Enable/Disable price edits (True by default)
* show_discount > Enable/Disable display discount (False by default)
diff --git a/web_widget_one2many_product_picker/readme/CONFIGURE.rst b/web_widget_one2many_product_picker/readme/CONFIGURE.rst
index 29d8e9813..f6ecea085 100644
--- a/web_widget_one2many_product_picker/readme/CONFIGURE.rst
+++ b/web_widget_one2many_product_picker/readme/CONFIGURE.rst
@@ -26,7 +26,7 @@ Widget options:
* price_unit -> The field that represent a price_unit ('price_unit' by default)
* discount -> The field that represent a discount ('discount' by default)
-* search > Array of dictionaries or Array of 'triplets' ([[field_map.name, 'ilike', '$search']] by default)
+* search > Array of dictionaries (defines to use name_search by default)
* name -> The name to display
* domain -> The domain to use
@@ -34,6 +34,9 @@ Widget options:
* $search -> Replaces it with the current value of the searchbox
* $number_search -> Replaces all the leaf with the current value of the searchbox as a number
+ * name_search_value -> Enables the use of 'name_search' instead of 'search_read' and defines the value to search ('$search' by default)
+ * operator -> Operator used in 'name_search' ('ilike' by default)
+
* edit_discount > Enable/Disable discount edits (False by default)
* edit_price > Enable/Disable price edits (True by default)
* show_discount > Enable/Disable display discount (False by default)
diff --git a/web_widget_one2many_product_picker/static/description/index.html b/web_widget_one2many_product_picker/static/description/index.html
index a83807324..c04f874a3 100644
--- a/web_widget_one2many_product_picker/static/description/index.html
+++ b/web_widget_one2many_product_picker/static/description/index.html
@@ -442,7 +442,7 @@ You need to define the view fields. The view must be of search > Array of dictionaries or Array of ‘triplets’ ([[field_map.name, ‘ilike’, ‘$search’]] by default)
+search > Array of dictionaries (defines to use name_search by default)
diff --git a/web_widget_one2many_product_picker/static/src/js/widgets/field_one2many_product_picker.js b/web_widget_one2many_product_picker/static/src/js/widgets/field_one2many_product_picker.js
index 8e7364969..074983d1a 100644
--- a/web_widget_one2many_product_picker/static/src/js/widgets/field_one2many_product_picker.js
+++ b/web_widget_one2many_product_picker/static/src/js/widgets/field_one2many_product_picker.js
@@ -59,15 +59,18 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
this.attrs.options
);
if (!this.options.search) {
+ // Default search domain
this.options.search = [
- [this.options.field_map.name, "ilike", "$search"],
+ {
+ name: _t("By Name"),
+ domain: [],
+ name_search_value: "$search",
+ },
];
}
this._searchMode = 0;
- this._searchCategoryNames = [];
- if (!(this.options.search[0] instanceof Array)) {
- this._searchCategoryNames = _.map(this.options.search, "name");
- }
+ this._searchCategoryNames = _.map(this.options.search, "name");
+ this._searchContext = {};
// FIXME: Choose a better way to get the active controller or model objects
this.parent_controller = parent.getParent();
@@ -84,18 +87,10 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
return Promise.resolve();
}
- // Uses to work with searchs, so we can mix properties with the user values.
- this._searchContext = {
- domain: this.mode === "readonly" ? this._getLinesDomain() : false,
- text: false,
- order: false,
- activeTest: true,
- };
if (this.mode === "readonly") {
- this._activeSearchGroup = {
- name: "main_lines",
- };
- this._searchContext.activeTest = false;
+ this._updateSearchContext(-1);
+ } else {
+ this._updateSearchContext(0);
}
return Promise.all([
this._super.apply(this, arguments),
@@ -310,6 +305,15 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
this.updateSubtotalPrice();
},
+ _getSearchValue: function(value, format) {
+ if (format === "$number_search") {
+ return Number(value);
+ } else if (typeof value === "string") {
+ return format.replace(/\$search/, value);
+ }
+ return value;
+ },
+
/**
* Obtain the linked records defined in the options.
* If merge is true the current records aren't removed.
@@ -321,13 +325,16 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
*/
_getSearchRecords: function(options, merge) {
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;
// Launch the rpc request and ensures that we wait for the reply
// to continue
- const domain = this._getFullSearchDomain();
+ const domain = this._getFullSearchDomain(search_mode);
const soptions = options || {};
const context = _.extend(
{
@@ -337,20 +344,41 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
},
this.value.getContext()
);
+ const limit = soptions.limit || this.options.records_per_page;
+ const offset = soptions.offset || 0;
return new Promise(resolve => {
- const limit = soptions.limit || this.options.records_per_page;
- const offset = soptions.offset || 0;
- this._rpc({
- model: model,
- method: "search_read",
- fields: this.search_read_fields,
- domain: domain,
- limit: limit,
- offset: offset,
- orderBy: this._searchContext.order,
- kwargs: {context: context},
- }).then(results => {
+ let task = false;
+ if (search_mode.name_search_value) {
+ const search_val = this._getSearchValue(
+ this._searchContext.text,
+ search_mode.name_search_value
+ );
+ const operator = search_mode.operator;
+ task = this._doSearchRecordsNameSearch(
+ model,
+ search_val,
+ domain,
+ fields,
+ orderby,
+ operator,
+ limit,
+ offset,
+ context
+ );
+ } else {
+ task = this._doSearchRecords(
+ model,
+ domain,
+ fields,
+ orderby,
+ limit,
+ offset,
+ context
+ );
+ }
+
+ task.then(results => {
if (merge) {
this._searchRecords = _.union(
this._searchRecords || [],
@@ -368,11 +396,82 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
this._activeSearchGroup
);
}
+
resolve(results);
});
});
},
+ _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
@@ -380,12 +479,7 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
_onClickSearchGroup: function(evt) {
const $btn = $(evt.target);
const groupIndex = Number($btn.data("group")) || 0;
- this._activeSearchGroup = this.searchGroups[groupIndex];
- this._searchContext.domain = this._activeSearchGroup.domain;
- this._searchContext.order = this._activeSearchGroup.order;
- this._searchContext.activeTest = true;
- this.doRenderSearchRecords();
- this.$btnLines.removeClass("active");
+ this.showGroup(groupIndex);
$btn.parent()
.find(".active")
.removeClass("active");
@@ -459,16 +553,14 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
* This domain is used to get the records to display.
*
* @private
+ * @param {Object} active_search
* @returns {Array}
*/
- _getFullSearchDomain: function() {
+ _getFullSearchDomain: function(search_mode) {
this._searchContext.involvedFields = [];
const domain = _.clone(this._searchContext.domain) || [];
if (this._searchContext.text) {
- let search_domain = this.options.search;
- if (!(search_domain[0] instanceof Array)) {
- search_domain = search_domain[this._searchMode].domain;
- }
+ const search_domain = search_mode.domain;
const involved_fields = [];
// Iterate domain triplets and logic operators
@@ -478,27 +570,15 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
// Is a triplet
if (domain_cloned instanceof Array) {
// Replace right leaf with the current value of the search input
- if (domain_cloned[2] === "$number_search") {
- domain_cloned[2] = Number(this._searchContext.text);
- involved_fields.push({
- type: "number",
- field: domain_cloned[0],
- oper: domain_cloned[1],
- });
- } else if (
- typeof domain_cloned[2] === "string" &&
- domain_cloned[2].includes("$search")
- ) {
- domain_cloned[2] = domain_cloned[2].replace(
- /\$search/,
- this._searchContext.text
- );
- involved_fields.push({
- type: "text",
- field: domain_cloned[0],
- oper: domain_cloned[1],
- });
- }
+ domain_cloned[2] = this._getSearchValue(
+ domain_cloned[2],
+ this._searchContext.text
+ );
+ involved_fields.push({
+ type: "number",
+ field: domain_cloned[0],
+ oper: domain_cloned[1],
+ });
}
domain.push(domain_cloned);
}
@@ -528,32 +608,57 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
return [["id", "in", ids]];
},
+ /**
+ * @param {Number} group_id
+ */
+ _updateSearchContext: function(group_id) {
+ if (group_id >= 0) {
+ this._activeSearchGroup = this.searchGroups[group_id];
+ this._searchContext.domain = this._activeSearchGroup.domain;
+ this._searchContext.order = this._activeSearchGroup.order;
+ this._searchContext.activeTest = this._activeSearchGroup.active_test;
+ } else {
+ this._activeSearchGroup = {
+ name: "main_lines",
+ };
+ this._searchContext.domain = this._getLinesDomain();
+ this._searchContext.order = [{name: "sequence"}, {name: "id"}];
+ this._searchContext.activeTest = false;
+ }
+ },
+
/**
* The lines are special data, so we need display it in a other way
* that the search results. Use directy in-memory values.
*/
showLines: function() {
+ this._updateSearchContext(-1);
this._clearSearchInput();
this.$btnLines
.parent()
.find(".active")
.removeClass("active");
this.$btnLines.addClass("active");
- this._activeSearchGroup = {
- name: "main_lines",
- };
- this._searchContext.domain = this._getLinesDomain();
- this._searchContext.order = [{name: "sequence"}, {name: "id"}];
- this._searchContext.activeTest = false;
this.doRenderSearchRecords();
},
+ /**
+ * @param {Number} group_id
+ */
+ showGroup: function(group_id) {
+ this._updateSearchContext(group_id);
+ this.doRenderSearchRecords();
+ this.$btnLines.removeClass("active");
+ },
+
/**
* @private
*/
_clearSearchInput: function() {
- this.$searchInput.val("");
- this._searchContext.text = "";
+ if (this.$searchInput) {
+ this.$searchInput.val("");
+ this._searchContext.text = "";
+ }
},
/**