Module Reference

Discounts

Sales, codes, buy X get Y offers, free gifts, member prices and happy hours for the shop, the register, food ordering and bookings.

Discounts holds every discount a business runs, on one Discounts page under Sales. A discount set up once works wherever the business sells: the online shop in Storefront, the register in POS, food ordering from the table in Guest ordering, and Booking. Each of them prices a sale with the same rules, and each sale records what came off each line, so receipts, VAT, deposits, refunds and staff commission all use the same amounts. Storefront, POS and Booking need it, so it can't be switched off while any of them is on. It doesn't own products, menu items or services; it points at them in the Modules that do.

How a discount works

To make one, open Discounts and choose New discount. Choose how it applies, give an automatic discount its name or a typed one its code, pick a type, and it's saved, switched off. Everything else is set on the discount itself: click a value to change it, and the change applies straight away. Switch on Active when it's ready.

TypeWhat it gives
Percent offA percentage off the whole order, or off the items you choose.
Amount offA fixed amount off the order, or off each chosen item.
Free shippingNo shipping charge on a shop order.
Buy X get YWhen the customer buys enough, some items are free or at a percentage off.

Automatic or with a code, and its name

How it applies has two choices. Automatically means the discount applies by itself whenever its conditions hold. With a code means the customer types the code at checkout or on the booking page, or gives it to a cashier.

Every discount can have a name in English and Thai, such as "Spring sale". An automatic discount needs one, because nobody types its code. Customers see the name, not the code, in the cart, at checkout, on receipts, on a diner's ticket and on a booking. An item on sale shows the name on its badge instead of the plain "Sale". A discount with no name shows its code.

What it applies to

Applies to is either the Whole order or Chosen items. Chosen items can be products, collections, register items, register categories or booking services. A register item linked to a shop product counts as that product too, so one "Spring sale on the Spring collection" covers the collection online and in store.

Where and when

  • Where lists the places it runs: Shop, Register, Food ordering and Bookings. A discount for the register only never touches an online order. Food ordering covers tickets a diner opened by scanning a table's QR code.
  • Locations narrows it to the branches you pick. Leave it on all locations to run everywhere.
  • Minimum spend sets the total a sale needs first, and Minimum quantity how many of the chosen items (or of anything, for the whole order) the customer must buy. Gift cards never count toward a minimum and are never discounted.
  • Starts and Ends are in the business's time zone. Leave them empty for a discount that runs until you switch it off.
  • Time window limits it to certain days and hours, such as Monday to Friday 15:00–18:00. The hours are in each location's time zone, and a window that ends before it starts runs past midnight. For bookings, the window is checked against the appointment time, so "weekday mornings, 15% off" applies to a Monday 10:00 appointment booked on a Sunday. The dates are checked against when the booking is made.
  • Customer limits it to Any member or to the membership tiers you choose. It needs Membership: in the shop the member is signed in, at the register the member is added to the ticket, and for bookings the person booking is a member. A paused member doesn't get member discounts.

Buy X get Y and free gifts

A Buy X get Y discount says what the customer buys (Customer buys: a quantity of chosen items) and what they get (Customer gets: a quantity of the same or other items, free or at a percentage off). Times per order caps how often it repeats in one sale; empty repeats as often as the order allows. The cheapest qualifying item is the one that comes free, and an item never counts both as bought and as free.

When what the customer gets is one free product or register item, it works as a gift:

  • In the shop and in food ordering, the gift goes into the cart by itself as soon as the cart earns it, marked Free gift, and comes out if the cart stops earning it. Items the customer added themselves are never taken out, and a gift the customer removes isn't added back.
  • A gift that's out of stock isn't added, and the cart says so. Its stock is held at checkout like any other item.
  • At the register, the cashier sees Add free … on the ticket and taps it, since someone has to hand the item over.

Combining discounts

Every discount is an item discount, an order discount or a shipping discount. Combines with says which of those it may apply together with, and two discounts apply together only when each allows the other's kind. With all three off, a discount never applies alongside another. When a sale qualifies for discounts that can't be combined, the customer gets the set that saves them the most.

Discounts apply in a fixed order: item discounts first (at most one on each line, the one that saves more there), then order discounts on what the items still cost, then shipping. An order discount is capped at what's left, so stacked discounts never take a sale below zero. At the register, the bill discount (an amount, a percentage, a comp or points) comes after all of them.

Usage limits

Usage limit caps how many times a discount can be used in total, counted across the shop, the register and bookings. A use is held while a sale is in progress and counted once it's paid. An abandoned cart, a voided ticket or a booking whose hold expires gives the use back. When a sale carries several codes, it holds all of them or none.

Staff discounts at the register

Turn on Staff only for a discount only a cashier can give, such as a damaged-item discount or a staff meal. Customers can't type it, and it never applies by itself. On the ticket, the cashier opens Discounts and picks it under Staff discounts, and it applies to the whole ticket. Who can apply it sets the lowest role that may: Any staff, Managers and owners or Owners only.

Refunds and commission

A shop return suggests the returned items' share of what their line actually paid, after the discount. Returning one of three shirts on a "buy 2 get 1 free" line that paid ฿600 suggests ฿200. Staff can change the amount, and a return doesn't take back a gift or a discount the rest of the order no longer qualifies for. Staff commission on a booking is worked out on what the customer paid after discounts, not on the list price.

Run a spring sale on a collection

1

Create the discount

Open Discounts and choose New discount. Set How it applies to Automatically, enter the name shoppers see, "Spring sale", in English and Thai, keep Percent off, and create it. Its code is made from the name, and it starts switched off.

2

Set the percent and pick the collection

Enter 20 as the value. Set Applies to to Chosen items, search for the Spring collection and pick it.

3

Choose where and when

Under Where, keep Shop, and add Register to run it in store too. Set Starts and Ends.

4

Switch it on

Turn on Active. Between its dates, every product in the collection shows its sale price in the shop with the regular price struck through and a "Spring sale" badge, on product cards and product pages. The cart shows what each line saves, and checkout charges the price shown. When the sale ends, the prices go back by themselves.

5

Give it a page (optional)

Under Sale page, switch the page on. Its address is made from the name, /shop/sales/spring-sale, and you can change it. Add a headline and a short introduction in each language and, with Website on, a picture from the media library. The page lists every product the sale applies to at its sale price. It's live only while the discount is: switched on, between its dates, automatic and sold in the shop. Link to it from the homepage banner or the site's menu on the Website page.

You don't change any product's price for a sale: the shop works out the sale price from the discount. Use a product's Compare-at price in Catalog instead when one item is marked down for good, such as last season's jacket that now sells at ฿1,200 instead of ฿1,800. Set its price to ฿1,200 and its compare-at price to ฿1,800, and the shop shows ฿1,800 struck through with a "Sale" badge. A compare-at price changes only what the page shows; no discount is recorded on the order.

What it handles

  • Staff who may not change discounts. Creating or editing a discount needs discounts:write, which a new app gives Managers. Anyone else is refused, and nothing is written. Tested: "Discounts: managers create and edit discounts"
  • A sale that starts at the business's midnight. A start of 20 March 00:00 entered for a business in Bangkok starts at midnight Bangkok time, whatever the time zone of the browser used to enter it. Tested: "Discounts: managers create and edit discounts"
  • A target nothing sells. A discount can only target the kinds of item that a Module in the app sells, and each kind belongs to exactly one Module. Anything else is refused when it's saved, so a discount can't silently never apply. Tested: "Discounts: managers create and edit discounts" Tested: "discount item sources"
  • Setting up a sale from the page. A manager creates 20% off the Spring collection, each change is saved as it's made, and the list shows it running in the shop once it's switched on. Tested: "Discounts: the Discounts page"
  • Sale page addresses. Two discounts can't share a page address, and an address with spaces or slashes is refused (capitals are lowered). Only staff who may change discounts can give one a page. Tested: "Discounts: a sale's page on the website"
  • Uses already held during an update. The update that moved shop promotions into Discounts kept every use a shopper had already reserved, so a one-use code still had its one use. Tested: "Discounts: promotion schema upgrade"

Each channel's own reference page lists the cases its tests prove: the shop's sale prices, gifts and combining in Storefront, codes and staff discounts in POS, and discounted deposits in Booking.

What you build on top

  • Modules that use it. Storefront, POS and Booking price their sales through Discounts, and Guest ordering prices through POS. Membership adds the Customer condition and its tier picker.
  • Your own channel. A Module your app adds that sells something can register its items as discount targets and price its sales with the same engine. See Build on a Module.
  • Your words. Rename what staff and customers see with an override.
  • In code. Your coding agent imports Discounts only through its public API: index.ts and server/index.ts in apps/web/src/modules/discounts/. See Build on a Module.

Limits

  • A discount doesn't take money off a payment method ("10% off with a bank's card"), and there are no bulk one-use codes for a campaign: each code is one discount.
  • A product's compare-at price has no dates. A markdown that should end on a day is a discount.
  • The register's bill discount (an amount, a percentage, a comp or points redemption) is separate from Discounts. It doesn't follow Combines with, and it always comes off last.

Facts

Pages

WherePath
Admin/admin/discounts

Permissions

Admin holds every key. The other roles listed hold it when the app first gets the Module; after that, roles are yours to change under Settings → Roles & Permissions.

PermissionWhat it allowsOrganization roles that start with it
admin-panel:writeFull compatibility access to all module administration, including POS, catalog, storefront, and CRM staff tools.Admin
discounts:writeCreate and edit discounts: codes, automatic discounts, what they apply to, where and when.Admin, Manager

Data

  • Tables: promo_code, promo_redemption, discount_target

Slots

Places other Modules and your app code can add to. See Extend a Module.

  • discounts.sale-page-picture

Tested workflows

  • Discounts: promotion schema upgrade
  • Discounts: managers create and edit discounts
  • Discounts: a sale's page on the website

Operator Guide pages

Pages this Module adds to the app's built-in Guide for the people who run the business.

  • Discounts