Discounts and Surcharges

Tags: v6

SyrveRms has a built-in discount system. Third-party loyalty systems (plazius, SyrveCard, etc.) are not covered in this article. The SyrveRms discount system allows for the application of discounts and surcharges under various conditions. A discount is understood as a reduction in the cost of an order item by a certain amount, while a surcharge is an increase. Since the difference between a discount and a surcharge lies only in the sign of the number subtracted from the cost, for the sake of simplicity, we will refer to both as discounts (in the code DiscountType, DiscountItem, DiscountCard, etc.), implying that a positive value of DiscountSum in the subject area corresponds to a discount, while a negative value corresponds to a surcharge.

In general, a discount can be configured in such a way that within an order for one dish it reduces the cost, acting as a discount, while for another dish it increases the cost, acting as a surcharge; therefore, the distinction between discounts and surcharges can be considered quite conditional.

Limitations

The rules and conditions for applying discounts (DiscountItem) are determined by the type (DiscountType), which can be a fixed amount (voucher), a percentage of the cost, rounding (dropping cents), and so on, but the result of applying a discount (AppliedDiscountItem) is always an absolute value, a specific number. The algorithms for applying discounts depend on the category of the dish, the section of the order, the order amount (FullSum), the service mode, the current time, and the service print time; discounts may or may not be combined, and can be applied either in parallel (to the total cost) or sequentially (taking into account the application of previous discounts). All these conditions are implementation details and are not published in the API.

The API only provides general settings, such as:

The discount amount is calculated separately for each order item, even if the discount applies to the entire order. Thus, a discount on the order is the sum of the discounts on its items. The discount amount, like any other monetary value, is a multiple of the minimum denomination of the currency. The total of all active discounts on an order item does not exceed its cost; in other words, the result of subtracting discounts from the cost can reach zero (100% discount), but cannot become negative. There is no such limitation for surcharges; any value can be added to the cost of an order item.

Lifecycle

A discount added to an order can be in one of two states — fixed or not fixed. Transitions between these states are possible, but cannot be directly controlled; the state is tied to the lifecycle of the order. Currently, discounts are fixed when the order is moved to the status Bill and return to an unconfirmed state when moved to the New status, but this is an implementation detail that may change at any time.

Discount Not Fixed

When a discount is added to an order, only the data on how to calculate it is remembered. Amounts are calculated on the fly upon request, and the results of calculations are not stored. Since the latest available values of the parameters of the discount application algorithm, including settings from Syrve Office and the current time, are used in each calculation, the results may vary. Accordingly, the final cost of the order may also change.

Automatically added discounts (IsAutomatic) implicitly exist in all orders with unconfirmed discounts; until fixed, they will not appear in the Discounts list of each order, and after fixing — it depends on the presence of the effect of application to the order.

Discount Fixed

When the order reaches a point where its final cost should no longer change, the on-the-fly calculated values (prices, discounts, etc.) are fixed. The result of the last calculation is saved and used in subsequent requests instead of recalculating. This allows for independence from changes in settings or other parameters of discount applications. From this point on, in addition to the algorithm and parameters for applying the discount, specific amounts for each order item are remembered. However, if at the time of fixing the discount was not actually applied (had a zero effect), it is removed from the order.

Data Structures

Note: the total discount for the order should not be defined as the difference between the last two values, as they differ not only in terms of discounts but also in terms of value-added tax (VAT), which is not included in the price of goods. It is better to calculate the discount amount by summing up DiscountSum.

Selective Application of Discounts

By default, discounts apply to all dishes, including those added after the discount is assigned. However, discounts with the CanApplySelectively setting enabled can be selectively applied to one or more items in the order, and they will only apply to those items. For example, when selling baked goods, hot items may be sold at full price, while the same items that have cooled down may be sold at a discount. The product item is the same in both cases. The decision is made by the user (or plugin), setting the restriction on which dishes and modifiers the discount will apply. This restriction works as a whitelist, so a selectively applied discount will not apply to dishes added later. All other restrictions (by category, by time, by amount, etc.) remain in effect, meaning that the discount will effectively apply only to those items in the whitelist that meet the other conditions.

A selectively applied discount only affects the specified items in the order. For example, if there is a dish with paid modifiers in the order, and the discount is selectively applied only to the dish, it will only apply to the dish. To selectively apply the discount to both dishes and modifiers, both the dish and the modifiers must be explicitly specified.

Key Functions:

Examples

An example of selective discount application can be found in the SDK plugin Resto.Front.Api.SamplePlugin (EditorTester.AddSelectiveDiscount):

/// <summary>
/// Adding a discount with the ability to select dishes.
/// </summary>
private void AddSelectiveDiscount()
{
    var order = PluginContext.Operations.GetOrders().Last();
    var selectedDish = new List<IOrderProductItemStub> { order.Items.OfType<IOrderProductItem>().Last() };
    var discountType = PluginContext.Operations.GetDiscountTypes().Last(x => !x.Deleted && x.IsActive && x.CanApplySelectively);

    var editSession = PluginContext.Operations.CreateEditSession();
    editSession.AddDiscount(discountType, order);
    editSession.ChangeSelectiveDiscount(order, discountType, selectedDish, null, null);
    PluginContext.Operations.SubmitChanges(PluginContext.Operations.GetCredentials(), editSession);
}