private void OnBeforeOrderBill(IOrder order, [CanBeNull] IViewManager viewManager)
        {
            PluginContext.Log.Info("On before order bill subscription.");
            viewManager?.ChangeProgressBarMessage("Waiting for confirmation...");

            if (MessageBox.Show($"Allow bill operation of the order: #{order.Number}, guests {order.Guests.Count}, sum: {order.ResultSum}?{Environment.NewLine}", "", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes)
                != MessageBoxResult.Yes)
            {
                PluginContext.Log.Info($"Bill operation of order '{order.Id}' will be canceled.");
                throw new OperationCanceledException();
            }
        }
        // Implementation of collect data method. Executes when plug-in payment item is going to be added to the order.
        public void CollectData(Guid orderId, Guid paymentTypeId, [NotNull] IUser cashier, IReceiptPrinter printer,
                                IViewManager viewManager, IPaymentDataContext context)
        {
            PluginContext.Log.InfoFormat("Collect data for order ({0})", orderId);

            // Show dialog window with magnet card slide listener and number input keyboard.
            var defaultRoomNumber = 42;
            var input             = viewManager.ShowInputDialog("Enter room number or slide card", InputDialogTypes.Card | InputDialogTypes.Number, defaultRoomNumber);

            //Cancel button pressed, cancel operation silently.
            if (input == null)
            {
                throw new PaymentActionCancelledException();
            }

            var data = string.Empty;

            // If number was typed input result is INumberInputResult
            if (input is NumberInputDialogResult roomNum)
            {
                data = roomNum.Number.ToString();
            }

            // If card was slided input result is ICardInputResult
            var card = input as CardInputDialogResult;

            if (card != null)
            {
                data = card.FullCardTrack;
            }

            //Required data is not collected, cancel operation with message box.
            if (string.IsNullOrEmpty(data))
            {
                throw new PaymentActionFailedException("Fail to collect data. This text will be shown in dialog window and storning operation will be aborted.");
            }

            // Changing the text displayed on progress bar
            viewManager.ChangeProgressBarMessage("Long action. Information for user");
            Thread.Sleep(5000);

            PluginContext.Log.InfoFormat("Data  {0}, Order id  {1}", data, orderId);

            var d = new CollectedDataDemoClass {
                Data = data, IsCard = card != null
            };

            context.SetRollbackData(d);
        }
        // Implementation of payment method. Executes when order contains plug-in payment item type and order payment process begins.
        public void Pay(decimal sum, [NotNull] IOrder order, Guid paymentTypeId, Guid transactionId, [NotNull] IPointOfSale pointOfSale, [NotNull] IUser cashier,
                        [NotNull] IOperationService operations, IReceiptPrinter printer, IViewManager viewManager, IPaymentDataContext context)
        {
            PluginContext.Log.InfoFormat("Pay {0}", sum);

            var data = context.GetRollbackData <CollectedDataDemoClass>();

            // Changing the text displayed on progress bar on pay operation
            viewManager.ChangeProgressBarMessage("Printing slip");

            // Slip to print. Slip consists of XElement children from Resto.CashServer.Agent.Print.Tags.Xml (Resto.Framework.dll)
            var slip = new ReceiptSlip
            {
                Doc =
                    new XElement(Tags.Doc,
                                 new XElement(Tags.Pair,
                                              new XAttribute(Data.Cheques.Attributes.Left, "Payment System"),
                                              new XAttribute(Data.Cheques.Attributes.Right, PaymentSystemKey),
                                              new XAttribute(Data.Cheques.Attributes.Fit, Data.Cheques.Attributes.Right)),
                                 new XElement(Tags.Pair,
                                              new XAttribute(Data.Cheques.Attributes.Left, "Transaction ID"),
                                              new XAttribute(Data.Cheques.Attributes.Right, transactionId.ToString()),
                                              new XAttribute(Data.Cheques.Attributes.Fit, Data.Cheques.Attributes.Right)),
                                 new XElement(Tags.Pair,
                                              new XAttribute(Data.Cheques.Attributes.Left, "Data"),
                                              new XAttribute(Data.Cheques.Attributes.Right, data != null ? data.Data : "unknown"),
                                              new XAttribute(Data.Cheques.Attributes.Fit, Data.Cheques.Attributes.Right)),
                                 new XElement(Tags.Pair,
                                              new XAttribute(Data.Cheques.Attributes.Left, "was card"),
                                              new XAttribute(Data.Cheques.Attributes.Right, data != null && data.IsCard ? "YES" : "NO"),
                                              new XAttribute(Data.Cheques.Attributes.Fit, Data.Cheques.Attributes.Right)),
                                 new XElement(Tags.Pair,
                                              new XAttribute(Data.Cheques.Attributes.Left, "Order #"),
                                              new XAttribute(Data.Cheques.Attributes.Right, order.Number.ToString()),
                                              new XAttribute(Data.Cheques.Attributes.Fit, Data.Cheques.Attributes.Right)),
                                 new XElement(Tags.Pair,
                                              new XAttribute(Data.Cheques.Attributes.Left, "Full sum"),
                                              new XAttribute(Data.Cheques.Attributes.Right, order.FullSum.ToString()),
                                              new XAttribute(Data.Cheques.Attributes.Fit, Data.Cheques.Attributes.Right)),
                                 new XElement(Tags.Pair,
                                              new XAttribute(Data.Cheques.Attributes.Left, "Sum to pay"),
                                              new XAttribute(Data.Cheques.Attributes.Right, order.ResultSum.ToString()),
                                              new XAttribute(Data.Cheques.Attributes.Fit, Data.Cheques.Attributes.Right)),
                                 new XElement(Tags.Pair,
                                              new XAttribute(Data.Cheques.Attributes.Left, "Sum to process"),
                                              new XAttribute(Data.Cheques.Attributes.Right, sum.ToString()),
                                              new XAttribute(Data.Cheques.Attributes.Fit, Data.Cheques.Attributes.Right)))
            };

            printer.Print(slip);
            context.SetInfoForReports(data?.Data, "Test Card Type");

            var donationType = operations.GetDonationTypesCompatibleWith(order).FirstOrDefault(dt => dt.PaymentTypes.Any(pt => pt.Kind == PaymentTypeKind.External));

            if (donationType != null)
            {
                var paymentType    = donationType.PaymentTypes.First(x => x.Kind == PaymentTypeKind.External && x.Name == "SampleApiPayment");
                var additionalData = new ExternalPaymentItemAdditionalData {
                    CustomData = Serializer.Serialize(new PaymentAdditionalData {
                        SilentPay = true
                    })
                };
                var credentials = operations.GetCredentials();

                operations.AddDonation(credentials, order, donationType, paymentType, additionalData, false, order.ResultSum / 2);
            }
        }