Exemple #1
0
        public object Clone()
        {
            PriceRule priceRule = new PriceRule {
                Id = Id, Name = Name, Formula = Formula, Enabled = Enabled, Priority = Priority
            };

            foreach (PriceRuleCondition newCondition in conditions.Select(c => new PriceRuleCondition(c.Type, c.Formula)
            {
                IsActive = c.IsActive
            }.SetIsException(c.IsException)))
            {
                priceRule.conditions.Add(newCondition);
            }

            foreach (PriceRuleAction newAction in actions.Select(a => a.Clone()))
            {
                priceRule.actions.Add(newAction);
            }

            foreach (OperationType operationType in operations)
            {
                priceRule.operations.Add(operationType);
            }

            return(priceRule);
        }
        private static List <T> GetDetailsForPromotionalItems <T> (string actionString) where T : OperationDetail
        {
            string itemsToPromote = PriceRule.GetStringValue(actionString, ' ');

            if (itemsToPromote == null)
            {
                return(null);
            }

            List <T> details = new List <T> ();

            foreach (string itemString in itemsToPromote.Split('|'))
            {
                string [] itemData = itemString.Split(';');
                if (itemData.Length != 3)
                {
                    continue;
                }

                long itemId;
                if (!long.TryParse(itemData [0], out itemId))
                {
                    continue;
                }

                double quantity;
                if (!Double.TryParse(itemData [1], NumberStyles.Any, CultureInfo.InvariantCulture, out quantity))
                {
                    continue;
                }

                double price;
                if (!Double.TryParse(itemData [2], NumberStyles.Any, CultureInfo.InvariantCulture, out price))
                {
                    continue;
                }

                Item item = Item.Cache.GetById(itemId);
                if (item == null)
                {
                    continue;
                }

                T detail = (T)Activator.CreateInstance(typeof(T));
                detail.AppliedPriceRules = PriceRule.AppliedActions.PromotionalItem;
                if (!detail.ItemEvaluate(item, PriceGroup.RegularPrice))
                {
                    continue;
                }

                detail.Quantity = quantity;
                detail.OriginalPriceOutEvaluate(price);
                details.Add(detail);
            }

            return(details);
        }
        public bool CheckApplicableToDetail <T> (IList <T> operationDetails, OperationDetail operationDetail) where T : OperationDetail
        {
            if (error)
            {
                return(false);
            }

            bool ret;

            switch (type)
            {
            case PriceRule.ConditionType.Good:
                ret = operationDetail.ItemId == Convert.ToInt64(values [0]);
                break;

            case PriceRule.ConditionType.GoodGroup:
                ItemsGroup itemsGroup = ItemsGroup.Cache.GetById(operationDetail.ItemGroupId);

                string groupCode = null;
                long?  intValue  = PriceRule.GetLongValue(formula);
                if (intValue != null)
                {
                    ItemsGroup byId = ItemsGroup.Cache.GetById(intValue.Value);
                    if (byId != null)
                    {
                        groupCode = byId.Code;
                    }
                }

                if (groupCode == null)
                {
                    groupCode = PriceRule.GetStringValue(formula);
                }

                ret = itemsGroup.Code.StartsWith(groupCode);
                break;

            case PriceRule.ConditionType.GoodQttySum:
                double from;
                double to;
                GetConditionNumericInterval(formula, out from, out to);
                double quantity = operationDetails
                                  .Where(detail => detail.ItemId == operationDetail.ItemId)
                                  .Select(detail => detail.Quantity)
                                  .Sum();
                ret = from <= quantity && quantity <= to;
                break;

            default:
                return(true);
            }

            return(ret != IsException);
        }
        private List <BasePaymentType> GetConditionPaymentTypes()
        {
            List <BasePaymentType> ret = new List <BasePaymentType> ();
            string mask = PriceRule.GetStringValue(Formula);

            for (int i = 0; i < mask.Length && i < (int)BasePaymentType.Advance; i++)
            {
                if (mask [i] == '1')
                {
                    ret.Add((BasePaymentType)i + 1);
                }
            }

            return(ret);
        }
        private static string [] GetPriceExpressionParts(string actionString, out PriceGroup priceGroup)
        {
            priceGroup = PriceGroup.TradePrice;
            string priceExpression = PriceRule.GetStringValue(actionString);

            if (priceExpression == null)
            {
                return(null);
            }

            string [] parts = priceExpression.Split(' ');
            if (parts.Length > 1)
            {
                // price group expression
                string priceGroupAlias = parts [0];
                priceGroup = priceGroupAliases.Where(pair => pair.Value == priceGroupAlias).Select(pair => pair.Key).FirstOrDefault();
            }

            return(parts);
        }
        private List <DayOfWeek> GetRuleWeekDays()
        {
            string           weekBitMask  = PriceRule.GetStringValue(Formula);
            List <DayOfWeek> ruleWeekDays = new List <DayOfWeek> (weekBitMask.Length);

            for (int i = 0; i < weekBitMask.Length; i++)
            {
                if (weekBitMask [i] == '1')
                {
                    // Sunday is 0 instead of 7, the remaining days start from 1
                    if (i == weekBitMask.Length - 1)
                    {
                        ruleWeekDays.Add(0);
                    }
                    else
                    {
                        ruleWeekDays.Add((DayOfWeek)(i + 1));
                    }
                }
            }

            return(ruleWeekDays);
        }
        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);
        }
        private void SetFormula(string value)
        {
            if (formula == value)
            {
                return;
            }

            formula = value;
            values  = null;
            string stringValue;

            switch (Type)
            {
            case PriceRule.ActionType.Stop:
            case PriceRule.ActionType.Exit:
            case PriceRule.ActionType.Message:
                values = new object [] { PriceRule.GetStringValue(formula, ' ') };
                break;

            case PriceRule.ActionType.Email:
                stringValue = PriceRule.GetStringValue(formula, ' ');
                if (stringValue == null)
                {
                    break;
                }

                int lastIndexOf = stringValue.LastIndexOf('|');
                if (lastIndexOf < 0)
                {
                    break;
                }

                values = new object [] { stringValue.Substring(lastIndexOf + 1), stringValue.Substring(0, lastIndexOf) };
                break;

            case PriceRule.ActionType.AddGood:
            case PriceRule.ActionType.AddGlobalGood:
                List <SaleDetail> details = GetDetailsForPromotionalItems <SaleDetail> (formula);
                if (details != null)
                {
                    values = details.Cast <object> ().ToArray();
                }
                break;

            case PriceRule.ActionType.Price:
                PriceGroup priceGroup;
                string []  priceParts = GetPriceExpressionParts(formula, out priceGroup);
                if (priceParts == null || priceParts.Length == 0)
                {
                    break;
                }

                double price;
                if (priceParts.Length > 1)
                {
                    OperatorType operatorType;
                    switch (priceParts [1].ToLowerInvariant())
                    {
                    case "+":
                    case "plus":
                        operatorType = OperatorType.Plus;
                        break;

                    case "-":
                    case "minus":
                        operatorType = OperatorType.Minus;
                        break;

                    case "*":
                        operatorType = OperatorType.Multiply;
                        break;

                    case "/":
                        operatorType = OperatorType.Divide;
                        break;

                    default:
                        operatorType = OperatorType.Unknown;
                        break;
                    }
                    if (operatorType == OperatorType.Unknown)
                    {
                        break;
                    }

                    if (Double.TryParse(priceParts [2], NumberStyles.Any, CultureInfo.InvariantCulture, out price))
                    {
                        values = new object [] { priceGroup, operatorType, price }
                    }
                    ;
                }
                else
                if (Double.TryParse(priceParts [0], NumberStyles.Any, CultureInfo.InvariantCulture, out price))
                {
                    values = new object [] { price }
                }
                ;
                break;

            case PriceRule.ActionType.Discount:
                values = new object [] { PriceRule.GetDoubleValue(formula) };
                break;

            case PriceRule.ActionType.ServiceCharge:
                string [] itemWithPercent = formula.Split(';');
                if (itemWithPercent.Length < 2)
                {
                    break;
                }

                long?itemId = PriceRule.GetLongValue(itemWithPercent [0]);
                if (itemId == null)
                {
                    break;
                }

                Item item = Item.Cache.GetById(itemId.Value);
                if (item == null)
                {
                    break;
                }

                string s = PriceRule.GetStringValue(itemWithPercent [1]);
                if (s == null)
                {
                    break;
                }

                double result;
                values = new [] { item,
                                  Double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out result) ? (object)result : s };
                break;

            case PriceRule.ActionType.Payment:
            case PriceRule.ActionType.AskAdvancePayment:
                stringValue = PriceRule.GetStringValue(formula, ' ');
                if (stringValue == null)
                {
                    break;
                }

                try {
                    List <Token> tokens = RPNCalculator.ParseTokens(stringValue);
                    if (tokens.Count > 0)
                    {
                        values = new object [] { ((Operand)tokens [0]).Value }
                    }
                    ;
                } catch (Exception ex) {
                    ErrorHandling.LogException(ex);
                }
                break;
            }

            error = values == null || values.All(v => v == null);
        }
Exemple #9
0
        public static bool ApplyBeforeOperationSaved <T> (Operation <T> operation,
                                                          ConfirmationToApply <T> confirmationToApply = null,
                                                          bool operationComplete = true,
                                                          IEnumerable <PriceRule> allPriceRules = null) where T : OperationDetail
        {
            if (allPriceRules == null)
            {
                allPriceRules = GetAll();
            }

            IDictionary <PriceRule, IList <T> > rulesToApply = new Dictionary <PriceRule, IList <T> > ();

            foreach (PriceRule priceRule in allPriceRules.Where(p => p.actions.All(a =>
                                                                                   a.Type != ActionType.Email &&
                                                                                   a.Type != ActionType.Payment &&
                                                                                   a.Type != ActionType.AskAdvancePayment &&
                                                                                   a.Type != ActionType.ServiceCharge) &&
                                                                p.CheckApplicableToOperation(operation)))
            {
                if (priceRule.IsGlobal)
                {
                    if (operationComplete)
                    {
                        rulesToApply.Add(priceRule, null);
                    }
                }
                else if (operationComplete == priceRule.DependsOnDocumentSum())
                {
                    priceRule.CheckApplicableDetails(operation.Details, ref rulesToApply);
                    priceRule.CheckApplicableDetails(operation.AdditionalDetails, ref rulesToApply);
                }
            }

            List <PriceRule> selectedRulesToApply;

            if (BusinessDomain.AppConfiguration.ConfirmPriceRules &&
                confirmationToApply != null &&
                rulesToApply.Any(r => r.Key.actions.All(a => a.Type != ActionType.AddGlobalGood) && r.Value != null && r.Value.Count > 0))
            {
                selectedRulesToApply = confirmationToApply(rulesToApply.Keys, operation);
            }
            else
            {
                selectedRulesToApply = new List <PriceRule> (rulesToApply.Keys);
            }

            if (selectedRulesToApply.Count == 0)
            {
                return(true);
            }

            foreach (KeyValuePair <PriceRule, IList <T> > ruleToApply in rulesToApply)
            {
                PriceRule priceRule = ruleToApply.Key;
                if (!selectedRulesToApply.Contains(priceRule))
                {
                    continue;
                }

                if (priceRule.IsGlobal)
                {
                    Result result = priceRule.Apply(operation);
                    if (result == Result.StopOperation)
                    {
                        return(false);
                    }

                    if (result == Result.StopRules)
                    {
                        break;
                    }
                }
                else
                {
                    foreach (T detail in ruleToApply.Value)
                    {
                        priceRule.Apply(detail, operation);
                    }
                }
            }

            return(true);
        }
        private void SetFormula(string value)
        {
            if (formula == value)
            {
                return;
            }

            formula = value;
            values  = null;
            switch (type)
            {
            case PriceRule.ConditionType.Partner:
            case PriceRule.ConditionType.Object:
            case PriceRule.ConditionType.User:
            case PriceRule.ConditionType.Good:
            case PriceRule.ConditionType.ContainsGood:
                values = new object [] { PriceRule.GetLongValue(formula) };
                break;

            case PriceRule.ConditionType.PartnerGroup:
            case PriceRule.ConditionType.ObjectGroup:
            case PriceRule.ConditionType.UserGroup:
            case PriceRule.ConditionType.GoodGroup:
            case PriceRule.ConditionType.ContainsGGroup:
                values = new object [] { PriceRule.GetStringValue(formula) };
                break;

            case PriceRule.ConditionType.Time:
            case PriceRule.ConditionType.Date:
                DateTime dateTimeFrom;
                DateTime dateTimeTo;
                GetConditionDateTimeInterval(formula, out dateTimeFrom, out dateTimeTo);
                values = new object [] { dateTimeFrom, dateTimeTo };
                break;

            case PriceRule.ConditionType.DocumentSum:
            case PriceRule.ConditionType.TurnoverSum:
            case PriceRule.ConditionType.GoodQttySum:
            case PriceRule.ConditionType.PaymentSum:
            case PriceRule.ConditionType.UnpaidDocumentsSum:
                double from;
                double to;
                GetConditionNumericInterval(formula, out from, out to);
                values = new [] { from.IsEqualTo(Double.MinValue) ? (object)null : from, to.IsEqualTo(Double.MaxValue) ? (object)null : to };
                break;

            case PriceRule.ConditionType.Weekdays:
                values = new object [] { GetRuleWeekDays() };
                break;

            case PriceRule.ConditionType.PaymentTypeUsed:
                values = new object [] { GetConditionPaymentTypes() };
                break;

            case PriceRule.ConditionType.DatabaseUpdated:
                values = new object [] { 30 };
                break;
            }

            error = values == null || values.All(v => v == null);
        }
        public bool CheckApplicableToOperation <T> (Operation <T> operation) where T : OperationDetail
        {
            if (error)
            {
                return(false);
            }

            DateTime dateFrom;
            DateTime dateTo;
            double   @from;
            double   to;
            bool     ret;
            string   groupCode = null;
            long?    intValue;

            switch (type)
            {
            case PriceRule.ConditionType.Partner:
                ret = operation.PartnerId == Convert.ToInt64(values [0]);
                break;

            case PriceRule.ConditionType.PartnerGroup:
                intValue = PriceRule.GetLongValue(formula);
                if (intValue != null)
                {
                    PartnersGroup byId = PartnersGroup.Cache.GetById(intValue.Value);
                    if (byId != null)
                    {
                        groupCode = byId.Code;
                    }
                }

                if (groupCode == null)
                {
                    groupCode = PriceRule.GetStringValue(formula);
                }

                Partner partner = Partner.Cache.GetById(operation.PartnerId);
                ret = PartnersGroup.Cache.GetById(partner.GroupId).Code.StartsWith(groupCode);
                break;

            case PriceRule.ConditionType.Object:
                ret = operation.LocationId == Convert.ToInt64(values [0]);
                break;

            case PriceRule.ConditionType.ObjectGroup:
                intValue = PriceRule.GetLongValue(formula);
                if (intValue != null)
                {
                    LocationsGroup byId = LocationsGroup.Cache.GetById(intValue.Value);
                    if (byId != null)
                    {
                        groupCode = byId.Code;
                    }
                }

                if (groupCode == null)
                {
                    groupCode = PriceRule.GetStringValue(formula);
                }

                Location location = Location.Cache.GetById(operation.LocationId);
                ret = LocationsGroup.Cache.GetById(location.GroupId).Code.StartsWith(groupCode);
                break;

            case PriceRule.ConditionType.User:
                ret = operation.UserId == Convert.ToInt64(values [0]);
                break;

            case PriceRule.ConditionType.UserGroup:
                intValue = PriceRule.GetLongValue(formula);
                if (intValue != null)
                {
                    UsersGroup byId = UsersGroup.Cache.GetById(intValue.Value);
                    if (byId != null)
                    {
                        groupCode = byId.Code;
                    }
                }

                if (groupCode == null)
                {
                    groupCode = PriceRule.GetStringValue(formula);
                }

                User user = User.Cache.GetById(operation.UserId);
                ret = UsersGroup.Cache.GetById(user.GroupId).Code.StartsWith(groupCode);
                break;

            case PriceRule.ConditionType.Time:
                GetConditionDateTimeInterval(formula, out dateFrom, out dateTo);
                DateTime now = BusinessDomain.Now;
                if (dateFrom.TimeOfDay < dateTo.TimeOfDay)
                {
                    ret = dateFrom.TimeOfDay <= now.TimeOfDay && now.TimeOfDay <= dateTo.TimeOfDay;
                }
                else
                {
                    ret = dateFrom.TimeOfDay <= now.TimeOfDay || now.TimeOfDay <= dateTo.TimeOfDay;
                }
                break;

            case PriceRule.ConditionType.Date:
                GetConditionDateTimeInterval(formula, out dateFrom, out dateTo);
                ret = dateFrom <= operation.Date && operation.Date <= dateTo;
                break;

            case PriceRule.ConditionType.DocumentSum:
                GetConditionNumericInterval(formula, out from, out to);
                ret = from <= operation.Total && operation.Total <= to;
                break;

            case PriceRule.ConditionType.TurnoverSum:
                GetConditionNumericInterval(formula, out from, out to);
                double turnover = Partner.GetTurnover(operation.PartnerId);
                ret = from <= turnover && turnover <= to;
                break;

            case PriceRule.ConditionType.PaymentSum:
                GetConditionNumericInterval(formula, out from, out to);
                double debt = Partner.GetDebt(operation.PartnerId);
                ret = from <= debt && debt <= to;
                break;

            case PriceRule.ConditionType.Weekdays:
                List <DayOfWeek> ruleWeekDays = GetRuleWeekDays();
                ret = ruleWeekDays.Contains(operation.Date.DayOfWeek);
                break;

            case PriceRule.ConditionType.UnpaidDocumentsSum:
                GetConditionNumericInterval(formula, out from, out to);
                double sum = Partner.GetUnpaidAmountWithExpiredDueDate(operation.PartnerId, operation.Date);
                ret = from <= sum && sum <= to;
                break;

            case PriceRule.ConditionType.ContainsGood:
                intValue = Convert.ToInt64(values [0]);
                ret      = operation.Details.Any(d => d.ItemId == intValue) ||
                           operation.AdditionalDetails.Any(d => d.ItemId == intValue);
                break;

            case PriceRule.ConditionType.GoodGroup:
            case PriceRule.ConditionType.ContainsGGroup:
                Dictionary <long, string> codes = new Dictionary <long, string> ();

                foreach (T detail in operation.Details)
                {
                    AddGroupCode(codes, detail.ItemGroupId);
                }

                foreach (T additionalDetail in operation.AdditionalDetails)
                {
                    AddGroupCode(codes, additionalDetail.ItemGroupId);
                }

                intValue = PriceRule.GetLongValue(formula);
                if (intValue != null)
                {
                    ItemsGroup byId = ItemsGroup.Cache.GetById(intValue.Value);
                    if (byId != null)
                    {
                        groupCode = byId.Code;
                    }
                }

                if (groupCode == null)
                {
                    groupCode = PriceRule.GetStringValue(formula);
                }

                ret = codes.Values.Any(c => c.StartsWith(groupCode));
                break;

            case PriceRule.ConditionType.PaymentTypeUsed:
                List <BasePaymentType> paymentTypes = GetConditionPaymentTypes();
                ret = operation.Payments.Any(payment => paymentTypes.Contains(payment.Type.BaseType));
                break;

            case PriceRule.ConditionType.DatabaseUpdated:
                ret = BusinessDomain.GetDatabaseLastUpdate().AddMinutes(30) > DateTime.Now;
                break;

            default:
                return(true);
            }

            return(ret != IsException);
        }