From fc63dda464b5d4ff0f6c3f4db465d75a689abecf Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Tue, 2 Jun 2026 15:16:31 +0700 Subject: [PATCH] refactor: remove redundant multi-level loyalty program membership logic from POS order model --- static/src/app/models/pos_order.js | 91 ------------------------------ 1 file changed, 91 deletions(-) diff --git a/static/src/app/models/pos_order.js b/static/src/app/models/pos_order.js index b27ccef..e69de29 100644 --- a/static/src/app/models/pos_order.js +++ b/static/src/app/models/pos_order.js @@ -1,91 +0,0 @@ -/** @odoo-module **/ - -import { PosOrder } from "@point_of_sale/app/models/pos_order"; -import { patch } from "@web/core/utils/patch"; - -/** - * Safely extract a numeric ID from a Many2One field value. - * Handles three forms Odoo may return: - * - raw integer: 5 - * - [id, name] tuple: [5, "Gold"] - * - record object: { id: 5, name: "Gold", ... } - */ -function resolveManyToOneId(value) { - if (!value && value !== 0) { - return null; - } - if (Array.isArray(value)) { - return parseInt(value[0], 10); - } - if (typeof value === 'object') { - return parseInt(value.id, 10); - } - return parseInt(value, 10); -} - -// Track recursion depth to prevent infinite loops when filtering multiLevelPrograms -let _checkingMultiLevel = false; - -patch(PosOrder.prototype, { - _programIsApplicable(program) { - // Evaluate base program applicability first. - const isApplicable = super._programIsApplicable(...arguments); - if (!isApplicable) { - return false; - } - - // Custom Logic for Multi-Level Membership. - // Guard against recursive calls triggered when filtering all programs below. - if (program.multi_level_membership && !_checkingMultiLevel) { - // Retrieve all loyalty programs - const allPrograms = this.models['loyalty.program'].getAll(); - - // Set guard BEFORE filtering to prevent re-entry into this block - _checkingMultiLevel = true; - let multiLevelPrograms; - try { - // Filter programs that have the multi-level flag and pass the base applicability check. - // With the guard set, this._programIsApplicable(p) will skip the custom block, - // effectively calling only the base logic for each candidate program. - multiLevelPrograms = allPrograms.filter( - (p) => p.multi_level_membership && this._programIsApplicable(p) - ); - } finally { - _checkingMultiLevel = false; - } - - // If there are no applicable multi-level programs, block all of them. - if (multiLevelPrograms.length === 0) { - return false; - } - - let bestProgram = null; - const partner = this.getPartner(); - - // If the partner is set and has a membership level, try to match it. - if (partner && partner.membership_level_id) { - const membershipId = resolveManyToOneId(partner.membership_level_id); - if (membershipId) { - // Find the matching program among applicable multi-level programs - bestProgram = multiLevelPrograms.find((p) => p.id === membershipId) || null; - } - } - - // Fallback: pick the program with the smallest minimum_spend - if (!bestProgram) { - bestProgram = multiLevelPrograms.reduce((prev, curr) => { - const prevSpend = prev.minimum_spend || 0; - const currSpend = curr.minimum_spend || 0; - return currSpend < prevSpend ? curr : prev; - }, multiLevelPrograms[0]); - } - - // Only permit the chosen program to be active - if (program.id !== bestProgram.id) { - return false; - } - } - - return true; - }, -});