diff --git a/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js b/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js index 1a00f019e..68e12334e 100644 --- a/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js +++ b/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js @@ -6,7 +6,6 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { var _t = core._t; var session = require('web.session'); var pyUtils = require('web.py_utils'); - var Domain = require('web.Domain'); ListRenderer.include({ events: _.extend({}, ListRenderer.prototype.events, { @@ -146,6 +145,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { // Store original data if first search if (!this._searchState.originalData) { this._searchState.originalData = this._captureCurrentData(); + console.log('Captured original data:', this._searchState.originalData); } // Build and execute search @@ -195,15 +195,34 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { * Capture current data state */ _captureCurrentData: function() { - // Try to get current records from various locations - if (this.state && this.state.data) { - return { - records: this.state.data.records ? this.state.data.records.slice() : [], - count: this.state.count || 0, - domain: this.state.domain ? this.state.domain.slice() : [] - }; + var data = { + records: [], + count: 0, + domain: [], + limit: 80, + offset: 0 + }; + + // Get current records + if (this.state) { + if (this.state.data && this.state.data.records) { + data.records = this.state.data.records.slice(); + } + if (this.state.count !== undefined) { + data.count = this.state.count; + } + if (this.state.domain) { + data.domain = Array.isArray(this.state.domain) ? this.state.domain.slice() : this.state.domain; + } + if (this.state.limit !== undefined) { + data.limit = this.state.limit; + } + if (this.state.offset !== undefined) { + data.offset = this.state.offset; + } } - return null; + + return data; }, /** @@ -277,7 +296,21 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { } // Combine with AND operator - return ['&'].concat(baseDomain).concat(searchDomain); + // Need to be careful with domain structure + var result = []; + + // Add AND operator if both domains exist + if (baseDomain.length > 0 && searchDomain.length > 0) { + result.push('&'); + } + + // Add base domain + result = result.concat(baseDomain); + + // Add search domain + result = result.concat(searchDomain); + + return result; }, /** @@ -353,21 +386,21 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { var conditions = []; var self = this; - // Escape special characters for safe search - var safeValue = this._escapeSearchValue(value); - var normalizedValue = this._normalizeArabic(safeValue); + // Don't escape for now - let's keep it simple + var searchValue = value; + var normalizedValue = this._normalizeArabic(searchValue); fields.forEach(function(field) { // Text-based fields if (['char', 'text', 'html'].includes(field.type)) { - conditions.push([field.name, 'ilike', safeValue]); - if (normalizedValue && normalizedValue !== safeValue) { + conditions.push([field.name, 'ilike', searchValue]); + if (normalizedValue && normalizedValue !== searchValue) { conditions.push([field.name, 'ilike', normalizedValue]); } } // Selection fields else if (field.type === 'selection') { - conditions.push([field.name, 'ilike', safeValue]); + conditions.push([field.name, 'ilike', searchValue]); } // Number fields else if (['integer', 'float', 'monetary'].includes(field.type)) { @@ -401,14 +434,6 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { return domain.concat(conditions); }, - /** - * Escape special characters in search value - */ - _escapeSearchValue: function(value) { - // Remove dangerous characters that might break domain - return value.replace(/[%_\\]/g, '\\$&'); - }, - /** * Execute RPC search */ @@ -419,6 +444,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { console.log('Executing RPC search...'); console.log('Model:', model); + console.log('Domain for RPC:', JSON.stringify(domain)); console.log('Fields to read:', fields); this._rpc({ @@ -433,6 +459,9 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { } }).then(function(result) { console.log('Search completed. Found:', result.length, 'records'); + if (result.length > 0) { + console.log('First result:', result[0]); + } self._handleSearchResults(result, searchValue); }).catch(function(error) { console.error('RPC Error:', error); @@ -444,14 +473,15 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { }, /** - * Get fields to read + * Get fields to read - CRITICAL: Must match the original fields structure */ _getFieldsToRead: function() { var fields = ['id']; var fieldsInfo = this._getFieldsInfo(); if (!fieldsInfo) { - return ['id', 'display_name']; + // Return all fields if we can't determine + return false; // This tells Odoo to return all fields } // Add visible column fields @@ -462,7 +492,8 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { var fieldInfo = fieldsInfo[fieldName]; // Skip computed non-stored fields - if (!fieldInfo || (fieldInfo.compute && !fieldInfo.store)) { + if (fieldInfo && fieldInfo.compute && !fieldInfo.store) { + console.log('Skipping computed field:', fieldName); return; } @@ -476,6 +507,11 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { fields.push('display_name'); } + // Add __last_update for proper record tracking + if (fieldsInfo.__last_update) { + fields.push('__last_update'); + } + return _.uniq(fields); }, @@ -484,25 +520,156 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { */ _getSearchContext: function() { var context = _.extend({}, this.state.context || {}, session.user_context || {}); - // Remove active_test to include inactive records - delete context.active_test; + // Don't remove active_test - keep original context return context; }, /** - * Handle search results + * Handle search results - THIS IS THE CRITICAL PART */ _handleSearchResults: function(records, searchValue) { var count = records.length; + console.log('Handling search results:', count, 'records'); if (count > 0) { - this._updateView(records); + // Update the view with new records + this._updateViewWithRecords(records); this._showResultCount(count); } else { this._showNoResults(searchValue); } }, + /** + * Update view with search results - PROPER WAY + */ + _updateViewWithRecords: function(records) { + var self = this; + console.log('Updating view with', records.length, 'records'); + + // Method 1: Update state and trigger re-render + if (this.state && this.state.data) { + // Update the data + this.state.data.records = records; + this.state.data.count = records.length; + this.state.count = records.length; + + // Update res_ids if it exists + if (this.state.res_ids) { + this.state.res_ids = records.map(function(r) { return r.id; }); + } + + console.log('State updated, attempting to re-render...'); + + // Try different render methods + // Method A: Direct _renderBody + if (typeof this._renderBody === 'function') { + try { + console.log('Calling _renderBody...'); + var renderPromise = this._renderBody(); + if (renderPromise && typeof renderPromise.then === 'function') { + renderPromise.then(function() { + console.log('_renderBody completed successfully'); + self._restoreSearchValue(); + }).catch(function(error) { + console.error('_renderBody promise error:', error); + self._tryAlternativeRender(records); + }); + } else { + console.log('_renderBody completed (non-promise)'); + self._restoreSearchValue(); + } + } catch (error) { + console.error('_renderBody error:', error); + this._tryAlternativeRender(records); + } + } else { + console.log('_renderBody not available, trying alternative...'); + this._tryAlternativeRender(records); + } + } else { + console.error('No state.data to update'); + this._tryAlternativeRender(records); + } + }, + + /** + * Try alternative rendering method + */ + _tryAlternativeRender: function(records) { + var self = this; + console.log('Trying alternative render method...'); + + // Method B: Try to trigger parent update + if (this.trigger_up) { + console.log('Triggering update event...'); + this.trigger_up('update', { + records: records, + domain: this._searchState.lastSearchDomain + }); + } + + // Method C: Manual DOM update as last resort + // Hide non-matching rows and show matching ones + var recordIds = records.map(function(r) { return r.id; }); + console.log('Record IDs to show:', recordIds); + + // First hide all rows + this.$('.o_data_row').hide(); + + // Then show matching rows + recordIds.forEach(function(id) { + self.$('.o_data_row[data-id="' + id + '"]').show(); + }); + + // If no visible rows after filtering, we might need to render them + var visibleRows = this.$('.o_data_row:visible').length; + console.log('Visible rows after filtering:', visibleRows); + + if (visibleRows === 0 && records.length > 0) { + console.log('No visible rows but have records, may need full re-render'); + // The records might not be in the current DOM, need full render + this._forceFullRender(records); + } + + this._restoreSearchValue(); + }, + + /** + * Force full render of records + */ + _forceFullRender: function(records) { + console.log('Forcing full render...'); + + // Store records in state + if (this.state && this.state.data) { + this.state.data.records = records; + } + + // Try to call parent's reload if available + if (this.getParent && typeof this.getParent === 'function') { + var parent = this.getParent(); + if (parent && parent.reload) { + console.log('Calling parent reload...'); + parent.reload({ + offset: 0, + limit: records.length, + domain: this._searchState.lastSearchDomain + }); + } + } + }, + + /** + * Restore search value in input + */ + _restoreSearchValue: function() { + if (this._searchState && this._searchState.currentValue) { + this.$('.oe_search_input').val(this._searchState.currentValue); + this.$('.oe_clear_search').show(); + } + }, + /** * Handle search error */ @@ -512,27 +679,6 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { this._fallbackToClientSearch(searchValue); }, - /** - * Update view with search results - */ - _updateView: function(records) { - // This is the tricky part - we need to update the view - // Different versions of Odoo handle this differently - - if (this.state && this.state.data) { - this.state.data.records = records; - } - - // Try to re-render - if (typeof this._renderBody === 'function') { - try { - this._renderBody(); - } catch (e) { - console.error('Error rendering body:', e); - } - } - }, - /** * Fallback to client-side search */ @@ -542,18 +688,30 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { var searchLower = value.toLowerCase(); var normalizedSearch = this._normalizeArabic(searchLower); var visibleCount = 0; + var totalCount = 0; this.$('.o_data_row').each(function() { var $row = $(this); + totalCount++; + var text = $row.text().toLowerCase(); var normalizedText = this._normalizeArabic(text); - var match = text.includes(searchLower) || normalizedText.includes(normalizedSearch); + var match = text.includes(searchLower) || + (normalizedText && normalizedSearch && normalizedText.includes(normalizedSearch)); + $row.toggle(match); if (match) visibleCount++; }.bind(this)); - this._showResultCount(visibleCount, true); + // Remove no results message if exists + this.$('.oe_no_results').remove(); + + if (visibleCount === 0) { + this._showNoResults(value); + } else { + this._showResultCount(visibleCount, true); + } }, /** @@ -576,11 +734,14 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { // Restore original data if (this._searchState.originalData) { this._restoreOriginalData(); + } else { + // Just show all rows + this.$('.o_data_row').show(); } + } else { + // Show all rows + this.$('.o_data_row').show(); } - - // Show all rows - this.$('.o_data_row').show(); }, /** @@ -591,19 +752,46 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { return; } + console.log('Restoring original data...'); var originalData = this._searchState.originalData; - if (this.state && this.state.data) { - this.state.data.records = originalData.records; + // Restore state + if (this.state) { + if (this.state.data && originalData.records) { + this.state.data.records = originalData.records; + this.state.data.count = originalData.count || originalData.records.length; + } + if (originalData.count !== undefined) { + this.state.count = originalData.count; + } + if (originalData.res_ids) { + this.state.res_ids = originalData.res_ids; + } } - // Re-render if possible + // Re-render if (typeof this._renderBody === 'function') { try { - this._renderBody(); + var renderPromise = this._renderBody(); + if (renderPromise && typeof renderPromise.then === 'function') { + renderPromise.then(function() { + console.log('Original data restored successfully'); + }).catch(function(error) { + console.error('Error restoring original data:', error); + // Fallback: show all rows + this.$('.o_data_row').show(); + }.bind(this)); + } else { + console.log('Original data restored'); + } } catch (e) { console.error('Error restoring view:', e); + // Fallback: show all rows + this.$('.o_data_row').show(); } + } else { + // Fallback: show all rows + this.$('.o_data_row').show(); } this._searchState.originalData = null;