Sales Discount Rules

Guide for creating sales price, item discount, and invoice discount rules with formulas evaluated by ExpressionCalc.

Menu Route

Settings Business Rules

/form/salesdiscrules

When to Use This Form

Use this form to create master rules for sales discounts. The rule does not create a transaction by itself; it is read by sales transactions when the selected customer or product has the related rule.

Item Sales Price
Change line-item selling price based on product, customer, salesperson, unit, quantity, or temporary subtotal.
Item Discount
Apply percent or value discount per unit in Sales, Sales Order, POS, Table Order, and Shop.
Invoice Discount
Apply header-level percent or value discount based on sales gross amount and summaries by brand, supplier, factory, or product group.
This rule is only for sales pricing and discounts. Payment discounts, product rewards, and point rewards use separate rule forms.

System Overview

  1. Users create the rule in /form/salesdiscrules.
  2. Product-category rules are attached to Product master data. Customer master data must also contain the rule list so item price or item discount calculation is called from transactions.
  3. Transaction-category rules are attached to Customer master data and are used to calculate invoice-level discounts.
  4. When a transaction changes, the frontend calls POST /salespriceformula for item detail and POST /salesinvoiceformula for header discount.
  5. The backend reads formulas from salesdiscrules, passes variables into ExpressionCalc, and returns the result to the transaction form.
If several active rules of the same kind are evaluated, the last evaluated value can overwrite the previous value. Use one final rule per need, or combine tiered logic in one formula.

Before Creating a Rule

Requirement
The discount_management package is active so rule fields are visible in Customer and Product master data.
Requirement
Product, Customer, Salesperson, and product units are correct because those fields become formula variables.
Requirement
Sales price, default discount, and quantity-based prices in Units are prepared when they will be used in formulas.
Requirement
The user writing the formula understands that the formula result must be numeric: a price, percent discount, or value discount.

Workflow

  1. Open Settings / Business Rules / Sales Discount Rules.
  2. Click Add to create a new rule.
  3. Fill in Code, Description, and Display Name.
  4. Choose Category: Product for line-item rules, or Transaction for invoice-level rules.
  5. Choose Kind: Sales Price, Percent Disc, or Value Disc.
  6. Use the Variables field to copy a valid variable name.
  7. Use the Functions field when the formula needs helpers such as round or stackeddiscount.
  8. Write the formula in Formula. It must return one value.
  9. Save the rule.
  10. Attach the rule to Product or Customer according to its category, then test it in Sales, Sales Order, POS, Table Order, or Shop.

Form Fields

Field Required Explanation
Code (id) Yes Numeric rule code. This code is stored in the salesdiscrules JSON field in Customer or Product.
Description (description) Yes Long rule name. Use a name that explains the condition and result, for example "Wholesale discount 12 pcs".
Display Name (displayname) Yes Short name with a maximum of 20 characters for compact display.
Category (category) Yes Product calculates item values. Transaction calculates invoice discount.
Kind (kind) Yes Sales Price returns a new selling price. Percent Disc returns a percent discount. Value Disc returns a value discount.
Formula (formula) Yes Calculation expression evaluated by ExpressionCalc. The editor looks like JavaScript, but backend evaluation uses the PHP expression parser.
Variables (variables) No Autocomplete list from vw_salesdiscrules. Selecting a variable copies it to the clipboard.
Functions (functions) No Formula helper list. Selecting a function copies a template to the clipboard.
Audit fields No usercreate, useredit, and updatetimestamp are filled automatically.

Attaching the Rule to Master Data

Attach Product-category rules to Product when the rule should react to a specific item. The same rule should also be allowed for the Customer so the transaction can evaluate it.

Attach Product-category rules for item price or item discount, and Transaction-category rules for invoice discount. Customer rules control which formulas are available during sales entry.

How the Formula Works

  1. The transaction prepares variables from the selected product, customer, salesperson, unit, quantity, price, discount, tax, and transaction summary.
  2. The backend loads the rule formula and evaluates it through ExpressionCalc.
  3. For Sales Price, the result becomes the item selling price.
  4. For Percent Disc, the result becomes item or invoice percent discount.
  5. For Value Disc, the result becomes item or invoice value discount.
  6. If the formula is invalid, the transaction should be tested again after the formula is corrected.
Formula result must be numeric.
Use Product category for item price or item discount.
Use Transaction category for invoice discount.
Avoid writing fixed dates or fixed customer IDs unless the promotion is intentionally limited.

Available Variables

Variable Group Examples Notes
Product and unit productid, productgroup, brand, unit Used for product-specific price or discount rules.
Customer and salesperson customerid, customergroup, salesman Used for customer-level or salesperson-level promotions.
Quantity and price qty, salesprice, subtotal Used for tiered quantity discounts or price changes.
Invoice summary grossamount, brandgross, suppliergross Used for transaction-level invoice discount formulas.

Use the variable selector in the form to copy valid variable names. Variable names are case-sensitive.

Functions and Formula Syntax

Function Example Use
round round(grossamount / 1000) * 1000 Round a calculated value.
floor floor(qty / 10) Return a whole number, commonly used for buy X get Y rules.
ceil ceil(qty / 12) Round up when a minimum package should count as one.
min / max min(10, percentdisc) Limit a result to a safe range.
stackeddiscount stackeddiscount(10, 5) Calculate stacked discount logic when it is enabled in the expression engine.
Write one expression that returns one value. Avoid multiple statements. Test the formula with realistic transaction data before using it in daily operations.

Formula Examples

Need Example Formula Result
10% item discount when quantity reaches 12 qty >= 12 ? 10 : 0 Percent Disc returns 10 or 0.
Special price for high quantity qty >= 24 ? 95000 : salesprice Sales Price returns a replacement selling price.
Invoice discount by gross amount grossamount >= 1000000 ? 5 : 0 Transaction Percent Disc returns 5%.
Rounded value discount round(grossamount * 0.02) Value Disc returns 2% of gross amount rounded.

Testing Checklist

  • Test with a customer that has the rule attached.
  • Test with a product that has the rule attached when the category is Product.
  • Test below and above the promotion threshold.
  • Check Sales, Sales Order, POS, Table Order, or Shop depending on where the rule will be used.
  • Check whether multiple active rules overwrite each other.

Common Issues

  • Rule does not run: check whether the rule is attached to Customer and, for Product rules, to Product.
  • Wrong discount: check Category and Kind first.
  • Formula returns empty or error: check variable names, syntax, and whether the variable exists in the selected transaction context.
  • Invoice discount does not change: make sure the rule category is Transaction and it is attached to Customer.