Sales Discount Rules

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

Menu Route

General 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 General / 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

FieldRequiredExplanation
Code (id)YesNumeric rule code. This code is stored in the salesdiscrules JSON field in Customer or Product.
Description (description)YesLong rule name. Use a name that explains the condition and result, for example "Wholesale discount 12 pcs".
Display Name (displayname)YesShort name with a maximum of 20 characters for compact display.
Category (category)YesProduct calculates item values. Transaction calculates invoice discount.
Kind (kind)YesSales Price returns a new selling price. Percent Disc returns a percent discount. Value Disc returns a value discount.
Formula (formula)YesCalculation expression evaluated by ExpressionCalc. The editor looks like JavaScript, but backend evaluation uses the PHP expression parser.
Variables (variables)NoAutocomplete list from vw_salesdiscrules. Selecting a variable copies it to the clipboard.
Functions (functions)NoFormula helper list. Selecting a function copies a template to the clipboard.
Audit fieldsNousercreate, 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 GroupExamplesNotes
Product and unitproductid, productgroup, brand, unitUsed for product-specific price or discount rules.
Customer and salespersoncustomerid, customergroup, salesmanUsed for customer-level or salesperson-level promotions.
Quantity and priceqty, salesprice, subtotalUsed for tiered quantity discounts or price changes.
Invoice summarygrossamount, brandgross, suppliergrossUsed 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

FunctionExampleUse
roundround(grossamount / 1000) * 1000Round a calculated value.
floorfloor(qty / 10)Return a whole number, commonly used for buy X get Y rules.
ceilceil(qty / 12)Round up when a minimum package should count as one.
min / maxmin(10, percentdisc)Limit a result to a safe range.
stackeddiscountstackeddiscount(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

NeedExample FormulaResult
10% item discount when quantity reaches 12qty >= 12 ? 10 : 0Percent Disc returns 10 or 0.
Special price for high quantityqty >= 24 ? 95000 : salespriceSales Price returns a replacement selling price.
Invoice discount by gross amountgrossamount >= 1000000 ? 5 : 0Transaction Percent Disc returns 5%.
Rounded value discountround(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.