enhance_search
This commit is contained in:
parent
eab53cde3e
commit
5b7ca42a0f
|
|
@ -125,6 +125,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
self._customSearchState.value = value;
|
||||
return self.update({}, {reload: false});
|
||||
}).catch(function(error) {
|
||||
console.error('FIMS Search Error:', error);
|
||||
self._showSearchError();
|
||||
return Promise.resolve();
|
||||
}).finally(function() {
|
||||
|
|
@ -177,11 +178,19 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* بناء domain للبحث - مع دعم non-stored fields
|
||||
* @param {String} value - قيمة البحث
|
||||
* @returns {Array} domain صحيح دائماً
|
||||
*/
|
||||
_buildCustomSearchDomain: function(value) {
|
||||
if (!value) return [];
|
||||
|
||||
var fields = this._getCustomSearchableFields();
|
||||
if (!fields || fields.length === 0) return [];
|
||||
if (!fields || fields.length === 0) {
|
||||
console.warn('FIMS Search: No searchable fields found');
|
||||
return [];
|
||||
}
|
||||
|
||||
var conditions = [];
|
||||
var normalized = this._normalizeText(value);
|
||||
|
|
@ -193,47 +202,70 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
fields.forEach(function(field) {
|
||||
var fieldType = field.type;
|
||||
var fieldName = field.name;
|
||||
var fieldPath = field.searchPath || fieldName; // دعم related fields
|
||||
|
||||
switch(fieldType) {
|
||||
case 'char':
|
||||
case 'text':
|
||||
case 'html':
|
||||
case 'many2one':
|
||||
case 'selection':
|
||||
searchValues.forEach(function(searchVal) {
|
||||
conditions.push([fieldName, 'ilike', searchVal]);
|
||||
conditions.push([fieldPath, 'ilike', searchVal]);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'many2one':
|
||||
// البحث في اسم الـ relation
|
||||
searchValues.forEach(function(searchVal) {
|
||||
conditions.push([fieldPath, 'ilike', searchVal]);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'selection':
|
||||
searchValues.forEach(function(searchVal) {
|
||||
conditions.push([fieldPath, 'ilike', searchVal]);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'integer':
|
||||
case 'float':
|
||||
case 'monetary':
|
||||
var numValue = parseFloat(value);
|
||||
if (!isNaN(numValue)) {
|
||||
conditions.push([fieldName, '=', numValue]);
|
||||
conditions.push([fieldPath, '=', numValue]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
var lowerValue = value.toLowerCase().trim();
|
||||
var boolMap = {
|
||||
'true': true, 'yes': true, '1': true,
|
||||
'false': false, 'no': false, '0': false
|
||||
'true': true, 'yes': true, '1': true, 'نعم': true,
|
||||
'false': false, 'no': false, '0': false, 'لا': false
|
||||
};
|
||||
if (lowerValue in boolMap) {
|
||||
conditions.push([fieldName, '=', boolMap[lowerValue]]);
|
||||
conditions.push([fieldPath, '=', boolMap[lowerValue]]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
if (value.match(/^\d{4}-\d{2}-\d{2}/)) {
|
||||
conditions.push([fieldName, 'ilike', value]);
|
||||
conditions.push([fieldPath, 'ilike', value]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if (conditions.length === 0) return [];
|
||||
if (conditions.length === 1) return conditions[0];
|
||||
// **الإصلاح الأساسي: التأكد من return domain صحيح دائماً**
|
||||
if (conditions.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// دائماً نُرجع array حتى لو condition واحد
|
||||
if (conditions.length === 1) {
|
||||
return conditions; // ✅ return [condition] وليس condition
|
||||
}
|
||||
|
||||
// بناء OR domain للـ conditions المتعددة
|
||||
var orDomain = [];
|
||||
for (var i = 1; i < conditions.length; i++) {
|
||||
orDomain.push('|');
|
||||
|
|
@ -241,7 +273,12 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
return orDomain.concat(conditions);
|
||||
},
|
||||
|
||||
/**
|
||||
* جلب الحقول القابلة للبحث - مع دعم computed/related fields
|
||||
* @returns {Array} قائمة الحقول
|
||||
*/
|
||||
_getCustomSearchableFields: function() {
|
||||
var self = this;
|
||||
var fields = [];
|
||||
var state = this.model.get(this.handle);
|
||||
|
||||
|
|
@ -251,53 +288,128 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
var fieldsInfo = state.fieldsInfo;
|
||||
var viewType = state.viewType || 'list';
|
||||
|
||||
// محاولة 1: جلب من fieldsInfo (الحقول الموجودة في الـ view)
|
||||
if (fieldsInfo && fieldsInfo[viewType]) {
|
||||
Object.keys(fieldsInfo[viewType]).forEach(function(fieldName) {
|
||||
var fieldInfo = fieldsInfo[viewType][fieldName];
|
||||
if (fieldInfo && !fieldInfo.invisible && fieldDefs[fieldName]) {
|
||||
var fieldDef = fieldDefs[fieldName];
|
||||
if (fieldDef.store !== false && fieldDef.searchable !== false) {
|
||||
|
||||
// **التعديل الأساسي: إزالة شرط store**
|
||||
// نقبل جميع الحقول القابلة للبحث سواء stored أو computed
|
||||
if (self._isFieldSearchable(fieldDef)) {
|
||||
fields.push({
|
||||
name: fieldName,
|
||||
type: fieldDef.type,
|
||||
string: fieldDef.string || fieldName
|
||||
string: fieldDef.string || fieldName,
|
||||
searchPath: self._getFieldSearchPath(fieldName, fieldDef)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// محاولة 2: جلب من columns (إذا لم نجد في fieldsInfo)
|
||||
if (fields.length === 0 && this.renderer && this.renderer.columns) {
|
||||
this.renderer.columns.forEach(function(col) {
|
||||
if (!col.invisible && col.attrs && col.attrs.name) {
|
||||
var fieldName = col.attrs.name;
|
||||
var field = fieldDefs[fieldName];
|
||||
if (field && field.store !== false) {
|
||||
if (field && self._isFieldSearchable(field)) {
|
||||
fields.push({
|
||||
name: fieldName,
|
||||
type: field.type,
|
||||
string: field.string || fieldName
|
||||
string: field.string || fieldName,
|
||||
searchPath: self._getFieldSearchPath(fieldName, field)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// محاولة 3: حقول افتراضية (fallback)
|
||||
if (fields.length === 0) {
|
||||
['name', 'display_name', 'code', 'reference'].forEach(function(fname) {
|
||||
if (fieldDefs[fname] && fieldDefs[fname].store !== false) {
|
||||
['name', 'display_name', 'login', 'code', 'reference', 'email'].forEach(function(fname) {
|
||||
if (fieldDefs[fname] && self._isFieldSearchable(fieldDefs[fname])) {
|
||||
fields.push({
|
||||
name: fname,
|
||||
type: fieldDefs[fname].type,
|
||||
string: fieldDefs[fname].string || fname
|
||||
string: fieldDefs[fname].string || fname,
|
||||
searchPath: self._getFieldSearchPath(fname, fieldDefs[fname])
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('FIMS Search: Found', fields.length, 'searchable fields:',
|
||||
fields.map(f => f.searchPath || f.name).join(', '));
|
||||
|
||||
return fields;
|
||||
},
|
||||
|
||||
/**
|
||||
* التحقق من إمكانية البحث في الحقل
|
||||
* @param {Object} fieldDef - تعريف الحقل
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
_isFieldSearchable: function(fieldDef) {
|
||||
if (!fieldDef) return false;
|
||||
|
||||
// استبعاد الحقول الخاصة
|
||||
var excludedTypes = ['binary', 'one2many', 'many2many', 'reference'];
|
||||
if (excludedTypes.indexOf(fieldDef.type) !== -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// إذا الحقل صرّح أنه غير قابل للبحث
|
||||
if (fieldDef.searchable === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// **التعديل الأساسي: قبول computed fields**
|
||||
// stored fields = بحث مباشر
|
||||
// computed fields = بحث عبر related path إذا وُجد
|
||||
// related fields = بحث عبر related path
|
||||
|
||||
// نقبل الحقل إذا:
|
||||
// 1. stored field
|
||||
// 2. computed field مع related
|
||||
// 3. related field
|
||||
if (fieldDef.store !== false ||
|
||||
fieldDef.related ||
|
||||
fieldDef.compute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* الحصول على المسار الصحيح للبحث في الحقل
|
||||
* @param {String} fieldName - اسم الحقل
|
||||
* @param {Object} fieldDef - تعريف الحقل
|
||||
* @returns {String} - المسار للبحث
|
||||
*/
|
||||
_getFieldSearchPath: function(fieldName, fieldDef) {
|
||||
// إذا كان related field، نستخدم الـ related path
|
||||
if (fieldDef.related && fieldDef.related.length > 0) {
|
||||
return fieldDef.related.join('.');
|
||||
}
|
||||
|
||||
// إذا كان computed مع related في الـ definition
|
||||
if (fieldDef.store === false && fieldDef.depends) {
|
||||
// محاولة استخراج أول depend كـ search path
|
||||
var depends = fieldDef.depends;
|
||||
if (depends && depends.length > 0) {
|
||||
// استخدام أول dependency
|
||||
return depends[0];
|
||||
}
|
||||
}
|
||||
|
||||
// default: استخدام اسم الحقل مباشرة
|
||||
return fieldName;
|
||||
},
|
||||
|
||||
_combineCustomDomains: function(searchDomain) {
|
||||
var originalDomain = this._customSearchState.originalDomain || [];
|
||||
|
||||
|
|
@ -323,7 +435,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
_showSearchError: function() {
|
||||
if (this.renderer && this.renderer.$) {
|
||||
this.renderer.$('.oe_search_count')
|
||||
.text(_t('Search error occurred'))
|
||||
.text(_t('حدث خطأ في البحث'))
|
||||
.addClass('text-danger')
|
||||
.show();
|
||||
}
|
||||
|
|
@ -347,21 +459,17 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
});
|
||||
|
||||
ListRenderer.include({
|
||||
// **إزالة events من class definition لتجنب التعارضات**
|
||||
// سيتم ربط events programmatically عند الحاجة فقط
|
||||
|
||||
init: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this._searchTimer = null;
|
||||
this._customSearchReady = false;
|
||||
this._lastInputValue = '';
|
||||
this._customEventsbound = false; // تجنب double binding
|
||||
this._customEventsbound = false;
|
||||
},
|
||||
|
||||
_renderView: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function (result) {
|
||||
// تأخير قليل للتأكد من DOM readiness
|
||||
setTimeout(function() {
|
||||
try {
|
||||
if (self._shouldAddSearchBox()) {
|
||||
|
|
@ -373,7 +481,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
} catch (error) {
|
||||
console.error('FIMS Search: Error in _renderView:', error);
|
||||
}
|
||||
}, 50); // تأخير أكبر قليلاً للاستقرار
|
||||
}, 50);
|
||||
return result;
|
||||
});
|
||||
},
|
||||
|
|
@ -411,7 +519,6 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
|
||||
_shouldAddSearchBox: function() {
|
||||
try {
|
||||
// **فحوصات الأمان الأساسية**
|
||||
if (!this.arch ||
|
||||
this.arch.tag !== 'tree' ||
|
||||
!this.$el ||
|
||||
|
|
@ -421,30 +528,18 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// **الحل النهائي المؤكد: فحص hasSelectors**
|
||||
// embedded tree views: hasSelectors = false أو undefined
|
||||
// standalone tree views: hasSelectors = true
|
||||
|
||||
if (this.hasSelectors === false) {
|
||||
console.log('FIMS Search: Hidden - embedded tree view (hasSelectors = false)');
|
||||
return false;
|
||||
}
|
||||
|
||||
// **فحوصات إضافية للأمان:**
|
||||
|
||||
// فحص DOM structure كـ backup
|
||||
if (this.$el.closest('.o_form_view').length > 0) {
|
||||
console.log('FIMS Search: Hidden - inside form view');
|
||||
return false;
|
||||
}
|
||||
|
||||
// فحص field widget
|
||||
if (this.$el.closest('.o_field_widget').length > 0) {
|
||||
console.log('FIMS Search: Hidden - inside field widget');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('FIMS Search: Shown - standalone tree view (hasSelectors:', this.hasSelectors, ')');
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
|
|
@ -455,9 +550,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
|
||||
_addCustomSearchBox: function() {
|
||||
try {
|
||||
// **التحقق من DOM validity**
|
||||
if (!this.$el || !this.$el.length) {
|
||||
console.warn('FIMS Search: Invalid DOM element');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -512,16 +605,14 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
}
|
||||
},
|
||||
|
||||
// **ربط Events programmatically**
|
||||
_bindCustomEvents: function() {
|
||||
if (this._customEventsbound) {
|
||||
return; // تجنب double binding
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var self = this;
|
||||
|
||||
// bind events to the search container
|
||||
this.$el.on('keyup', '.oe_search_input', function(e) {
|
||||
self._onCustomSearchKeyUp(e);
|
||||
});
|
||||
|
|
@ -544,7 +635,6 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
|
|||
}
|
||||
},
|
||||
|
||||
// **تنظيف Events عند destroy**
|
||||
destroy: function() {
|
||||
if (this._customEventsbound) {
|
||||
this.$el.off('keyup', '.oe_search_input');
|
||||
|
|
|
|||
Loading…
Reference in New Issue