Workflow: Loyalty Program — Fidelizare Clienți
Module implicate: Loyalty (Rules · Transactions · Redemption · Membership · Programs) · Invoices · OmniSales · Clients
Cine îl folosește: Marketing · Sales · Customer Success
Durata tipică: Continuu — punctele se acumulează la fiecare plată
Overview
Modulul Loyalty implementează un sistem complet de fidelizare: acumulare automată de puncte la plata facturilor, trei tipuri de bonusuri suplimentare (cont nou, aniversare, manual), răscumpărare în 4 contexte diferite (factură admin, portal client, OmniSales, voucher), și un sistem de niveluri (tiere) cu beneficii diferențiate per nivel.
Condiție obligatorie: Toggle-ul global
loyalty_settingtrebuie setat la1din Setup → Marketing → Loyalty. Fără aceasta, hook-ulafter_payment_addednu execută nicio logică de puncte, indiferent de regulile configurate.
Nu există expirare automată a punctelor. Punctele scad doar prin răscumpărare explicită.
Diagrama fluxului
[SETUP — admin, o singură dată]
│
├── Activare globală: loyalty_setting = 1
├── Loyalty Rules: tip câștig (card_total / product_category / product)
│ + benzi de răscumpărare (point_weight per bandă de puncte)
├── Membership Rules (Tiere): Bronze / Silver / Gold by point range
├── Membership Programs: discounturi per tier (card/categorie/produs)
└── Loyalty Cards: template vizual (opțional)
│
↓
[ACUMULARE PUNCTE — automat la plată]
│
├── Trigger: after_payment_added → factură status = PAID (2)
├── Sistem caută reguli active pentru client (by client_id sau client_group)
│
├── rule_base = 'card_total':
│ puncte = poin_awarded × floor(total_factură / purchase_value)
│ (ex: 10 puncte per 100 RON cheltuiți)
│
├── rule_base = 'product_category':
│ per linie de factură: dacă grupa produsului = rel_id în rule_detail
│ → puncte = loyalty_point × cantitate
│
└── rule_base = 'product':
per linie de factură: dacă produsul = rel_id în rule_detail
→ puncte = loyalty_point × cantitate
│
├── Insert în loy_transation: type='debit', reference='order_debit'
└── clients.loy_point += puncte câștigate
│
↓
[BONUSURI SUPLIMENTARE]
│
├── Cont nou (after_client_added hook):
│ → regula cu MAX(create_account_point) activă azi
│ → type='credit', reference='manual_credit'
│
├── Aniversare (cron before_cron_run hook):
│ → caută clienți cu câmpul custom 'Birthday' = azi (lună+zi)
│ → o singură dată per an (verifică loy_transation.note='bonus_points_for_customers_birthday')
│ → trimite email template 'loyalty-birthday-bonus-point'
│
└── Manual (admin): loyalty/transation_form → tip='credit'
│
↓
[NIVEL (TIER) — calculat dinamic]
│
├── client_rank() → caută loy_mbs_rule unde loy_point ∈ [loyalty_point_from, loyalty_point_to]
├── Cel mai înalt tier matching câștigat
└── client_next_rank() → arată câte puncte mai lipsesc pentru nivelul următor
│
↓
[RĂSCUMPĂRARE — 4 contexte]
│
├── [A] Admin pe factură: câmp redeem în formularul de factură
├── [B] Client în portal: pagina facturii → redeem points
├── [C] OmniSales/POS: câmp redeem în coșul de comandă
└── [D] Voucher/Program membership: cod voucher sau discount automat per tier
│
↓
[DISCOUNT APLICAT]
│
├── Puncte convertite la monedă via point_weight (ex: 1 pt = 0.05 RON)
├── redeemp_type='full': toate punctele, valoare calculată automat
├── redeemp_type='partial': clientul alege câte puncte răscumpără
├── Insert în loy_redeem_log: old_point, new_point, redeep_from, redeep_to
└── clients.loy_point -= puncte răscumpărate
[CLIENT FIDEL ✓ · PUNCTE ACUMULATE ✓]
Pas cu pas
1. Activare și configurare globală (admin)
Unde: /admin/loyalty → Setup → General Settings
Activare obligatorie: loyalty_setting = 1
Fără aceasta, hook-ul after_payment_added este înregistrat dar returnează imediat fără calcul.
2. Loyalty Rules — regulile de câștig și răscumpărare
Unde: /admin/loyalty → Loyalty Rules → New Rule
O singură regulă definește atât câștigul cât și răscumpărarea.
2a. Câmpuri regulă
| Câmp | Obligatoriu | Descriere |
|---|---|---|
subject |
Da | Denumire regulă |
enable |
Da | 1 = activă |
start_date / end_date |
Da | Intervalul de valabilitate |
rule_base |
Da | card_total / product_category / product |
client_group |
Nu | Grupul de clienți vizat (0 = toți) |
client |
Nu | ID-uri specifice de clienți (CSV) |
minium_purchase |
Nu | Valoare minimă comandă pentru câștig puncte |
max_amount_received |
Nu | Plafon maxim de puncte câștigate per tranzacție |
Pentru card_total:
| Câmp | Descriere |
|---|---|
poin_awarded |
Puncte acordate per tranșă |
purchase_value |
Valoarea unei tranșe (ex: 100 RON = 10 puncte) |
Pentru product_category și product: adăugați linii în Rule Details — fiecare linie specifică rel_type, rel_id (ID grupă sau produs) și loyalty_point per unitate.
Bonusuri speciale per regulă:
| Câmp | Descriere |
|---|---|
create_account_point |
Puncte bonus la crearea unui cont client nou |
birthday_point |
Puncte bonus de ziua de naștere (necesită câmpul custom 'Birthday' pe client) |
2b. Benzi de răscumpărare (Redemption Tiers)
Adăugați cel puțin o bandă în secțiunea Redemption Details a regulii:
| Câmp | Descriere |
|---|---|
point_from / point_to |
Intervalul de puncte pentru această bandă |
point_weight |
Rata de conversie: puncte → monedă (ex: 0.05 = 1 pt = 0.05 RON) |
status |
'enable' = bandă activă |
redeem_portal |
1 = poate fi utilizată în portalul client |
redeem_pos |
1 = poate fi utilizată în OmniSales/POS |
min_poin_to_redeem |
Minim de puncte necesare pentru a activa răscumpărarea |
redeemp_type |
'full' = răscumpărare totală · 'partial' = răscumpărare parțială |
3. Membership Rules — niveluri (tiere)
Unde: /admin/loyalty → Membership → New Membership Rule
Definesc tierele (ex: Bronze, Silver, Gold) pe baza punctelor acumulate:
| Câmp | Descriere |
|---|---|
name |
Denumire tier (ex: „Gold") |
loyalty_point_from / loyalty_point_to |
Intervalul de puncte pentru acest tier |
client_group |
Grupul de clienți eligibil (0 = toți) |
card |
FK → loy_card (template card vizual opțional) |
4. Membership Programs — beneficii per tier
Unde: /admin/loyalty → Membership Programs → New Program
Un program leagă un tier (sau mai multe) de un beneficiu de discount:
| Câmp | Descriere |
|---|---|
program_name |
Denumire program |
membership |
ID-uri tiere vizate (CSV din loy_mbs_rule) |
discount |
Tip discount: card_total / product_category / product |
discount_percent |
Procentul de discount |
voucher_code |
Cod voucher opțional (pentru răscumpărare manuală) |
voucher_value |
Valoarea fixă a voucherului |
minium_purchase |
Comandă minimă pentru activare discount |
start_date / end_date |
Valabilitate program |
Atenție: Când un program de membership cu discount este aplicat la factură, sistemul generează automat o notă de credit (
add_credit_mbs_program()) și o aplică la factură. Această notă de credit apare în modulul Credit Notes.
5. Câmpul custom „Birthday" (pentru bonus aniversar)
Unde: /admin/clients → fișa client → câmpul custom Birthday (date_picker)
Câmpul este creat automat de modul cu slug customers_birthday. Bonusul de aniversare se declanșează prin cron (before_cron_run) o singură dată pe an per client.
6. Răscumpărare puncte
6a. Pe factură (admin)
La crearea/editarea unei facturi, apare secțiunea Redeem Points dacă:
- Clientul are puncte suficiente (
≥ min_poin_to_redeem) - Există o regulă activă cu bandă de răscumpărare validă
Staff selectează punctele de răscumpărare → discount calculat automat → scris în loy_redeem_log.
6b. Portal client
Clientul logat vede butonul Redeem Points pe pagina facturii (dacă redeem_portal=1 pe regulă și factura nu e deja plătită complet).
Clientul alege punctele → sistemul modifică direct invoices.total (reduce totalul) și loghează în loy_voucher_inv_log.
6c. OmniSales / POS
Câmpul de răscumpărare apare în coșul OmniSales (dacă redeem_pos=1). Se aplică la crearea comenzii.
6d. Voucher membership
La introducerea unui cod voucher (apply_other_voucher filter), sistemul verifică dacă clientul aparține unui tier cu program activ care are acel cod. Returnează voucher_value și minium_purchase.
7. Vizualizare sold puncte client
Unde: /admin/clients/{id} → coloana loy_point pe fișa clientului
Soldul curent este stocat direct în tblclients.loy_point (DECIMAL). Istoricul complet al tranzacțiilor se vede în Loyalty → Transactions filtrat pe client.
Permisiuni necesare
| Acțiune | Permisiune |
|---|---|
| Vizualizare modul Loyalty | loyalty → view |
| Configurare reguli, carduri, programe | is_admin() exclusiv (require_loyalty_admin) |
| Portal client (răscumpărare) | is_client_logged_in() |
Gotchas
| Problemă | Cauză | Soluție |
|---|---|---|
| Punctele nu se adaugă după plată | loyalty_setting ≠ 1 sau regula expirată |
Activați toggle-ul global + verificați start_date/end_date regulii |
| Clientul nu apare în regula de acumulare | client sau client_group nepotrivit |
Verificați că regula include clientul respectiv sau grupul său |
| Bonus aniversar nu s-a acordat | Câmpul Birthday nu e completat pe client sau cron inactiv |
Completați câmpul + verificați cron job |
| Răscumpărare nu apare pe factură | min_poin_to_redeem neîndeplinit sau regulă inactivă |
Verificați soldul punctelor vs min_poin_to_redeem |
| Discount membership generează notă de credit neașteptată | Comportament corect — add_credit_mbs_program() |
Nota de credit este normală; o vedeți în Credit Notes |
| Puncte nu expiră | Nu există mecanism de expirare | Comportament corect — punctele sunt permanente; limitați prin end_date pe regulă |
Referințe module
- Clients — soldul loy_point pe fișa client
- Invoices — răscumpărare pe factură
- OmniSales — răscumpărare POS
- Credit Notes — note de credit generate de membership programs
Configurați ratele de acumulare, pragurile de nivel și regulile de expirare înainte de invitarea clienților în program — schimbarea ratei de acumulare după ce clienții au acumulat solduri nu ajustează retroactiv punctele existente, creând nepotriviri de așteptări.
Punctele de fidelizare se acumulează pe facturi și comenzi omnicanal. Nu se acumulează pe note de credit sau tranzacții rambursate. Revenirile parțiale sau totale ale facturilor nu reduc automat soldul de puncte existent al clientului — ajustați manual dacă este necesar.