Promotion Types
The Commerce promotion engine has no built-in promotion logic. All promotion types are provided by apps. A promotion type consists of two parts:
- A Filtrera promotion script (
.hpr) that computes discounts against an order - A Vue settings component that renders the type's configuration UI in the portal
The Promotion Script
Promotion scripts use the .hpr extension and are referenced by a componentId. The runtime provides the script with an order value containing the full order state, and calls the script once per promotion application.
Input
The order value is available globally in the script (no param declaration needed):
order.orderId // uuid
order.currencyCode // text
order.channelKey // text
order.orderTotal // number
order.deliveries // [Delivery]
.shippingPrice // number
.orderLines // [OrderLine]
.orderLineId // uuid
.productNumber // text
.quantity // number
.unitPrice // numberParameters
Declare param statements to receive configuration from the promotion's settings:
param threshold: number = 0
param discountIsPercentage: bool = trueParameter values are set by the portal UI via the settings component and stored on the promotion rule. The runtime injects them when the script executes.
Discount Effects
Scripts produce discount effects using two built-in functions:
| Function | Description |
|---|---|
percentage(target, percent) | Apply a percentage discount to matching entities |
absolute(target, amount) | Apply a fixed-amount discount to matching entities |
Both functions take a target(predicate) expression that selects which order entities receive the discount:
// Discount all order lines by 10%
percentage(target(e => e is OrderLine), 10%)
// Discount a specific delivery by 100%
percentage(target(d => d is Delivery and d.deliveryId == someId), 100%)
// Fixed amount off all order lines
absolute(target(e => e is OrderLine), 50)A script can produce multiple discount effects — one per from statement.
Messages
Scripts can return a user-facing message instead of (or alongside) a discount:
from {
type = 'message'
message = $'Add {threshold - order.orderTotal} more to qualify!'
}Messages are surfaced in the rendered cart and can be used to communicate promotion thresholds to the customer.
The Settings Component
The settings component is a standard Vue component that receives the promotion context as props:
interface PromotionTypeSlotContext {
promotionKey: string
promotionType: string
parameters: Record<string, any>
setParameter: (key: string, value: any) => void
removeParameter: (key: string) => void
isNew: boolean
}Use setParameter and removeParameter to manage the type-specific parameters that will be passed to the .hpr script at runtime:
<script setup lang="ts">
import { computed } from 'vue'
const props = defineProps<{
promotionKey: string
promotionType: string
parameters: Record<string, any>
setParameter: (key: string, value: any) => void
removeParameter: (key: string) => void
isNew: boolean
}>()
const threshold = computed({
get: () => props.parameters['threshold'] ?? 0,
set: (value) => {
if (value > 0) {
props.setParameter('threshold', value)
} else {
props.removeParameter('threshold')
}
},
})
</script>Parameter names must match the param declarations in the .hpr script exactly.
Registering the Type
1. Declare the component in h_app.yaml
components:
- id: promotions/my-promotion-type.hprThe id determines the componentId you'll reference during registration.
2. Register in portal/index.ts
Import the promotionTypeService and register your type with its key, label, component ID, and settings component:
import { portal } from '@hantera/portal-app'
import { promotionTypeService } from '@hantera/apps-commerce'
import MyPromotionSettings from './components/MyPromotionSettings.vue'
portal.registerService(promotionTypeService, () => ({
types: [
{
key: 'my-promotion-type',
label: 'My Promotion Type',
componentId: 'apps/my-app/promotions/my-promotion-type.hpr',
component: MyPromotionSettings,
},
],
}))The key is a stable identifier used to associate portal-created promotions with this type. The componentId must match the fully-qualified ID of the .hpr component as it appears in your app.
Once registered, the type appears in the promotion type selector when creating a new promotion in the portal.