diff --git a/models/res_partner.py b/models/res_partner.py index 59e70de..644aa56 100644 --- a/models/res_partner.py +++ b/models/res_partner.py @@ -63,7 +63,7 @@ class ResPartner(models.Model): # Find the lowest membership program level (Membership Silver) lowest_program = self.env['loyalty.program'].sudo().search( - [('multi_level_membership', '=', True), ('name', '=ilike', 'Membership Silver')], + [('multi_level_membership', '=', True), ('manual_membership', '=', False), ('name', '=ilike', 'Membership Silver')], limit=1 ) if not lowest_program: diff --git a/static/src/app/screens/partner_list_patch.js b/static/src/app/screens/partner_list_patch.js index 1584c7b..5071d17 100644 --- a/static/src/app/screens/partner_list_patch.js +++ b/static/src/app/screens/partner_list_patch.js @@ -2,11 +2,55 @@ import { PartnerList } from "@point_of_sale/app/screens/partner_list/partner_list"; import { patch } from "@web/core/utils/patch"; +import { normalize } from "@web/core/l10n/utils"; patch(PartnerList.prototype, { getPartners(partners) { // Filter the partner list to strictly only display partners who are loyalty members const filteredPartners = partners.filter((p) => p.is_loyalty_member); - return super.getPartners(filteredPartners); + + const searchWord = normalize(this.state.query?.trim() ?? ""); + if (!searchWord) { + // When query is empty, slice and sort following standard POS behavior + return filteredPartners + .slice(0, 1000) + .toSorted((a, b) => + this.props.partner?.id === a.id + ? -1 + : this.props.partner?.id === b.id + ? 1 + : (a.name || "").localeCompare(b.name || "") + ); + } + + // When query is present, optimize search filtering + const exactMatches = filteredPartners.filter((partner) => partner.exactMatch(searchWord)); + if (exactMatches.length > 0) { + return exactMatches; + } + + const numberString = searchWord.replace(/[+\s()-]/g, ""); + const isSearchWordNumber = /^[0-9]+$/.test(numberString); + const patternBase = isSearchWordNumber ? numberString : searchWord; + const regex = new RegExp( + patternBase + .replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + .replace(/%/g, ".*") + ); + + // Pre-normalize and cache p.searchString, then filter and limit to 200 items to avoid rendering lag + const matches = []; + for (const p of filteredPartners) { + if (!p._normalizedSearchString) { + p._normalizedSearchString = normalize(p.searchString || ""); + } + if (regex.test(p._normalizedSearchString)) { + matches.push(p); + if (matches.length >= 200) { + break; + } + } + } + return matches; } });