fix: override getClaimableRewards to correctly display product rewards for manual membership programs
This commit is contained in:
parent
1f85ab68bc
commit
1a1ad81a55
@ -115,5 +115,76 @@ patch(PosOrder.prototype, {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override to fix free product rewards for manual_membership (subscription) programs.
|
||||||
|
*
|
||||||
|
* Odoo's base _computeUnclaimedFreeProductQty returns Math.min(available, freeQty).
|
||||||
|
* `available` = qty of the reward product already in the current order.
|
||||||
|
* For subscription programs (e.g. Makan Pagi Gratis), the free breakfast product is
|
||||||
|
* NOT in the order yet — so available=0, freeQty=0 and the reward is never shown.
|
||||||
|
*
|
||||||
|
* Fix: after the base getClaimableRewards runs, we re-evaluate manual_membership
|
||||||
|
* programs that were silently skipped and inject their product rewards using the
|
||||||
|
* raw point-based qty (points / required_points), so the cashier can select them
|
||||||
|
* from the Rewards popup and the product is added to the order automatically.
|
||||||
|
*/
|
||||||
|
getClaimableRewards(coupon_id = false, program_id = false, auto = false) {
|
||||||
|
const baseResult = super.getClaimableRewards(...arguments);
|
||||||
|
|
||||||
|
// Auto mode is the background reward sweep — don't alter it.
|
||||||
|
if (auto) {
|
||||||
|
return baseResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect program IDs already present so we don't add duplicates.
|
||||||
|
const presentProgramIds = new Set(
|
||||||
|
baseResult.map((r) => r.reward?.program_id?.id)
|
||||||
|
);
|
||||||
|
|
||||||
|
const couponPointChanges = this.uiState.couponPointChanges;
|
||||||
|
const extraRewards = [];
|
||||||
|
|
||||||
|
for (const pe of Object.values(couponPointChanges)) {
|
||||||
|
const program = this.models['loyalty.program'].get(pe.program_id);
|
||||||
|
if (!program || !program.manual_membership) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (presentProgramIds.has(program.id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (coupon_id && pe.coupon_id !== coupon_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (program_id && pe.program_id !== program_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const points = this._getRealCouponPoints(pe.coupon_id);
|
||||||
|
for (const reward of program.reward_ids) {
|
||||||
|
if (points < reward.required_points) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (reward.reward_type !== 'product') {
|
||||||
|
// Non-product rewards are already handled by base logic.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Compute how many free items can be claimed from remaining points.
|
||||||
|
const freeQty = Math.floor(
|
||||||
|
(points / reward.required_points) * (reward.reward_product_qty || 1)
|
||||||
|
);
|
||||||
|
if (freeQty <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
extraRewards.push({
|
||||||
|
coupon_id: pe.coupon_id,
|
||||||
|
reward: reward,
|
||||||
|
potentialQty: freeQty,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...baseResult, ...extraRewards];
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user