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); }
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); }