enhance_search

This commit is contained in:
Mohamed Eltayar 2025-10-01 16:48:42 +03:00 committed by GitHub
parent eab53cde3e
commit 5b7ca42a0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 134 additions and 44 deletions

View File

@ -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');