ZuloOne
English
Sign in
Menu

🎁 Loyalty

Updated

← Business process wiki

The loyalty programme lives in the CRM model, not in Core and not in a country package. The order and realization axis is unchanged: points are a side effect of issuing a SalesRealization.

Why#

The customer accumulates a points balance. The tier ladder (LoyaltyTier) is derived from that balance, so the tier cannot drift away from the facts. A tier sets:

What Field
Permanent invoice discount DiscountPercent
Redemption limit per document MaxRedemptionPerDocument
Earn rate for the next points EarnRate

EarnRate = 0 means inherit CRMSettings.PointsPerCurrencyUnit (or 1:1 if there are no settings). A positive tier rate overrides the settings. The module switch is only CRMSettings.LoyaltyEnabled (with the optional Boolean trap: a positive settings rate still means "the module has been set up").

Both accrual and discount look at the balance before this invoice's points: an invoice does not earn at the tier it creates itself.

Scope#

The LoyaltyPoints register (dimension Customer), SalesLoyaltyTx accrual on Issued, LoyaltyRedemption write-off, the header discount and the rate from the tier. Redemption printing is LoyaltyRedemptionZr (customer and points, without sales pricing). Purchase history is CustomerPurchaseHistoryReport (CustomReport): customer × item × document, amount = quantity × line price of the issued SalesRealization. Drafts and cancellations are excluded. Points are not put into this report: the grain of LoyaltyPoints is customer, and a join would multiply points by lines.

CRM → Reports → Purchase history. Grouped by customer and item, columns Quantity.Add and Amount.Add. The points counter is the LoyaltyPoints register, not this report. The Loyalty points by customer layout (CRM → Totals → Loyalty points) groups by customer. A B2B invoice for 3 × 5 at campaign rate 5 gives closing 75. Zero closing is hidden: redeeming the full balance removes the row.

A LoyaltyCampaign is a dated earn-rate window. An empty ItemGroup means a global rate for all invoice lines. A filled group means the rate only for lines of this item group; other lines stay on the tier or settings. Two live windows of one group cannot overlap; different groups may share the calendar.

Customer type on the campaign#

Where: CRM → Dictionaries → Loyalty campaigns, field Customer type.

Value What it means
Empty Campaign for every customer. This is both the default and all campaigns created before the field existed.
A type from Sales → Customer types Only customers of that type. The customer card picks from the same list, so the two always mean the same thing. A new tenant gets B2B, B2C and Retail from the Customer types data package; demo data uses B2B and Retail.

Behind the list is the type's code (at most 8 characters), and that is what is compared: b2b and B2B are one type, and the list refuses a second code that differs only in case. A type's code cannot change once it is saved, because customers and campaigns keep a copy of it. When a code is wrong, create a new type and move the customers to it. Changing the name is always safe.

What changes on an issued invoice, by line, from the narrow window to the broad one:

  1. Both item group and customer type match.
  2. Only the item group matches.
  3. Only the type matches.
  4. Both filters are empty — the general campaign.
  5. No campaign — the tier, then the settings rate.

A typed campaign and a general campaign may stand on the same dates: the narrow one wins for that type. Two live campaigns of one type on overlapping dates are not saved. B2B and Retail on the same dates are allowed.

Example. CRM settings: 2 points per revenue unit. General campaign: rate 4. Campaign with type B2B: rate 5. An invoice for a B2B customer, line 3 units × 5:

  • without the typed campaign the customer gets 3 × 5 × 4 = 60;
  • with the B2B campaign — 3 × 5 × 5 = 75; the general campaign is not used on this invoice.

The same invoice for a Retail customer gives 60: the B2B campaign does not see it.

If the Beans group also has rate 9 only for B2B, a bean line for a B2B customer uses 9, and another group on the same invoice uses the type campaign (5), not 9.

The agent phone does not have the customer catalogue at that point, so it shows a campaign without a type (4 pts · Beans). A B2B-only campaign earns points on the invoice and does not appear in the catalogue. The tier rate is not sent to the phone: it depends on the balance before the invoice. The manager desk does not choose a campaign.

User: how to configure it. Developer: objects and traps.

What's not there yet#

  • Purchase history does not include points; CustomerPurchaseHistoryReport is quantity and amount from issued realizations.
  • The agent phone does not show campaigns restricted by customer type.
  • The manager desk and the phone do not choose a loyalty campaign; the server resolves the rate on posting.
  • Loyalty does not replace price lists or contract prices.

Same topic for other readers: User · Developer

Where next#

Was this page helpful?