Settings
Set Up Loyalty Points, Tiers, Redemption and Referrals
Loyalty turns a named customer's completed purchases into points and can spend those points as a server-validated bill discount. Configure one branch at a time, test the maths before launch, reconcile the customer ledger after sales and returns, and do not promise automatic point expiry in the current build.
- Menu path
- Manage -> Features -> Marketing ON; then Manage -> Marketing -> Loyalty & Rewards
- Verified from
- Posnic demo and current POS source reviewed on 2026-09-13
Technical source evidence
frontend/modules/settings_write.html Marketing Loyalty controls and liability cards, frontend/static/script/js/modules/js/loyalty.js settings preview customer summary and till redemption, frontend/modules/sales_write.html loyalty panel, frontend/static/script/js/modules/js/sales.js loyalty payload and payable-total calculation, frontend/static/script/js/modules/js/customers.js customer dossier badge and next-tier progress, api/src/services/loyalty.service.js earn redeem referral reverse summary and liability rules, api/src/controllers/sales.controller.js server validation post-sale hooks and return or void reversal, api/src/controllers/loyalty.controller.js permissions and branch context, api/src/constants/loyalty.constants.js defaults and ledger types, demo.posnic.io Marketing Loyalty screen reviewed on 2026-09-13
Before You Turn It On
Loyalty changes what customers pay and creates a future discount obligation. Treat the earn rate, redemption value and limits as an owner-approved financial policy, not as a cosmetic switch.
| Decision | Confirm before launch | Why it matters |
|---|---|---|
| Membership identity | Cashiers will attach the correct named customer, preferably verified by phone. | Walk-in sales have no customer ID and receive no loyalty movement. |
| Earn cost | Expected points for common basket values and every tier multiplier. | An aggressive rate increases the outstanding reward obligation. |
| Redeem value | Currency value per point, minimum redemption and maximum bill percentage. | These rules directly reduce the amount payable. |
| Branch policy | Whether branches intentionally use the same or different rates. | Configuration is branch-specific, while customer records and points can be shared across shops. |
| Returns policy | Staff know to process returns or voids through the saved sale. | The linked loyalty entries are reversed from the original sale. |
| Expiry promise | No customer-facing expiry promise is made yet. | The current build stores expiry_months but contains no job or service that expires points. |
Open Loyalty and Rewards
- Sign in with a role allowed to manage branch settings and customer data.
- Open Manage -> Features and turn Marketing on if the Marketing entry is hidden.
- Open Manage -> Marketing.
- Choose Loyalty & Rewards. The screen loads the active branch's saved configuration and the current liability summary.
- Leave Enable loyalty off while designing or checking new rules.
- Confirm the active branch and currency before entering ratios; the currency symbol is a label, while all calculations use the numeric rates.
Define How Customers Earn
For a completed named-customer sale, Posnic calculates spend / Amount spent x Points earned x the customer's current tier multiplier, then applies the selected rounding rule. A bill below Minimum spend earns zero.
| Field | What the server uses | Operational guidance |
|---|---|---|
| Points earned | The points side of the earn ratio; it must be greater than zero to save from this screen. | Use a whole-number rate staff can explain. |
| Amount spent | The branch-currency side of the ratio; it must be greater than zero. | Avoid a tiny amount that creates unexpectedly large balances. |
| Rounding | Round down, nearest integer or round up after the tier multiplier. | Round down is the conservative default and never over-credits a partial point. |
| Minimum spend to earn | A completed sale below this value receives no normal earn entry. | Set 0 only when every positive named-customer sale should qualify. |
| Sale amount used | The saved sale total after validated loyalty or coupon discounts. | Test discounted bills as well as full-price bills. |
| Named customer | A valid customer_id is required. | Selecting Walk-in means no earning, regardless of basket value. |
Check the Earn Maths
Example: 1 point per 100 spent, minimum spend 200, Round down, and a 1.25 Gold multiplier.
- Use the on-screen worked preview as a quick rate check, then verify several real basket amounts manually.
- Tier selection uses lifetime points before the new sale's normal earn is added.
- A repeated request or saved-sale edit does not award a second normal earn entry for the same sale.
| Completed sale | Calculation | Points earned |
|---|---|---|
| 150 by a Member | Below the 200 minimum. | 0 |
| 250 by a Member | 250 / 100 x 1 x 1, then floor. | 2 |
| 250 by a Gold customer | 250 / 100 x 1 x 1.25 = 3.125, then floor. | 3 |
| 1,000 by a Gold customer | 1,000 / 100 x 1 x 1.25. | 12 with floor; 13 with nearest or round up depending on the fraction. |
Define Redemption Limits
Redemption converts whole points into a bill-level loyalty discount. Posnic validates the requested points against the current customer balance and current bill on the server before pricing the sale.
| Field | Meaning | Example |
|---|---|---|
| Points | Points in the redemption ratio. | 100 points |
| Value | Branch-currency discount bought by that number of points. | 100 points = 50 off means each point is worth 0.50. |
| Minimum points to redeem | Smallest allowed request in one sale. | A value of 200 rejects a request for 150 points. |
| Max discount (% of bill) | Maximum share of the current bill payable with points, clamped between 0 and 100 when saved. | At 25%, a 1,000 bill can receive at most 250 of loyalty discount. |
| Available balance | The customer's current unspent whole points. | A request above the balance is rejected. |
| Points expire after | A stored number of months; 0 means never in the configuration. | Do not rely on a nonzero value yet because automatic expiry is not implemented in the current source. |
Build the Tier Ladder
A tier is selected from the customer's lifetime earned points, not the currently spendable balance. Redeeming points lowers the balance but does not by itself lower lifetime points or the tier.
- Keep a starting tier at threshold 0 so every member has a defined tier.
- Select Add Tier for each higher level.
- Enter a unique, customer-friendly Name, a From lifetime points threshold and a positive Earn multiplier.
- Arrange thresholds conceptually from lowest to highest. The server sorts by threshold before selecting the highest reached tier.
- Remove accidental rows with the trash control; the screen keeps at least one tier row.
- Calculate sample earnings immediately below and above each threshold before saving.
Configure Referral Rewards
When referrals are enabled, the first qualifying completed purchase by a customer who has a saved Referral customer can grant separate fixed-point bonuses to the new customer and the referrer.
- Record the referrer on the new customer's profile before the qualifying sale.
- Set Points to the referrer, Points to the new customer and Min first-purchase spend.
- The system marks the referred customer as rewarded before granting points so concurrent or repeated sales cannot grant the bonus twice.
- Referral bonuses are adjustment entries and count toward lifetime points and tier progress.
- Returning or voiding the qualifying sale reverses normal earn and redeem entries, but it does not claw back referral adjustment bonuses in the current implementation.
- If the first sale is below the minimum, the customer remains eligible for a later qualifying sale because no reward flag is set.
Save and Launch the Programme
- Review the earning example shown on screen and independently calculate at least a small, normal and high-value basket.
- Review the value of 100 points and the maximum possible discount on those baskets.
- Confirm every tier threshold and multiplier.
- Confirm the referral values and minimum, or leave referrals off.
- Turn on Enable loyalty.
- Select Save loyalty settings and wait for Loyalty settings saved.
- Reload Loyalty & Rewards and confirm every value persisted for the active branch.
- Run the controlled checkout tests below before advertising the programme.
Earn Points on a Sale
- Open New Sale and add the test items.
- Open the customer picker and select the exact named customer; do not leave Walk-in selected.
- Confirm the loyalty badge shows the expected tier and current point balance when loyalty is enabled.
- Complete payment normally. A held or parked bill does not earn points until it becomes a completed sale.
- Read the completed-sale result for points earned when present.
- Open the same customer dossier and confirm the new balance, lifetime total, tier or next-tier progress.
- Retain the Sale ID and expected calculation for reconciliation.
Redeem Points at Checkout
The till preview is not the final authority. At save time, the server rechecks the active branch rules and the customer's real balance. If the request has become invalid or stale, the loyalty request is dropped and the sale is allowed to continue at full price. Cashiers must verify the final payable amount before collecting money.
- Build the bill, then select the exact customer before payment.
- Read the loyalty badge, available points and value-per-point hint.
- Enter the number of whole points requested and select Apply.
- Read the displayed discount, points accepted and any capped-to-bill-limit message.
- Confirm Pay Total and Discount changed by the expected amount before opening PAY.
- Complete payment and verify the final saved bill, customer balance and loyalty ledger entry.
- Use the clear control before payment when the customer changes their mind.
Understand the Customer Ledger
- The ledger records customer, branch, type, signed points, balance after, value, currency, Sale ID, reason, tier and operator context.
- Normal earning and redemption are idempotent per sale, preventing a retry from moving the same points twice.
- A loyalty hook failure is deliberately prevented from failing a completed sale. If the bill saved but points did not move, preserve the Sale ID and investigate rather than recreating the sale.
| Ledger type | Points direction | When it appears |
|---|---|---|
| earn | Positive | A qualifying completed sale adds normal purchase points. |
| redeem | Negative | A completed sale spends points as a validated discount. |
| adjust | Usually positive in the current referral flow | Referral welcome or referrer bonuses are granted. |
| reverse | Opposite of the original movement | A linked earned or redeemed movement is undone after the sale is returned or voided. |
| expire | Designed as negative | The type exists in the model, but the current source has no automatic expiry writer. |
Return or Void a Loyalty Sale
- Find the original transaction in Sales History and verify its Sale ID and customer.
- Use the supported return or void action; do not create a negative replacement sale just to alter points.
- Complete the financial return or void and wait for its success result.
- Reopen the customer and verify that points earned by the original sale were removed and points redeemed on it were restored.
- Check for reverse entries linked to the original Sale ID.
- Review referral bonuses separately because they are not reversed with the normal sale loyalty entries.
Review Loyalty Liability
The cards show members with positive balances, total outstanding points and their value at the active branch's current redemption rate. The tier table groups members, points and value.
- Review liability after changing the redemption ratio because the value of every outstanding point changes immediately in this report.
- Customer points may be shared across branches. The current liability query counts positive balances license-wide, then values all of them with the active branch's rate.
- When branch redemption rates differ, do not treat one branch's displayed liability as a precise consolidated accounting value; reconcile by policy or use a common rate.
- The liability is a current balance estimate, not a list of future redemption dates and not proof that expiry has run.
Permissions and Scope
| Action | Current access boundary | Recommended role |
|---|---|---|
| Open Marketing settings | The settings navigation uses Branch Write access and the Marketing feature switch. | Owner or configuration manager. |
| Save loyalty configuration | The API rejects a user whose Customer Write access is explicitly false. | Owner or customer-program manager. |
| Read liability or till preview | The API rejects a user whose Customer Read access is explicitly false. | Manager or authorized cashier as required. |
| Create a loyalty sale | Requires the normal sale workflow and a valid named customer. | Cashier with Sales Write and Customer Read. |
| Return or void | Uses the normal protected return or void workflow and its approval controls. | Authorized supervisor or approved cashier. |
Controlled Test Matrix
| Test | Expected result | Evidence to keep |
|---|---|---|
| Walk-in sale | No loyalty panel movement and no earn ledger entry. | Sale ID and customer shown as Walk-in. |
| Named sale below minimum | Zero normal points earned. | Basket total and current rule. |
| Named sale above minimum | Points match rate, tier multiplier and rounding. | Before/after balance and Sale ID. |
| Valid redemption | Accepted points reduce Pay Total by the server-calculated value. | Final bill discount and redeem ledger row. |
| Over-balance redemption | Request is rejected or removed; points are not overspent. | Displayed message and unchanged balance. |
| Max-percent cap | Accepted points/value are reduced to fit the configured bill share. | Capped message and final total. |
| Return or void | Normal earn is removed and redeemed points are restored through reverse rows. | Original Sale ID and resulting balance. |
| Referral first qualifying sale | Each configured side receives one adjustment bonus. | Both customer balances and shared Sale ID. |
| Repeat referred-customer sale | No second referral bonus. | Second Sale ID and ledger review. |
Troubleshooting
| Problem | Likely cause | Action |
|---|---|---|
| Marketing is missing | Marketing is off under Manage -> Features or the role lacks Branch Write. | Enable the feature with an authorized role, then reopen Manage. |
| Loyalty panel does not appear | Walk-in is selected, loyalty is off for this branch, or the customer summary did not load. | Select a named customer, confirm branch and reload the saved configuration. |
| Sale earned zero points | Below minimum, zero/invalid rate, Walk-in, held bill, cancelled bill or post-sale hook failure. | Use the Sale ID, basket total, customer and active rule to isolate the reason. |
| Requested points were not applied | Insufficient balance, below minimum, capped to zero, loyalty disabled or stale rules/balance at save. | Recheck the final total and customer balance before collecting payment; do not assume the preview survived save. |
| Tier looks wrong | Tier uses lifetime earned points and thresholds are sorted numerically. | Compare lifetime points to every threshold, not the spendable balance. |
| Referral bonus is missing | No saved referrer, referral off, bill below minimum, zero bonus values or customer already rewarded. | Inspect the customer referral field and qualifying-sale history. |
| Returned sale still has referral points | Referral bonuses are adjustment rows and are not reversed by the current return path. | Follow the shop's approved correction process; do not alter the customer balance blindly. |
| Points did not expire | The current build stores the expiry setting but does not execute expiry. | Do not promise or manually simulate automatic expiry; escalate the product gap. |
| Liability changes between branches | License-wide points are valued using the currently active branch's redeem rate. | Compare branch rates and use a documented common-rate accounting policy. |
| Sale saved but balance did not change | Loyalty is a protected post-sale side effect and a failure does not roll back the sale. | Keep the saved Sale ID, do not duplicate the sale, and escalate ledger reconciliation. |