public PriceRule.Result Apply <T> (PriceRule priceRule, Operation <T> operation) where T : OperationDetail
        {
            if (error)
            {
                return(PriceRule.Result.Success);
            }

            string stringValue;

            switch (Type)
            {
            case PriceRule.ActionType.Stop:
                BusinessDomain.OnPriceRuleMessage(new PriceRuleMessageEventArgs(values [0].ToString(), ErrorSeverity.Warning));
                return(PriceRule.Result.StopOperation);

            case PriceRule.ActionType.Exit:
                BusinessDomain.OnPriceRuleMessage(new PriceRuleMessageEventArgs(values [0].ToString(), ErrorSeverity.Warning));
                return(PriceRule.Result.StopRules);

            case PriceRule.ActionType.Message:
                BusinessDomain.OnPriceRuleMessage(new PriceRuleMessageEventArgs(values [0].ToString(), ErrorSeverity.Information));
                break;

            case PriceRule.ActionType.Email:
                BusinessDomain.WorkflowManager.SendEmailAsync(operation, values [0].ToString(), values [1].ToString());
                break;

            case PriceRule.ActionType.ServiceCharge:
                List <T> detailsWithService         = new List <T> ();
                const PriceRule.AppliedActions mask = PriceRule.AppliedActions.ServiceChargeItem;
                detailsWithService.AddRange(operation.Details.Where(d =>
                                                                    priceRule.CheckApplicableToDetail(operation.Details, d, mask)));
                detailsWithService.AddRange(operation.AdditionalDetails.Where(d =>
                                                                              priceRule.CheckApplicableToDetail(operation.AdditionalDetails, d, mask)));

                Item       item           = (Item)values [0];
                PriceGroup priceGroup     = operation.GetPriceGroup();
                double     operationTotal = detailsWithService.Sum(detail => detail.Total);
                double     serviceChargeAmount;
                if (values [1] is double)
                {
                    serviceChargeAmount = operationTotal * (double)values [1] / 100;
                }
                else
                {
                    string expression = (string)values [1];
                    try {
                        serviceChargeAmount = RPNCalculator.EvaluateExpression(expression.Replace(DOCUMENT_SUM, operationTotal.ToString(CultureInfo.InvariantCulture)));
                    } catch (Exception ex) {
                        ErrorHandling.LogException(ex);
                        serviceChargeAmount = 0;
                    }
                }

                if (serviceChargeAmount > 0)
                {
                    item.SetPriceGroupPrice(priceGroup, serviceChargeAmount);
                    string note   = operation.Note;
                    T      detail = operation.AddNewDetail();
                    if (detail.ItemEvaluate(item, priceGroup, true))
                    {
                        detail.Note = note;
                        detail.AppliedPriceRules = PriceRule.AppliedActions.ServiceChargeItem;
                    }
                    else
                    {
                        operation.RemoveDetail(operation.Details.Count - 1, false);
                    }
                }
                break;

            case PriceRule.ActionType.AddGlobalGood:
                foreach (T detail in GetDetailsForPromotionalItems <T> (formula))
                {
                    if (operation.OperationType == OperationType.RestaurantOrder)
                    {
                        detail.LotId = Int32.MinValue;
                    }
                    operation.Details.Add(detail);
                }
                break;

            case PriceRule.ActionType.Payment:
                Payment payment = new Payment(operation, (int)BasePaymentType.Coupon, PaymentMode.Paid);
                stringValue = PriceRule.GetStringValue(formula, ' ');
                try {
                    payment.Quantity = RPNCalculator.EvaluateExpression(stringValue
                                                                        .Replace(DOCUMENT_SUM, operation.TotalPlusVAT.ToString(CultureInfo.InvariantCulture)));
                    payment.CommitAdvance();
                } catch (Exception ex) {
                    ErrorHandling.LogException(ex);
                }
                break;

            case PriceRule.ActionType.AskAdvancePayment:
                stringValue = PriceRule.GetStringValue(formula, ' ');
                try {
                    BusinessDomain.OnPriceRulePriceRuleAskForAdvance(new PriceRuleAskAdvanceEventArgs(operation.PartnerId,
                                                                                                      RPNCalculator.EvaluateExpression(stringValue.Replace(DOCUMENT_SUM, operation.TotalPlusVAT.ToString(CultureInfo.InvariantCulture)))));
                } catch (Exception ex) {
                    ErrorHandling.LogException(ex);
                }
                break;
            }

            return(PriceRule.Result.Success);
        }