feat: Add allocation method type ONCE (#13700)
### What
Add a new `once` allocation strategy to promotions that limits application to a maximum number of items across the entire cart, rather than per line item.
### Why
Merchants want to create promotions that apply to a limited number of items across the entire cart. For example:
- "Get $10 off, applied to one item only"
- "20% off up to 2 items in your cart"
Current allocation strategies:
- `each`: Applies to each line item independently (respects `max_quantity` per item)
- `across`: Distributes proportionally across all items
Neither supports limiting total applications across the entire cart.
### How
Add `once` to the `ApplicationMethodAllocation` enum.
Behavior:
- Applies promotion to maximum `max_quantity` items across entire cart
- Always prioritizes lowest-priced eligible items first
- Distributes sequentially across items until quota exhausted
- Requires `max_quantity` field to be set
### Example Usage
**Scenario 1: Fixed discount**
```javascript
{
type: "fixed",
allocation: "once",
value: 10, // $10 off
max_quantity: 2 // Apply to 2 items max across cart
}
Cart:
- Item A: 3 units @ $100/unit
- Item B: 5 units @ $50/unit (lowest price)
Result: $20 discount on Item B (2 units × $10)
```
**Scenario 2: Distribution across items**
```javascript
{
type: "fixed",
allocation: "once",
value: 5,
max_quantity: 4
}
Cart:
- Item A: 2 units @ $50/unit
- Item B: 3 units @ $60/unit
Result:
- Item A: $10 discount (2 units × $5)
- Item B: $10 discount (2 units × $5, remaining quota)
```
**Scenario 3: Percentage discount - single item**
```javascript
{
type: "percentage",
allocation: "once",
value: 20, // 20% off
max_quantity: 3 // Apply to 3 items max
}
Cart:
- Item A: 5 units @ $100/unit
- Item B: 4 units @ $50/unit (lowest price)
Result: $30 discount on Item B (3 units × $50 × 20% = $30)
```
**Scenario 4: Percentage discount - distributed across items**
```javascript
{
type: "percentage",
allocation: "once",
value: 15, // 15% off
max_quantity: 5
}
Cart:
- Item A: 2 units @ $40/unit (lowest price)
- Item B: 4 units @ $80/unit
Result:
- Item A: $12 discount (2 units × $40 × 15% = $12)
- Item B: $36 discount (3 units × $80 × 15% = $36, remaining quota)
Total: $48 discount
```
**Scenario 5: Percentage with max_quantity = 1**
```javascript
{
type: "percentage",
allocation: "once",
value: 25, // 25% off
max_quantity: 1 // Only one item
}
Cart:
- Item A: 3 units @ $60/unit
- Item B: 2 units @ $30/unit (lowest price)
Result: $7.50 discount on Item B (1 unit × $30 × 25%)
```
This commit is contained in:
@@ -7569,6 +7569,9 @@
|
||||
"allocation": {
|
||||
"type": "string"
|
||||
},
|
||||
"allocationTooltip": {
|
||||
"type": "string"
|
||||
},
|
||||
"addCondition": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -8048,9 +8051,22 @@
|
||||
},
|
||||
"required": ["title", "description"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"once": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["title", "description"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["each", "across"],
|
||||
"required": ["each", "across", "once"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"code": {
|
||||
|
||||
@@ -2021,6 +2021,7 @@
|
||||
"campaign": "Campaign",
|
||||
"method": "Method",
|
||||
"allocation": "Allocation",
|
||||
"allocationTooltip": "Each enforces the quantity limit per item, while Once enforces the quantity limit across the entire cart",
|
||||
"addCondition": "Add condition",
|
||||
"clearAll": "Clear all",
|
||||
"taxInclusive": "Tax Inclusive",
|
||||
@@ -2162,6 +2163,10 @@
|
||||
"across": {
|
||||
"title": "Across",
|
||||
"description": "Applies value across items"
|
||||
},
|
||||
"once": {
|
||||
"title": "Once",
|
||||
"description": "Applies value to a limited number of items"
|
||||
}
|
||||
},
|
||||
"code": {
|
||||
|
||||
Reference in New Issue
Block a user