Bu makale şu anda yalnızca İngilizce olarak mevcuttur. Çeviri yakında eklenecektir.
By the end of this recipe, your Odoo 19 instance will run promotional pricelists, single-use and multi-use coupon codes, a points-based loyalty program with tiered rewards, and gift card support — all integrated with both the e-commerce checkout and the POS register. Skill required: Odoo administrator with sales/marketing context. Time required: 3 hours configuration plus 1 hour testing. ECOSIRE has rolled this out for retail clients running multi-channel storefronts, and the recipe below is the playbook we ship to clients on day 1 of every loyalty implementation.
The trap most teams fall into: confusing pricelists (rule-based price computation) with coupons (code-redeemed discounts) with loyalty (cumulative reward points). They are three different mechanisms with three different ROI profiles, and most retailers want all three running simultaneously. Misconfigure their priority and you end up with stacking discounts that destroy your margin overnight.
What you will need
- Odoo version: 17, 18, or 19. The unified
loyaltymodule that combines coupons, gift cards, and rewards landed in v17. - Modules:
sale_loyalty(for sales orders),pos_loyalty(for POS),website_sale_loyalty(for e-commerce), andloyalty(auto-installed dependency). - User access: Sales Manager + Settings administrator.
- Existing data: at least 10 products, 5 customers, and one running pricelist. If you have not configured pricelists, do that first via
Sales > Configuration > Pricelists. - Time: 3 hours configuration, 1 hour testing across SO + POS + e-commerce checkouts.
- Decision: which channels does each program run on? Some retailers run gift cards online only and loyalty in-store only. Configure scope from day 1.
Step-by-step
1. Activate the loyalty engine
Go to Settings > Sales > Pricing > Discounts, Loyalty & Gift Card. Tick the box. This loads the unified loyalty engine and adds the "Loyalty Programs" menu under Sales. Verification: the menu Sales > Products > Loyalty Programs exists with no records yet.
2. Create a percentage-discount pricelist
For "10% off everything for VIP customers", use a pricelist (no code needed, applies automatically based on the customer record). Go to Sales > Configuration > Pricelists > Create. Name "VIP 10%". Tick "Sales", set currency. Add a rule: "Apply on All Products", "Compute Price = 10% discount on Sales Price", "Min Quantity = 1". Save.
Now assign the pricelist to specific customers: open a contact, go to Sales & Purchase tab, set Pricelist = "VIP 10%". Every quote for that customer applies the discount automatically. Verification: create a quote for a VIP customer with any product. The unit price shows the standard price minus 10%.
3. Create a coupon-code program
For "Use code SUMMER25 for 25% off", create a Loyalty Program. Go to Sales > Products > Loyalty Programs > Create. Set:
- Program Name: Summer 2026
- Program Type: Discount Code
- Currency: your default
- Available On: Sales, eCommerce, PoS (tick all three)
Then add a Reward: "Discount = 25% on Order". On the Conditional Rules tab: leave blank (any cart qualifies) OR add "Minimum Amount = $50" to gate the discount.
On the Coupons tab, click "Generate Coupons", set count = 1 (single-use shared code) or 1000 (one-time-use codes), and pick "Code = SUMMER25" for the shared case. Save.
# Bulk-generate unique codes via odoo shell for an email blast
program = self.env['loyalty.program'].search([('name', '=', 'Summer 2026')])
self.env['loyalty.generate.wizard'].create({
'program_id': program.id,
'coupon_qty': 5000,
'points_granted': 0, # not applicable for code-only
}).generate_coupons()
self.env.cr.commit()
# Coupons are now in loyalty.card with auto-generated 9-char codes
Verification: create a quotation with $60 of products, click "Apply Coupon", enter the code. The discount line appears. Confirm the SO total reflects the 25% off.
4. Configure a points-based loyalty program
For "Earn 1 point per $1 spent, redeem 100 points for $10 off", create another Loyalty Program. Set:
- Program Type: Loyalty Cards (was "Loyalty Program" pre-v17)
- Available On: same channels as before
Conditional Rules tab: "Reward = 1 point per $1, on Sales Price (excluding tax)". This grants points at checkout.
Rewards tab: "Reward = $10 off, requires 100 points". You can add multiple reward tiers (e.g., 100 pts = $10, 500 pts = $60, 1000 pts = $150 — encourages saving).
Save. Now any customer logged in at checkout earns points and can redeem them. Verification: place a $100 order for a customer, validate. Open the customer record and look at the "Loyalty Card" tab — should show 100 points. Place a second $20 order with redemption — uses the 100 points for $10 off, leaving the customer at 20 points (the $20 minus $10 paid earned 10 new points).
5. Set up gift cards
Gift cards are technically a Loyalty Program of type "Gift Card". Create a new program:
- Program Name: Holiday Gift Cards
- Program Type: Gift Card
- Default code length = 16, issue value = $25/$50/$100/$250 (set as multiple coupon templates)
When a customer buys a gift card product (you create a product called "Gift Card $50" with type = service, list price = $50), Odoo automatically generates a coupon code with $50 redemption value. The customer emails the code to the recipient, who redeems it on their next purchase.
<!-- The gift card product -->
<record id="product_gift_card_50" model="product.product">
<field name="name">Gift Card $50</field>
<field name="type">service</field>
<field name="list_price">50</field>
<field name="taxes_id" eval="[(6, 0, [])]"/>
<field name="categ_id" ref="product.product_category_all"/>
</record>
Verification: place an order for a gift card product, validate. Check the customer's email for the auto-generated card code. Use that code on a separate test order to confirm $50 redemption.
6. Configure the priority of stacking rules
Multiple programs running together can stack. Go to Sales > Configuration > Settings > Discount and decide:
- "Apply only the best": single-program discount wins, no stacking.
- "Apply all": every applicable program stacks (dangerous — can produce 60%+ discounts).
- Custom priority: set the
sequencefield on each program.
For most retailers, "Apply only the best" is the safe default. Verification: create a cart that qualifies for both VIP 10% pricelist and SUMMER25 coupon. Confirm only the 25% applies (the better of the two), not 32.5% (10% + 25% stacked).
7. Add tier-based loyalty (advanced)
To run "Silver/Gold/Platinum" tiers where higher tiers earn more points, create three separate Loyalty Programs each with a different domain rule on the customer. For Gold, set the rule's "Customer Domain" to [('total_spent_last_12m', '>', 5000)].
This requires a small custom field for total_spent_last_12m on res.partner:
from odoo import models, fields, api
class ResPartner(models.Model):
_inherit = 'res.partner'
total_spent_last_12m = fields.Float(compute='_compute_total_spent_12m', store=True)
@api.depends('sale_order_ids.amount_total', 'sale_order_ids.state')
def _compute_total_spent_12m(self):
from datetime import date, timedelta
twelve_m_ago = date.today() - timedelta(days=365)
for partner in self:
partner.total_spent_last_12m = sum(
so.amount_total for so in partner.sale_order_ids
if so.state in ['sale', 'done'] and so.date_order.date() >= twelve_m_ago
)
Verification: a customer whose 12-month spend exceeds $5,000 automatically earns at the Gold rate on their next order.
8. Test across all channels
- Sales: create an SO with coupon, validate.
- POS: open a session, scan a coupon, redeem points.
- eCommerce: shop on the website, apply coupon at checkout.
All three channels share the same coupon pool — a code redeemed in POS cannot be reused on the website. Verification: redeem a single-use code in POS, then try the same code in the e-commerce cart. The cart rejects it as already used.
Common mistakes
- Stacking pricelist + coupon when "Apply only the best" is intended. Always confirm the stacking setting before launching a campaign.
- Generating 50,000 coupon codes in one batch. The transaction times out after 30 seconds. Generate in chunks of 5,000 via odoo shell.
- Forgetting to set the program's "Available On" channels. The coupon works in Sales but not POS, then customers get angry.
- Setting points to expire too aggressively. 6-month expiry feels "fair" to finance, hostile to customers. Industry norm is 12 to 24 months.
- Reusing the same discount code for multiple campaigns. The system tracks usage by code string — splitting analytics across campaigns becomes impossible.
Going further
Referral programs: create a Loyalty Program with type "Promotion" and reward = "10% off + 100 points to referrer". Hook into the website signup flow to capture the referrer's coupon code at registration.
Birthday discounts: schedule a cron that creates personalized single-use coupons for each customer 7 days before their birthday and emails them.
Stackable in-cart bundles: combine the loyalty engine with bundled products (a parent product whose components are auto-added). Customer scans bundle barcode, gets discount, earns points on each component.
External loyalty integration: sync points to an external CRM (HubSpot, Salesforce) via the Odoo webhook system. Points become a custom field that triggers segment-based email campaigns.
For complex retail loyalty rollouts, ECOSIRE's Odoo customization team builds bespoke engines for tiered VIP programs, multi-brand wallet sharing, and B2B rebate accruals. Pair this with how to integrate Mailchimp with Odoo for the email side.
Frequently Asked Questions
Can I run different programs on different brand websites?
Yes. The website_id field on loyalty.program scopes the program to a specific website. Set a different program per website and they won't cross-contaminate.
How do I report on coupon redemption?
Go to Sales > Reporting > Loyalty Cards. Filter by program and group by month. For deeper analysis, expose the loyalty.card.use model in a custom pivot view showing redemptions by SKU, region, and rep.
Does the loyalty engine work with Odoo's gift card balance system?
Yes — gift cards in Odoo are a Loyalty Program of type "Gift Card". The remaining balance is tracked on loyalty.card.points and decrements with each use. Once it hits zero the card is auto-archived.
Can I refund points on a customer return?
Yes if you tick "Apply on Refund Date" on the program. Without it, returns leave the points granted as-is, which becomes a margin leak over time. Refund handling is a 3-line tweak but easy to miss.
For multi-brand or multi-region loyalty rollouts, our Odoo customization team builds the entire system as a fixed-price engagement. Or read how to track customer lifetime value in Odoo to measure the loyalty program's actual ROI.
Yazan
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
ECOSIRE
Odoo ERP ile İşinizi Dönüştürün
Operasyonlarınızı kolaylaştırmak için uzman Odoo uygulaması, özelleştirme ve destek.
İlgili Makaleler
Odoo Form Görünümüne Özel Düğme Nasıl Eklenir (2026)
Odoo 19 form görünümlerine özel eylem düğmeleri ekleyin: Python eylem yöntemi, görünüm devralma, koşullu görünürlük, onay diyalogları. Üretimde test edilmiştir.
Odoo'da Studio Olmadan Özel Alan Nasıl Eklenir (2026)
Odoo 19'daki özel modül aracılığıyla özel alanlar ekleyin: model mirası, görünüm uzantısı, hesaplanan alanlar, mağaza/depo dışı kararlar. Kod öncelikli, sürüm kontrollü.
Odoo'da Harici Düzeni Kullanarak Özel Rapor Nasıl Eklenir?
Web.external_layout'u kullanarak Odoo 19'da markalı bir PDF raporu oluşturun: QWeb şablonu, paperformat, action bağlama. Baskı logosu + altbilgi geçersiz kılmalarıyla.