Use the following procedure to define custom price calculations that need to reason about a full collection of reservations and their related records, rather than a single reservation in isolation.
GoMeddo offers two approaches for customising the reservation price: the B25.Util_PluginManager.ReservationPrice interface (see Apply custom price calculations), and the contextual price calculation described on this page. The contextual calculation is the right choice when:
-
Pricing on one reservation depends on sibling or parent reservations
-
Queries need to be done during the price calculations. The contextual calculation allows you to bulkify the queries.
1. Create your custom price calculator class
Create a class that extends B25.CustomPriceCalculation. The class must be global so that GoMeddo can instantiate it. In that class, override the calculate method with the following signature:
global override void calculate(List<B25.CustomPriceCalculation.PriceCalculationParameters> calculationRequests)
Each PriceCalculationParameters item in the list represents one reservation that needs to be priced. It exposes the following properties:
|
Name |
Type |
Purpose |
|---|---|---|
|
|
|
Wraps the reservation currently being priced. |
|
|
|
The full collection being processed, exposing |
|
|
|
|
|
|
|
The object on which price changes are recorded. Call |
Why record changes on PriceChanges instead of writing directly to the record? This allows for the updating of fields that are read only. Allowing them to update in the UI and be returned as changes to the REST endpoint.
2. Activate the custom price calculator class
Register the class so GoMeddo uses it:
-
Go to Setup
-
Search for Custom Settings
-
Click Manage next to System Setting
-
Click New
-
Name the record Contextual Price Calculation Class, and for String Value enter the name of your custom class
As long as this setting exists, GoMeddo will call your calculate method whenever a triggering field changes on a reservation (or a related record) that the calculation depends on.
3. (Optional) Control which fields trigger the calculation
Override getTriggerConfiguration to customise:
-
Which field changes trigger a price recalculation — including fields on related objects such as Service Reservation
-
Whether a change on a child reservation should also trigger recalculation of the parent
-
Whether a change on a parent reservation should also trigger recalculation of its children
global override B25.CustomPriceCalculation.CalculationTriggerConfiguration getTriggerConfiguration()
The returned CalculationTriggerConfiguration exposes the following properties:
|
Property |
Type |
Purpose |
|---|---|---|
|
|
|
Fields whose changes trigger recalculation. Unlike the V1 interface, this set can contain fields on related objects (for example |
|
|
|
When |
|
|
|
When |
If this method is not overridden, GoMeddo uses a default trigger configuration that covers the standard Reservation pricing fields (Start, End, Base Price, Calculation Method, Quantity, Skip Subtotal Calculation) and the core Service Reservation fields (Quantity, Unit Price), with parentCalculationRequiresChildren enabled.
Examples
Fixed discount for an Installation Partner
The sample below adds the Account field to the set of triggering fields and sets the subtotal to zero when the linked Account is an Installation Partner. The default calculation runs first via super.calculate, so the standard pricing logic is still applied to every other reservation.
Apex Code
global class InstallationPartnerPriceCalculation extends B25.CustomPriceCalculation {
global override B25.CustomPriceCalculation.CalculationTriggerConfiguration getTriggerConfiguration() {
B25.CustomPriceCalculation.CalculationTriggerConfiguration config = super.getTriggerConfiguration();
config.parentCalculationRequiresChildren = true;
return config;
}
global override void calculate(List<B25.CustomPriceCalculation.PriceCalculationParameters> calculationRequests) {
super.calculate(calculationRequests);
Set<Id> accountIds = new Set<Id>();
for (B25.CustomPriceCalculation.PriceCalculationParameters request : calculationRequests) {
if (request.beingProcessed.reservation.B25__Account__c != null) {
accountIds.add(request.beingProcessed.reservation.B25__Account__c);
}
}
if (accountIds.isEmpty()) {
return;
}
Map<Id, Account> accountsById = new Map<Id, Account>([
SELECT Id, Type FROM Account WHERE Id IN :accountIds WITH USER_MODE
]);
for (B25.CustomPriceCalculation.PriceCalculationParameters request : calculationRequests) {
Account linkedAccount = accountsById.get(request.beingProcessed.reservation.B25__Account__c);
if (linkedAccount != null && linkedAccount.Type == 'Installation Partner') {
request.changes.updateFieldValue(B25__Reservation__c.B25__Subtotal__c, 0);
}
}
}
}
Parent subtotal as the sum of its children
The sample below recalculates the parent reservation's subtotal as the sum of its child reservations' subtotals. Because child changes must flow up to the parent, parentCalculationRequiresChildren is kept enabled (it is on by default).
global class RollupChildSubtotals extends B25.CustomPriceCalculation {
global override B25.CustomPriceCalculation.CalculationTriggerConfiguration getTriggerConfiguration() {
B25.CustomPriceCalculation.CalculationTriggerConfiguration config = super.getTriggerConfiguration();
config.triggeringFields.add(B25__Reservation__c.B25__Account__c);
return config;
}
global override void calculate(List<B25.CustomPriceCalculation.PriceCalculationParameters> calculationRequests) {
super.calculate(calculationRequests);
for (B25.CustomPriceCalculation.PriceCalculationParameters request : calculationRequests) {
if (!request.isParent) {
continue;
}
Decimal total = 0;
for (B25.Reservation child : request.collection.childReservations) {
total += child.reservation.B25__Subtotal__c ?? 0;
}
request.changes.updateFieldValue(B25__Reservation__c.B25__Subtotal__c, total);
}
}
}