refactor: improve loyalty program filtering and optimize partner list search performance in POS

This commit is contained in:
Suherdy Yacob 2026-06-02 16:51:32 +07:00
parent f7a8e1451d
commit b8218d83a9
2 changed files with 46 additions and 2 deletions

View File

@ -63,7 +63,7 @@ class ResPartner(models.Model):
# Find the lowest membership program level (Membership Silver) # Find the lowest membership program level (Membership Silver)
lowest_program = self.env['loyalty.program'].sudo().search( 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 limit=1
) )
if not lowest_program: if not lowest_program:

View File

@ -2,11 +2,55 @@
import { PartnerList } from "@point_of_sale/app/screens/partner_list/partner_list"; import { PartnerList } from "@point_of_sale/app/screens/partner_list/partner_list";
import { patch } from "@web/core/utils/patch"; import { patch } from "@web/core/utils/patch";
import { normalize } from "@web/core/l10n/utils";
patch(PartnerList.prototype, { patch(PartnerList.prototype, {
getPartners(partners) { getPartners(partners) {
// Filter the partner list to strictly only display partners who are loyalty members // Filter the partner list to strictly only display partners who are loyalty members
const filteredPartners = partners.filter((p) => p.is_loyalty_member); 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;
} }
}); });