| models | ||
| static/src/app | ||
| views | ||
| __init__.py | ||
| __manifest__.py | ||
| .gitignore | ||
| README.md | ||
POS Loyalty Extend
Version: 1.0 Author: Suherdy Yacob License: LGPL-3 Category: Sales / Point of Sale
Overview
pos_loyalty_extend is a custom Odoo 19 module that extends the built-in pos_loyalty module with additional reward applicability options in the Point of Sale interface.
The primary feature added is "Cheapest Product on Order" applicability for Buy X Get Y loyalty rewards — allowing merchants to automatically discount or give away the cheapest item(s) in a customer's cart based on the number of products purchased.
Features
🏷️ Cheapest Product Applicability
- Adds a new
reward_product_applicabilityfield (cheapest) toloyalty.reward. - When set, the reward dynamically targets the cheapest product(s) in the current POS order instead of a pre-configured fixed product.
📊 Proportional Free Item Calculation
The number of free items scales automatically based on the buy ratio:
| Products Bought | Free Items |
|---|---|
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
Formula: floor(points_earned / required_points_per_reward)
🛒 Multi-Product Free Lines
When multiple free items are awarded, each one targets a different cheapest product in the order (sorted by unit price ascending), rather than duplicating the single cheapest item:
- Buy 4 items → 2 free: Terong Penyet (Rp 15,000) + Telor Penyet (Rp 19,000) ✅
Buy 4 items → 2 free: 2× Terong Penyet (Rp 15,000)❌
⚡ Auto-Claim in POS
Cheapest product rewards are automatically discovered and claimed in the POS UI without requiring manual product configuration on the reward.
Dependencies
| Module | Purpose |
|---|---|
point_of_sale |
Core POS framework |
pos_loyalty |
Loyalty program UI and logic in POS |
sale_loyalty |
Backend loyalty program models |
Configuration
Setting Up a "Buy 2 Get 1 Free (Cheapest)" Program
- Go to Point of Sale → Products → Loyalty Programs
- Create a new program with type Loyalty Card or Promotion
- Under Conditional Rules:
- Minimum Quantity:
2 - Grant:
1 Credit per Unit Paid
- Minimum Quantity:
- Under Rewards → Add a reward:
- Reward Type:
Free Product - Reward Product Applicability:
Cheapest Product on Order(new field) - In Exchange of:
2 Credits(1 credit per product, 2 needed → 1 free) - Quantity Rewarded:
1
- Reward Type:
Important: Set "In Exchange of" to
2(not1) to get the correctbuy 2 → 1 freeratio. The formula isfloor(total_credits / credits_required) = free_items.
Technical Details
Modified Files
Python (Backend)
| File | Description |
|---|---|
models/loyalty_reward.py |
Adds reward_product_applicability selection field; overrides _compute_multi_product to handle cheapest type |
models/sale_order.py |
Overrides reward value computation for server-side cheapest product identification |
JavaScript (Frontend)
| File | Description |
|---|---|
static/src/app/models/pos_order.js |
Core reward logic patches — cheapest product detection, unclaimed qty computation, multi-product reward line generation, getClaimableRewards override |
static/src/app/services/pos_store.js |
Patches getPotentialFreeProductRewards to surface cheapest rewards with no fixed reward_product_ids |
static/src/app/screens/product_screen/control_buttons/control_buttons.js |
Patches _applyReward to route cheapest rewards through dynamic product resolution |
Views
| File | Description |
|---|---|
views/loyalty_reward_views.xml |
Adds the reward_product_applicability field to the loyalty reward form |
Key Methods
_getCheapestProductInOrder(reward)— Returns the single cheapest non-reward product in the current order_getCheapestProductsInOrder(reward, n)— Returns the N cheapest individual items (sorted by unit price), expanding multi-qty lines_computeUnclaimedFreeProductQtyForCheapest(...)— Calculates how many free items are still unclaimed based on remaining loyalty pointsgetClaimableRewards(...)— Extended to include cheapest-type rewards that the core skips (due to nullreward_product_id)
Installation
# Copy module to your custom addons path
cp -r pos_loyalty_extend /path/to/odoo/customaddons/
# Update addons list and install
./odoo-bin -c odoo.conf -u pos_loyalty_extend
Or via Odoo UI:
- Enable Developer Mode
- Go to Apps → Update Apps List
- Search for
POS Loyalty Extendand install
Changelog
v1.0
- Initial release
- Added
cheapestreward product applicability - Auto-claim cheapest product rewards in POS
- Proportional multi-product free item generation (N cheapest products, not N× same product)
- Fixed
getClaimableRewardsandgetPotentialFreeProductRewardsto surface cheapest rewards - Fixed
_updateRewardLinesdeduplication for multiple reward lines per reward