feat: implement membership validation logic to distinguish between manual and auto-tier loyalty programs in POS orders
This commit is contained in:
parent
9d1fe545e3
commit
1f85ab68bc
@ -37,6 +37,37 @@ patch(PosOrder.prototype, {
|
||||
// Custom Logic for Multi-Level Membership.
|
||||
// Guard against recursive calls triggered when filtering all programs below.
|
||||
if (program.multi_level_membership && !_checkingMultiLevel) {
|
||||
const partner = this.getPartner();
|
||||
const membershipId = (partner && partner.membership_level_id)
|
||||
? resolveManyToOneId(partner.membership_level_id)
|
||||
: null;
|
||||
|
||||
// ── Case 1: Manual membership program (e.g. Membership Direksi, subscriptions) ──
|
||||
// These programs are never part of auto-tier selection.
|
||||
// Only allow them when the partner actually holds an active loyalty card
|
||||
// for this program — whether it's a replacement tier (Direksi) or
|
||||
// an add-on subscription (e.g. Makan Pagi Gratis).
|
||||
if (program.manual_membership) {
|
||||
if (!partner) return false;
|
||||
const allCards = this.models['loyalty.card']?.getAll() || [];
|
||||
return allCards.some((card) => {
|
||||
const cardPartnerId = resolveManyToOneId(card.partner_id);
|
||||
const cardProgramId = resolveManyToOneId(card.program_id);
|
||||
return cardPartnerId === partner.id && cardProgramId === program.id;
|
||||
});
|
||||
}
|
||||
|
||||
// ── Case 2: Auto-tier program (Silver / Gold / Platinum) ──
|
||||
// If the partner holds a manual membership level (e.g. Direksi),
|
||||
// block all auto-tier rewards — they use their own program's rewards.
|
||||
if (membershipId) {
|
||||
const allPrograms = this.models['loyalty.program'].getAll();
|
||||
const memberProgram = allPrograms.find((p) => p.id === membershipId);
|
||||
if (memberProgram && memberProgram.manual_membership) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve all loyalty programs
|
||||
const allPrograms = this.models['loyalty.program'].getAll();
|
||||
|
||||
@ -44,9 +75,10 @@ patch(PosOrder.prototype, {
|
||||
_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.
|
||||
// Filter programs that have the multi-level flag (non-manual) and
|
||||
// pass the base applicability check. With the guard set,
|
||||
// _programIsApplicable(p) will skip this custom block,
|
||||
// effectively calling only the base logic for each candidate.
|
||||
multiLevelPrograms = allPrograms.filter(
|
||||
(p) => p.multi_level_membership && !p.manual_membership && this._programIsApplicable(p)
|
||||
);
|
||||
@ -54,24 +86,19 @@ patch(PosOrder.prototype, {
|
||||
_checkingMultiLevel = false;
|
||||
}
|
||||
|
||||
// If there are no applicable multi-level programs, block all of them.
|
||||
// If there are no applicable auto-tier 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;
|
||||
}
|
||||
// If the partner has a membership level, try to match it.
|
||||
if (membershipId) {
|
||||
bestProgram = multiLevelPrograms.find((p) => p.id === membershipId) || null;
|
||||
}
|
||||
|
||||
// Fallback: pick the program with the smallest minimum_spend
|
||||
// Fallback: pick the program with the smallest minimum_spend (Silver)
|
||||
if (!bestProgram) {
|
||||
bestProgram = multiLevelPrograms.reduce((prev, curr) => {
|
||||
const prevSpend = prev.minimum_spend || 0;
|
||||
@ -89,3 +116,4 @@ patch(PosOrder.prototype, {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user