Time Rated Services
v6
General Description
The SyrveFront application can be used to sell not only goods and dishes but also services with time-based pricing. These can include establishments with payment for the time spent (water parks, anti-cafes), equipment rentals, and much more, but a classic example is billiards, which will be used in this article to describe the subject area.
Starting and Stopping
The service can be started and stopped. When the service is started, time is counted, the “quantity” increases, and, accordingly, the cost rises. When the service is stopped, the time count is paused, and these periods are not charged.
The service can be ordered for a specific time; in this case, all ordered time is charged, even if the service was actually used for a shorter time. For example, a visitor can order billiards for an hour, with the cost initially set for 1 hour and not changing, while the “quantity” will increase over time. When the specified time limit is reached, the service will automatically stop. Another option is payment based on actual usage; you can play until you get tired and pay for the total time, then no limit is set, but the service will stop when the maximum possible duration of 12 hours is reached.
Starting and stopping the service may be accompanied by an additional action tied to the table on which the order is placed. In the case of billiards, this may involve turning on the lighting above the table during the game: initially, the light is off, the service is started — the light turns on, stopped — it goes out. This leads to a limitation — no more than one service can be started on a table. Currently, this limitation applies to all tables regardless of whether such additional actions are configured. In future versions, this limitation will not apply to tables or services that do not have ties to external devices.
Pricing
The cost of the service may depend on the day of the week and change over time. Two pricing options are possible:
- by time of day — for example, during the day the service may cost less, while in the evening hours it costs more, allowing for a balance between periods of low and high demand;
- by the duration of the service itself — for example, when the first hour is the most expensive, and each subsequent hour is cheaper, motivating visitors to consume the service in greater volume.
Time accounting is conducted according to the following rules:
- A unit of measurement is set, and the duration of the service is rounded up to the nearest value; for example, if hourly pricing is set and the service was started for 70 minutes, payment will be required for two hours.
- A minimum duration may be set — for example, if the service was started for only 10 minutes, and the minimum duration is half an hour, payment will be required for half an hour, even if minute-based pricing is selected. If the service was started for 31 minutes with the same settings, payment will be required for 31 minutes.
- Over time, switching between rates occurs automatically, and the duration of service usage for each rate is remembered. Periods corresponding to different rates will be charged at different prices.
Data Structures
Service
IOrderServiceItem — an order item corresponding to a time-based service. It is located in the collection IOrder.Items alongside dishes that can be prepared (IOrderCookingItem).
In the menu, the time-based service corresponds to a product (IProduct) with the type ProductType.Service and has pricing parameters IProduct.RateSchedule (if pricing parameters are not set, it is a service without time-based pricing, it is added to the order and paid for like a regular dish).
Key properties of the time-based service:
Service— the product corresponding to this service, defines availability in the menu, base price (default rate), etc.Periods— a list of service operation periods corresponding to different rates. When the service is started, the first period is added to the list, its time and cost increase until a switch to another rate occurs, for which a second period will be added, and so on. Each rate corresponds to one period: if the rate grid is configured such that one rate applies first, then another, and then back to the first, the time of the first period will grow first, then the second, and then back to the first.IsStarted— whether the service is currently started.Price— base price per unit of time (individual periods may be charged at different prices).TimeLimit— time limit. If set, the service will automatically stop when the limit is reached. Even if the service is manually stopped earlier, payment will still be required for all ordered time, while the used time is accounted for and charged within the periods, and the unused time is accounted for within the service itself (seeRemainingLimitCost).RemainingLimitCost— cost of the unused part of the time limit. If no limit is set, 0. When a limit is set, the initial cost will be the full cost of the time limit (since the service has not yet been started, there are no periods of operation, all ordered time has not yet been used), and over time it will decrease simultaneously with the increase in period costs (the unused part of the limit decreases while the used part increases) until it reaches zero.Cost— total cost of this service, includes the sum for all periods and the cost of the unused part of the time limit.ResultSum— final cost of this service, including discounts, surcharges, and VAT.
Service Period
IOrderServiceItemPeriod — the period of service operation under a specific rate, includes all time segments when the corresponding rate was active.
Key properties of the time-based service period:
Service— the product corresponding to the rate of this period. Either a product of typeProductType.Servicetaken from the service as the default rate, or a product of typeProductType.Ratetaken from the rate grid.Price— price per unit of time.ElapsedTime— total time when the corresponding rate was active. If the service was started and stopped multiple times, or there were switches between rates back and forth, all time segments when the rate was active will be collected into one period, and here will be the exact (not rounded) total length of all these segments. Payment is made for rounded time, but the actual time is recorded. For example, if payment is hourly, andElapsedTimeaccumulated only 10 minutes, the cost of the period will correspond to one hour and will not change in the next 50 minutes of this rate’s operation.Cost— total cost of this period. It is already included in the cost of the service (both total and final), so they should not be summed again. This property is intended only for the possibility of detailing the service cost by rates.
Pricing Settings
RateSchedule — settings for the time-based service, key properties:
TimingMode— pricing mode, by time of day or by the duration of the service itself.Items— rate grid, a list of elements of typeRateScheduleItemdefining time segments with rates different from the base rate. A time segment (RateScheduleInterval) is defined by the day of the week and the offset of the start and end of the segment relative to the start of the pricing scale. Depending on the selected pricing mode (TimingMode), the start of the scale will either be the start of the day (the entire scale [0;24) hours), or the start of the service (the entire scale [0;12) hours). It is guaranteed that time segments do not overlap. If the list is empty, the base rate always applies.TimingStep— unit of measurement. The actual time of service operation is rounded up to the nearest multiple value.MinimumDuration— minimum duration of the service, ornullif no lower limit is set.
Service Management
AddOrderServiceItem — adding a service to an order.
StartService — starting a service.
StopService — stopping a service. The service will stop automatically when the order is checked or paid.
Examples
In the SamplePlugin, which is part of the SDK, there are examples of adding a service to an order, starting, and stopping a service — the methods [StartService] and [StopService] in the class EditorTester:
private static void StartService()
{
var order = PluginContext.Operations.GetOrders().Last(x => x.Status == OrderStatus.New);
var serviceProduct = PluginContext.Operations.GetActiveProducts().Last(x => x.Type == ProductType.Service && x.RateSchedule != null);
var credentials = PluginContext.Operations.GetCredentials();
var service = PluginContext.Operations.AddOrderServiceItem(serviceProduct, order, order.Guests.Last(), credentials, TimeSpan.FromHours(2));
PluginContext.Operations.StartService(credentials, order, service);
}
private static void StopService()
{
var order = PluginContext.Operations.GetOrders().Last(x => x.Status == OrderStatus.New);
var service = order.Items.OfType<IOrderServiceItem>().Last(x => x.IsStarted);
PluginContext.Operations.StopService(PluginContext.Operations.GetCredentials(), order, service);
}