Skip to content

Commit 1e543a0

Browse files
Provide more realistic discount rule / reward provider examples
1 parent a9073fd commit 1e543a0

File tree

1 file changed

+87
-48
lines changed

1 file changed

+87
-48
lines changed

16/umbraco-commerce/key-concepts/discount-rules-and-rewards.md

Lines changed: 87 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,30 @@ There are two types of Discount Rules in Umbraco Commerce:
2323
An example of an Order Discount Rule Provider would look something like this:
2424

2525
```csharp
26-
[DiscountRuleProvider("myCustomOrderRule")]
27-
public class MyCustomOrderRuleProvider : OrderDiscountRuleProviderBase<MyCustomOrderRuleProviderSettings>
26+
[DiscountRuleProvider("customerEmailDomainRule")]
27+
public class CustomerEmailDomainRuleProvider : OrderDiscountRuleProviderBase<CustomerEmailDomainSettings>
2828
{
29-
public override async Task<DiscountRuleResult> ValidateRuleAsync(DiscountRuleContext ctx, MyCustomOrderRuleProviderSettings settings)
29+
public CustomerEmailDomainRuleProvider(UmbracoCommerceContext ctx) : base(ctx) { }
30+
31+
public override DiscountRuleResult ValidateRule(DiscountRuleContext ctx, CustomerEmailDomainSettings settings)
3032
{
31-
if (/* Some custom logic */)
32-
return Fulfilled();
33+
var customerEmail = ctx.Order.CustomerInfo.Email;
34+
35+
if (string.IsNullOrEmpty(customerEmail) || string.IsNullOrEmpty(settings.EmailDomain))
36+
return Unfulfilled();
3337

34-
return Unfulfilled();
38+
// Check if customer email ends with the specified domain
39+
return customerEmail.EndsWith($"@{settings.EmailDomain}", StringComparison.OrdinalIgnoreCase)
40+
? Fulfilled()
41+
: Unfulfilled();
3542
}
3643
}
3744

38-
public class MyCustomOrderRuleProviderSettings
45+
public class CustomerEmailDomainSettings
3946
{
40-
[DiscountRuleProviderSetting(Key = "priceType")]
41-
public OrderPriceType PriceType { get; set; }
42-
43-
...
47+
[DiscountRuleProviderSetting(Key = "emailDomain")]
48+
public string EmailDomain { get; set; }
4449
}
45-
4650
```
4751

4852
All Order Discount Rule Providers inherit from a base class `OrderDiscountRuleProviderBase<TSettings>`. `TSettings` is the type of a Plain Old Class Object (POCO) model class representing the Discount Rule Providers settings.
@@ -66,24 +70,26 @@ If the passed-in context (which contains a reference to the Order) meets the Rul
6670
An example of an Order Line Discount Rule Provider would look something like this:
6771

6872
```csharp
69-
[DiscountRuleProvider("myCustomOrderLineRule")]
70-
public class MyCustomOrderLineRuleProvider : OrderLineDiscountRuleProviderBase<MyCustomOrderLineRuleProviderSettings>
73+
[DiscountRuleProvider("minimumQuantityRule")]
74+
public class MinimumQuantityRuleProvider : OrderLineDiscountRuleProviderBase<MinimumQuantitySettings>
7175
{
72-
public override async Task<DiscountRuleResult> ValidateRuleAsync(DiscountRuleContext ctx, MyCustomOrderLineRuleProviderSettings settings)
76+
public MinimumQuantityRuleProvider(UmbracoCommerceContext ctx) : base(ctx) { }
77+
78+
public override DiscountRuleResult ValidateRule(DiscountRuleContext ctx, MinimumQuantitySettings settings)
7379
{
74-
if (/* Some custom logic */)
75-
return Fulfilled(fulfilledOrderLines);
76-
77-
return Unfulfilled();
80+
// Check if any line meets minimum quantity
81+
var qualifyingLines = ctx.ApplicableOrderLines
82+
.Where(line => line.Quantity >= settings.MinimumQuantity)
83+
.ToList();
84+
85+
return qualifyingLines.Any() ? Fulfilled(qualifyingLines) : Unfulfilled();
7886
}
7987
}
8088

81-
public class MyCustomOrderLineRuleProviderSettings
89+
public class MinimumQuantitySettings
8290
{
83-
[DiscountRuleProviderSetting(Key = "priceType")]
84-
public OrderPriceType PriceType { get; set; }
85-
86-
...
91+
[DiscountRuleProviderSetting(Key = "minimumQuantity")]
92+
public decimal MinimumQuantity { get; set; }
8793
}
8894

8995
```
@@ -97,27 +103,49 @@ All Order Line Discount Rule Providers inherit from a base class `OrderLineDisco
97103
An example of a Discount Reward Provider would look something like this:
98104

99105
```csharp
100-
[DiscountRewardProvider("myDiscountReward")]
101-
public class MyDiscountRewardProvider : DiscountRewardProviderBase<MyDiscountRewardProviderSettings>
106+
[DiscountRewardProvider("tieredPercentageReward")]
107+
public class TieredPercentageRewardProvider : DiscountRewardProviderBase<TieredPercentageSettings>
102108
{
103-
public override async Task<DiscountRewardCalculation> CalculateRewardAsync(DiscountRewardContext ctx, MyDiscountRewardProviderSettings settings)
109+
public TieredPercentageRewardProvider(UmbracoCommerceContext ctx) : base(ctx) { }
110+
111+
public override DiscountRewardCalculation CalculateReward(DiscountRewardContext ctx, TieredPercentageSettings settings)
104112
{
105113
var result = new DiscountRewardCalculation();
114+
var orderTotal = ctx.OrderCalculation.SubtotalPrice.Value.WithoutTax;
115+
116+
// Determine discount percentage based on order value
117+
var discountPercentage = orderTotal >= settings.HighTierThreshold ? settings.HighTierPercentage :
118+
orderTotal >= settings.MidTierThreshold ? settings.MidTierPercentage :
119+
settings.BaseTierPercentage;
106120

107-
// Some custom calculation logic goes here
121+
var discountAmount = orderTotal * (discountPercentage / 100m);
122+
123+
// Adjustment price must be negative for discounts or positive for fees
124+
var price = new Price(discountAmount * -1, 0, ctx.Order.CurrencyId);
125+
126+
result.SubtotalPriceAdjustments.Add(new DiscountAdjustment(ctx.Discount, price));
108127

109128
return result;
110129
}
111130
}
112131

113-
public class MyDiscountRewardProviderSettings
132+
public class TieredPercentageSettings
114133
{
115-
[DiscountRewardProviderSetting(Key = "priceType")]
116-
public OrderPriceType PriceType { get; set; }
134+
[DiscountRuleProviderSetting(Key = "baseTierPercentage")]
135+
public decimal BaseTierPercentage { get; set; }
117136

118-
...
119-
}
137+
[DiscountRuleProviderSetting(Key = "midTierThreshold")]
138+
public decimal MidTierThreshold { get; set; }
139+
140+
[DiscountRuleProviderSetting(Key = "midTierPercentage")]
141+
public decimal MidTierPercentage { get; set; }
120142

143+
[DiscountRuleProviderSetting(Key = "highTierThreshold")]
144+
public decimal HighTierThreshold { get; set; }
145+
146+
[DiscountRuleProviderSetting(Key = "highTierPercentage")]
147+
public decimal HighTierPercentage { get; set; }
148+
}
121149
```
122150

123151
All Discount Reward Providers inherit from a base class `DiscountRewardProviderBase<TSettings>`. `TSettings` is the Type of a POCO model class representing the Discount Reward Providers settings.
@@ -157,43 +185,54 @@ Both the `DiscountRuleProviderAttribute` and the `DiscountRewardProviderAttribut
157185
A basic label component is defined as follows:
158186

159187
```typescript
160-
import { customElement, html, property } from "@umbraco-cms/backoffice/external/lit";
188+
import { css, customElement, html, property, when } from "@umbraco-cms/backoffice/external/lit";
161189
import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element";
190+
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
162191

163-
@customElement('my-discount-rule-label')
164-
export class MyDiscountRuleLabelElement extends UmbLitElement {
192+
@customElement('uc-customer-email-domain-discount-rule-label')
193+
export class UcCustomerEmailDomainDiscountRuleLabelElement extends UmbLitElement {
165194

166195
@property()
167-
value?:Record<string, unknown>;
196+
value?: Record<string, unknown>;
168197

169198
render() {
170-
return html`-- CREATE YOUR LABEL HERE --`
199+
return when(this.value, () => html`
200+
Customer email ends with '@${this.value!.emailDomain}'
201+
`)
171202
}
203+
204+
static styles = [
205+
UmbTextStyles,
206+
css`
207+
:host {
208+
display: block;
209+
}
210+
`,
211+
];
172212
}
173213

174-
export default MyDiscountRuleLabelElement;
214+
export default UcCustomerEmailDomainDiscountRuleLabelElement;
175215

176216
declare global {
177217
interface HTMLElementTagNameMap {
178-
'my-discount-rule-label': MyDiscountRuleLabelElement;
218+
'uc-customer-email-domain-discount-rule-label': UcCustomerEmailDomainDiscountRuleLabelElement;
179219
}
180220
}
181-
182221
```
183222

184-
The component will pass a `Record<string, unknown>` value representing the rule/rewards configured values. Use this value to create your label.
223+
The component will be passed a `Record<string, unknown>` value representing the rule/rewards configured values. Use this value to create your label.
185224

186225
Once defined, your component can be registered as a Property Editor UI via a manifest entry.
187226

188227
```javascript
189-
const myDiscountRuleLabelManifest = {
228+
const customerEmailDomainDiscountRuleLabelManifest = {
190229
type: "propertyEditorUi",
191-
alias: "My.PropertyEditorUi.MyDiscountRuleLabel",
192-
name: "My Discount Rule Label",
193-
element: () => import('./my-discount-rule-label.element.js')
194-
};
230+
alias: "My.PropertyEditorUi.CustomerEmailDomainDiscountRuleLabel",
231+
name: "Customer Email Domain Discount Rule Label",
232+
element: () => import('./customer-email-domain-discount-rule-label.element.js')
233+
};
195234

196-
export const manifests = [ myDiscountRuleLabelManifest ];
235+
export const manifests = [ customerEmailDomainDiscountRuleLabelManifest ];
197236
```
198237

199238
{% hint style="info" %}

0 commit comments

Comments
 (0)