Pay-Per-Time Services
Overview
The Syrve POS app can be used not only to sell goods and items but also for services charged per time. Venues, where customers pay per time they spend there (water parks, bowling, anticafés), can be a good example. In this article, we use pool to describe the subject matter.
Start & Stop
You start and stop the service. The system tracks time while the service is running; the «quantity» is growing and thus growing the total amount. When the service is stopped, the time meter is stopped as well. Customers only pay for the playtime.
Customers may choose to pay for a specific time in advance. In this case, the service is paid in full even if customers decide to leave earlier. Suppose a guest buys one hour of pool. In this case, the time limit and the price are set and won’t change, unlike the «quantity», which will grow as time passes. When the limit is reached, the service will stop automatically. Alternatively, customers may choose to pay upon completion of services for the overall playtime. In this case, the time limit is not set, and the time will continue to progress until the maximum permissible duration of 12 hours is reached.
The starting and stopping can be accompanied by an additional action linked to the table where the order is placed. In the case of pool, it can be putting the light on over the table during the playtime: by default, the lights are off, when the service is started, the light turns on, when the service is stopped, the light goes off. This creates a restriction — no more than one concurrently running service per table. For now, this restriction applies to all tables regardless of whether such additional actions are set or not. In later versions, this restriction will not apply to the tables or services with no links to external devices.
Rates
The service price may depend on the day of the week and change with time. There are two rate types:
- By time of day — in the middle of the day the service may be cheaper than in the evening, which helps to balance the low-demand and high-demand periods out.
- By service time — the first hour may be the most expansive while each successive hour is cheaper than the previous, which makes it tempting to purchase more time.
The time is tracked according to the following rules:
- A measurement unit needs to be set. The service time is rounded up to the nearest rated interval, for example, if the hourly rate charging is set and the time since the service start is 70 minutes, customers should pay for two hours.
- Minimum service duration can be set. In this case, if, for example, a service is used for 10 minutes only, whereas the minimum duration is set to half an hour, a customer will need to pay for half an hour even if the per-minute charging is enabled. If the service with the same settings is used for 31 minutes, then a customer will need to pay for 31 minutes only.
- As time passes, the system switches from rate to rate automatically and stores the service time used under each rate. Periods, corresponding to different rates, are priced differently.
Data Structure
Service
IOrderServiceItem
— order item that corresponds to the time-based service. It is located in the IOrder.Items
collection together with food items (IOrderCookingItem
).
A pay-per-time service is given as the (IProduct
) product on the menu with the ProductType.Service
type and has the IProduct.RateSchedule
charging parameters (if charging parameters are not set, the service has no time-based rates and can be added to the order and paid as a regular item).
Key properties of the pay-per-time service:
Service
— the product associated with the service defines the availability on the menu, base price (default rate), and so on.Periods
— a list of service intervals representing different rates. When the service is started, the first period will be added to the list. The period time and value will grow until the next rate is enabled, which will add the second period, and so on. Each rate has one period (interval) associated with it: if—according to the rate scale—rates are enabled in turns, the time spent in the first period will increase, then the same will be true for the second period, and then the first period again.IsStarted
— whether or not the service is running at the moment.Price
— base unit price (certain periods can have different rates).TimeLimit
— a time limit. If set, the service will stop automatically when the limit is reached. Even if you stop the service prematurely, the entire service time needs to be paid anyways, in which case, used time is registered and paid under preconfigured periods, whereas, unused time — under the service itself (seeRemainingLimitCost
).RemainingLimitCost
— unused time price. If the limit is not set, 0. When the limit is set, the entire time limit price will be due (the service is not yet started, no ordered time is used). With time, the time limit total value will decrease (until dropped to zero), while the period total value will increase (unused limit time will grow smaller, and used time will become larger).Cost
— overall service value includes amounts accumulated over all periods and the value of unused time.ResultSum
— total service value, including discounts, surcharges, and the VAT.
Service Period
IOrderServiceItemPeriod
— a period a service operates at a particular rate, which includes all time intervals under this rate.
Key properties of the service period:
Service
— product associated with the period rate. Alternatively, it is theProductType.Service
product specified in the service as the default rate or theProductType.Rate
product specified in the rate scale.Price
— price per time unit.ElapsedTime
— overall time the service is used under the particular rate. If the service is started and stopped more than once or rates are switched back and forth, the system would combine all time intervals associated with the rate into one. It would be a precise, not rounded period of time. The system registers the actual time, however, a guest would pay for a rounded time. For example, if the service is charged hourly and the ElapsedTime is 10 minutes only, the period value will correspond to one hour and will not change during the next 50 minutes under this rate.Cost
— overall period value. It is already included in the service value (both overall and total), therefore, there is no need to sum them up. This property is only intended to break the service cost down by rates.
Rate Settings
RateSchedule
— charging mode: by service time or by the time of day.
TimingMode
— charging mode: by service time or by the time of day.Items
— rate scale, list ofRateScheduleItem
items that define time intervals with rates other than the base rate. The time interval (RateScheduleInterval
) is defined by the day of the week and the shift of the interval beginning and the end against the rate scale beginning. Depending on the selected charging mode (TimingMode
), the scale begins together with the day (entire scale is [0;24) hours) or together with the service (entire scale is [0;12] hours). Such time intervals are sure will not overlap. If the list is empty, the base rate is enabled all the time.TimingStep
— measurement unit. The real service time is rounded up to the nearest rate step.MinimumDuration
— minimum service duration or null if the lower limit is not set.
Service Management
AddOrderServiceItem
— adding the service to the order.
StartService
— starting the service.
StopService
— stopping the service. If a guest bill is printed or the order is paid, the service will stop automatically.
Examples
The SamplePlugin included in the SDK shows examples of the service adding, starting, and stopping — [StartService
] and [StopService
] methods in the EditorTester
class:
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);
}