protected string GetSparePartDetailsUrl( OrderLine line ) { if( line != null ) { SparePartPriceKey key = new SparePartPriceKey( line.Manufacturer, line.PartNumber, line.SupplierID ); return UrlManager.GetSparePartDetailsUrl( key.ToUrlString() ); } else { return null; } }
protected string GetStatusDescription( OrderLine order ) { if( order.LastStatusChange != null ) { if( !string.IsNullOrEmpty( order.LastStatusChange.StatusChangeInfo ) ) { return order.LastStatusChange.StatusChangeInfo; } } return null; }
//TODO: Здесь диспозиться как-то объект, из-за этого метод нельзя вызвать 2 раза за сессию public OrderResult SendOrder(OrderLineItemSource[] items, string custOrderNum) { if (!Rights.Contains("3")) { var ex = new Exception("Access Denied"); Logger.WriteError(CurrentIdentityName + ": Access Denied", EventLogerID.BLException, EventLogerCategory.WebServiceError, ex); throw ex; } OrderResult result = null; _getAppLock(new StoreDataContext().Connection.ConnectionString); try { RmsAuto.Acctg.ClientGroup clientGroup = profile.ClientGroup; Logger.WriteInformation(string.Format(LoggerTemplate, "Order lines to process: " + items.Length, DateTime.Now.ToString(TimeFormat), "Enter 'SendOrder' method of web-service"), EventLogerID.AdditionalLogic, EventLogerCategory.WebServiceError, new Object[] { true }); if (items.Length == 0) { var ex = new Exception("Количество строк заказа должно быть > 0"); Logger.WriteError(string.Format(LoggerTemplate, items.Length, DateTime.Now.ToString(TimeFormat), "Error checking number of lines: must be > 0"), EventLogerID.AdditionalLogic, EventLogerCategory.WebServiceError, ex); throw ex; } // Сопоставление сертификата (сертификат 'замаплен' на доменную учетку) и учетки на сайте decimal personalMarkup = profile.PersonalMarkup; //подгружаем "настройки" клиента StoreDataContext DC = new StoreDataContext(); var userSet = DC.spSelUserSetting(profile.UserId).FirstOrDefault(); byte PrcExcessPrice = userSet == null ? (byte)0 : userSet.PrcExcessPrice; //подгружаем список "собственных складов наличия" List<int> ownStores = StoreRefCatalog.RefOwnStores.Items.Select(x => x.SupplierID).ToList(); //TODO: Вынести логику проверки в общий метод для загрузки через Excel List<OrderItemResult> infos = new List<OrderItemResult>(); List<OrderLine> orderLines = new List<OrderLine>(); bool existSuccesItems = false; foreach (var line in items) { //подгружаем инфу о детали SparePartPriceKey key = new SparePartPriceKey(line.Manufacturer, line.PartNumber, line.SupplierID); var part = SparePartsDac.Load(DC, key); //производим количественные проверки, и проверку наличия детали if (part == null) { infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = ItemResultCode.SparePartNotFound.ToTextOrName(), ResultCode = (int)ItemResultCode.SparePartNotFound }); } else if (line.Qty < part.DefaultOrderQty) { infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = string.Format(ItemResultCode.MinOrderQtyError.ToTextOrName(), part.DefaultOrderQty), ResultCode = (int)ItemResultCode.MinOrderQtyError }); } else if (line.Qty % part.DefaultOrderQty != 0) { infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = ItemResultCode.DefaultOrderQtyError.ToTextOrName(), ResultCode = (int)ItemResultCode.DefaultOrderQtyError }); } else if (part.QtyInStock.GetValueOrDefault() > 0 && line.Qty > part.QtyInStock) { infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = string.Format(ItemResultCode.QtyInStockError.ToTextOrName(), part.QtyInStock), ResultCode = (int)ItemResultCode.QtyInStockError }); } else { decimal? priceClientYesterday = null; // "Вчерашная" цена bool isErrorPrice = false; //проверка цены //(т.е. если текущая цена > цена клиента + допустимый % превышения цены, то это факт превышения цены) if (part.GetFinalSalePrice(profile.ClientGroup, profile.PersonalMarkup) > line.UnitPrice + Math.Round(line.UnitPrice * PrcExcessPrice / 100, 2) && //т.е. расчет "вчерашних" цен производится ТОЛЬКО для собственных складов наличия ownStores != null && ownStores.Contains(part.SupplierID)) { using (var dc = new dcCommonDataContext()) { try { //получаем список "вчерашних" и сегодняшних цен фтп для сравнения //если загрузка производится в понедельник, то "вчерашние" цены фтп должны браться по пятнице, субботе и воскресенью string queryTemplate = "exec srvdb4.az.dbo.spGetPricesOnPeriod @Number='{0}', @Brand='{1}', @DateFrom='{2}', @DateTo='{3}', @PriceColumn={4}"; DateTime dateFrom = (DateTime.Now.DayOfWeek == DayOfWeek.Monday) ? DateTime.Now.AddDays(-3) : DateTime.Now.AddDays(-1); DateTime dateTo = DateTime.Now; List<decimal> prices = dc.ExecuteQuery<decimal>( string.Format(queryTemplate, part.PartNumber, part.Manufacturer, dateFrom.ToString("yyyyMMdd"), dateTo.ToString("yyyyMMdd"), (int)profile.ClientGroup)) .ToList<decimal>(); //для каждой из цен производим сравнение с ценой клиента +- 1 копейка (чтобы учесть возможные погрешности при округлении) //TODO: Переписать через LINQ foreach (var price in prices) { decimal pClient = Math.Round(line.UnitPrice, 2); //цена клиента в 'Excel' decimal pFtp = Math.Round(price, 2); //одна из вчерашних цен нашего Ftp if (pClient > 0 && (pClient == pFtp || pClient == (pFtp - 0.01M) || pClient == (pFtp + 0.01M))) { //добавляем допустимый % превышения (доли копеек отбрасываем) priceClientYesterday = pFtp + pFtp * PrcExcessPrice / 100; priceClientYesterday = decimal.Truncate((decimal)priceClientYesterday * 100) / 100; break; } } //если ни одного совпадения не найдено, то позиция отваливается с ошибкой "Несоответствие цены ФТП-прайсу" isErrorPrice = (prices.Count() > 0 && !priceClientYesterday.HasValue); if (prices.Count() == 0) //Если цен не найдено, ошибка isErrorPrice = true; } catch (Exception ex) { Logger.WriteError(@"Error while calculating 'Yesterday' price!", EventLogerID.UnknownError, EventLogerCategory.UnknownCategory, ex); } finally { if (dc.Connection.State == System.Data.ConnectionState.Open) dc.Connection.Close(); } } } if (isErrorPrice) { infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = ItemResultCode.PriceError.ToTextOrName(), ResultCode = (int)ItemResultCode.PriceError }); } else { OrderLine ol = new OrderLine() { AcctgOrderLineID = -line.ItemID, //временный ID пока УС не обработает заказ и не проставит свой ID Manufacturer = part.Manufacturer, PartNumber = part.PartNumber, SupplierID = part.SupplierID, ReferenceID = line.ReferenceID, DeliveryDaysMin = part.DeliveryDaysMin, DeliveryDaysMax = part.DeliveryDaysMax, PartName = part.PartName, PartDescription = part.PartDescription, WeightPhysical = part.WeightPhysical, WeightVolume = part.WeightVolume, UnitPrice = (priceClientYesterday.HasValue ? priceClientYesterday.Value : part.GetFinalSalePrice(clientGroup, personalMarkup)), Qty = line.Qty, StrictlyThisNumber = line.StrictlyThisNumber, VinCheckupData = string.Empty, OrderLineNotes = string.Empty, CurrentStatus = OrderLineStatusUtil.StatusByte("PreOrder") }; orderLines.Add(ol); infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = ItemResultCode.Successs.ToTextOrName(), ResultCode = (int)ItemResultCode.Successs }); existSuccesItems = true; } } } int? orderID = null; if (existSuccesItems) { orderID = OrderBO.CreateOrderForService(profile.UserId, profile.ClientId, "1", orderLines, custOrderNum); } result = new OrderResult() { OrderID = orderID, ItemResults = infos.ToArray() }; if (DC.Connection.State == System.Data.ConnectionState.Open) { DC.Connection.Close(); } _releaseAppLock(); } catch (Exception ex) { if (connection.State == System.Data.ConnectionState.Open) { try { _releaseAppLock(); } catch (Exception ex1) { connection.Close(); Logger.WriteError(string.Format(LoggerTemplate, result.ItemResults.Length, DateTime.Now.ToString(TimeFormat), "Error while release lock"), EventLogerID.AdditionalLogic, EventLogerCategory.WebServiceError, ex1); } } Logger.WriteError(string.Format(LoggerTemplate, "Order lines processed: not defined", DateTime.Now.ToString(TimeFormat), "Exception while executing web-service"), EventLogerID.AdditionalLogic, EventLogerCategory.WebServiceError, ex); } //Записываем сколько на выходе //TODO: возможно это можно переписать через какое-то LINQ var q1 = result.ItemResults.Where(x => x.ResultCode == (int)ItemResultCode.Successs).Count(); var q2 = result.ItemResults.Where(x => x.ResultCode == (int)ItemResultCode.SparePartNotFound).Count(); var q3 = result.ItemResults.Where(x => x.ResultCode == (int)ItemResultCode.QtyInStockError).Count(); var q4 = result.ItemResults.Where(x => x.ResultCode == (int)ItemResultCode.PriceError).Count(); var q5 = result.ItemResults.Where(x => x.ResultCode == (int)ItemResultCode.MinOrderQtyError).Count(); Logger.WriteInformation(string.Format(LoggerTemplate, "OrderID: " + (result.OrderID) + "\rOrder lines processed: " + result.ItemResults.Count() + "\r Success: " + q1 + ",\r SparePartNotFound: " + q2 + ",\r QtyInStockError: " + q3 + ",\r PriceError: " + q4 + ",\r MinOrderQtyError: " + q5, DateTime.Now.ToString(TimeFormat), "Successful exit of 'SendOrder' method"), EventLogerID.AdditionalLogic, EventLogerCategory.WebServiceLogic, new Object[] { true }); return result; }
public static void UpdateOrderLineProcessed(OrderLine orderLine) { UpdateOrderLineProcessed(orderLine.OrderLineID, orderLine.Processed); }
public static OrderLine LoadOrderLineData(string clientId, int orderLineId, bool TrackEnable) { using (var dc = new DCFactory<StoreDataContext>()) { DataLoadOptions options = new DataLoadOptions(); options.LoadWith<OrderLine>(l => l.Order); options.LoadWith<OrderLine>(l => l.OrderLineStatusChanges); options.AssociateWith<OrderLine>(l => l.OrderLineStatusChanges.OrderBy(sc => sc.StatusChangeTime)); dc.DataContext.LoadOptions = options; dc.DataContext.DeferredLoadingEnabled = false; dc.DataContext.ObjectTrackingEnabled = TrackEnable; var OrdLn = dc.DataContext.OrderLines.Where(l => l.OrderLineID == orderLineId && l.Order.ClientID == clientId).ToArray()[0]; if (!TrackEnable) { OrderLine res2 = new OrderLine(); Order o = new Order(); OrderLine res = Serializer.JsonClone<OrderLine>(OrdLn, res2); res.Order = Serializer.JsonClone<Order>(OrdLn.Order, o); return res; } else return OrdLn; //return res; } }
private static void SendOrderLineTrackingAlerts(string clientId, IDictionary<string, EmployeeInfo> managers, ISendOrderLineTrackingAlertsLog log) { using (var dc = new DCFactory<StoreDataContext>()) { DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<OrderLine>(l => l.Order); dlo.LoadWith<OrderLine>(l => l.OrderLineStatusChanges); var profile = ClientProfile.Load(clientId); var clientAlertInfo = dc.DataContext.ClientAlertInfos.Single(a => a.ClientID == clientId); //на всякий случай, для новых пользователей исключить отсылку "старых" оповещений, когда он был офлайн клиентом. if (clientAlertInfo == null) { dc.DataContext.ClientAlertInfos.InsertOnSubmit(new ClientAlertInfo { ClientID = clientId, OrderTrackingLastAlertDate = DateTime.Now }); dc.DataContext.SubmitChanges(); } // deas 23.05.2011 task4130 Ускорение работы со статусами //var stRejected = OrderLineStatusUtil.StatusByte(dc, "Rejected"); var stRejected = OrderLineStatusUtil.StatusByte( "Rejected" ); byte[] selectedStatuses = OrderLineStatusUtil.GetSelectedStatusesOfClient(dc.DataContext, clientId); // ID-шники выбранных этим клиентом статусов //var orderLines = ( from o in dc.Orders // join l in dc.OrderLines on o.OrderID equals l.OrderID // where o.ClientID == clientId // && l.CurrentStatusDate > clientAlertInfo.OrderTrackingLastAlertDate // && l.CurrentStatus != stRejected // && (selectedStatuses.Length > 0 && selectedStatuses.Contains(l.CurrentStatus)) // Для фильтрации по выбранным для оповещения статусам // orderby l.CurrentStatusDate // select l ).ToArray(); var orderLines = new OrderLine[] { }; if (selectedStatuses != null && selectedStatuses.Length > 0) { orderLines = (from o in dc.DataContext.Orders join l in dc.DataContext.OrderLines on o.OrderID equals l.OrderID where o.ClientID == clientId && l.CurrentStatusDate > clientAlertInfo.OrderTrackingLastAlertDate && l.CurrentStatus != stRejected && selectedStatuses.Contains(l.CurrentStatus) // Для фильтрации по выбранным для оповещения статусам orderby l.CurrentStatusDate select l).ToArray(); } else if(selectedStatuses == null) //значит записи в настройках клиента еще нет и тогда отсылаем все статусы (по умолчанию) //if (selectedStatuses != null && selectedStatuses.Length == 0) -> запись в настройках клиента есть, но нет выбранных статусов, тогда ничего не отсылаем { orderLines = (from o in dc.DataContext.Orders join l in dc.DataContext.OrderLines on o.OrderID equals l.OrderID where o.ClientID == clientId && l.CurrentStatusDate > clientAlertInfo.OrderTrackingLastAlertDate && l.CurrentStatus != stRejected orderby l.CurrentStatusDate select l).ToArray(); } if (orderLines.Length != 0) { OrderLineTrackingAlert alert = new OrderLineTrackingAlert(); if (LightBO.IsLight()) { alert = new OrderLineTrackingAlert(profile.InternalFranchName); } var estSupplyDateHint = TextItemsDac.GetTextItem( "Orders.EstSupplyDateHint", "ru-RU" ); alert.EstSupplyDateHint = estSupplyDateHint != null ? estSupplyDateHint.TextItemBody : ""; var blockMailFooter = TextItemsDac.GetTextItem( "OrderLineTrackingAlert.BlockMailFooter", "en-US"/*"ru-RU"*/ ); alert.BlockMailFooter = blockMailFooter != null ? blockMailFooter.TextItemBody.ToString() : ""; alert.NumChange = "0"; // считаем, что "перехода номера" не было. Dictionary<byte, string> dNames = new Dictionary<byte, string>(); foreach (var statusElement in dc.DataContext.OrderLineStatuses) { var status = statusElement.OrderLineStatusID; dNames.Add(status, OrderLineStatusUtil.DisplayName(status)); } alert.OrderLines = orderLines.Select(l => new OrderLineTrackingAlert.OrderLine { OrderDisplayNumber = RmsAuto.Store.Web.OrderTracking.GetOrderDisplayNumber(l.Order), CustOrderNum = l.Order.CustOrderNum, OrderDate = l.Order.OrderDate.ToString("dd.MM.yyyy"), Manufacturer = l.Manufacturer, PartNumber = l.PartNumber, PartName = l.PartName, UnitPrice = l.UnitPrice.ToString("### ### ##0.00"), Qty = l.Qty.ToString(), ReferenceID = l.ReferenceID, Total = l.Total.ToString("### ### ##0.00"), EstSupplyDate = l.EstSupplyDate != null ? l.EstSupplyDate.Value.ToString("dd.MM.yyyy") : "", CurrentStatusDate = l.CurrentStatusDate.Value.ToString("dd.MM.yyyy HH:mm:ss"), CurrentStatusName = dNames[l.CurrentStatus], CurrentStatusDescription = string.Empty,//l.LastStatusChange.StatusChangeInfo, -- закомментированно временно, до тех пор, пока снова не появится "история" по строке заказа ParentOrderLine = l.ParentOrderLine == null ? null : new OrderLineTrackingAlert.OrderLine { Manufacturer = l.ParentOrderLine.Manufacturer, PartNumber = l.ParentOrderLine.PartNumber, PartName = l.ParentOrderLine.PartName, UnitPrice = l.ParentOrderLine.UnitPrice.ToString("### ### ##0.00"), Qty = l.ParentOrderLine.Qty.ToString(), ReferenceID = l.ParentOrderLine.ReferenceID, Total = l.ParentOrderLine.Total.ToString("### ### ##0.00"), EstSupplyDate = l.ParentOrderLine.EstSupplyDate != null ? l.ParentOrderLine.EstSupplyDate.Value.ToString("dd.MM.yyyy") : "" } }).ToArray(); //var stPartNumberTransition = dNames[OrderLineStatusUtil.StatusByte(dc, "PartNumberTransition")]; try { var el = from o in alert.OrderLines where o.ParentOrderLine != null //where o.CurrentStatusName == stPartNumberTransition select o; if (el.Count() > 0) if (el.First() != null) alert.NumChange = "1"; //родительские строки есть! } catch (ApplicationException) { } MailAddress clientEmail = GetOrderLineTrackingEmail(profile.Email, profile.IsLegalWholesale ? profile.ContactPerson : profile.ClientName, log, clientId); MailAddress managerEmail = null; if (managers != null && profile.ManagerId != null) { EmployeeInfo manager; if (managers.TryGetValue(profile.ManagerId, out manager) && manager != null) managerEmail = GetOrderLineTrackingEmail(manager.Email, manager.FullName, log, "manager " + profile.ManagerId); } //создаем аттач Attachment attach = CreateAttachment(alert.OrderLines); //отправляем оповещение if ((clientEmail ?? managerEmail) != null) { /*MailEngine.SendMailWithBcc( clientEmail ?? managerEmail, clientEmail == null ? null : managerEmail, alert );*/ MailEngine.SendMailWithBccAndAttachments( clientEmail ?? managerEmail, clientEmail == null ? null : managerEmail, new Attachment[] { attach }, alert); } //если email не задан или некорректный, то дату последнего оповещения всё равно сдвигаем, //чтобы не заспамить клиента, когда в его профиле будет корректный email. clientAlertInfo.OrderTrackingLastAlertDate = orderLines.Max(l => l.CurrentStatusDate).Value; dc.DataContext.SubmitChanges(); log.LogSuccessfulAlert(clientId); } } }
static OrderResult SendOrder( OrderLineItemSource[] items ) { // Сопоставление сертификата (сертификат 'замаплен' на доменную учетку) и учетки на сайте string acctgId = ServiceAccountDac.GetClientIDByWcfServiceAccount( "RMS-AUTO\\franch01" ); //подгружаем данные о клиенте ClientProfile profile = ClientProfile.Load( acctgId ); RmsAuto.Acctg.ClientGroup clientGroup = profile.ClientGroup; decimal personalMarkup = profile.PersonalMarkup; //Dictionary<int, string> infos = new Dictionary<int, string>(); List<OrderItemResult> infos = new List<OrderItemResult>(); List<OrderLine> orderLines = new List<OrderLine>(); bool existSuccesItems = false; foreach (var line in items) { StoreDataContext DC = new StoreDataContext(); //подгружаем инфу о детали SparePartPriceKey key = new SparePartPriceKey( line.Manufacturer, line.PartNumber, line.SupplierID ); var part = SparePartsDac.Load( DC, key ); if (part == null) { infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = "Запчасть не найдена.", ResultCode = 2 } ); } else if (line.Qty < part.DefaultOrderQty) { infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = string.Format( "Минимальное количество для заказа: {0}.", part.DefaultOrderQty ), ResultCode = 3 } ); } else if (line.Qty % part.DefaultOrderQty != 0) { infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = "Количество должно быть кратным числу деталей в комплекте.", ResultCode = 4 } ); } else if (part.QtyInStock.GetValueOrDefault() > 0 && line.Qty > part.QtyInStock) { infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = string.Format( "Заказанное количество превышает остатки склада, доступно: {0}.", part.QtyInStock ), ResultCode = 5 } ); } else { OrderLine ol = new OrderLine() { AcctgOrderLineID = -line.ItemID, //временный ID пока УС не обработает заказ и не проставит свой ID Manufacturer = part.Manufacturer, PartNumber = part.PartNumber, SupplierID = part.SupplierID, ReferenceID = line.ReferenceID, DeliveryDaysMin = part.DeliveryDaysMin, DeliveryDaysMax = part.DeliveryDaysMax, PartName = part.PartName, PartDescription = part.PartDescription, WeightPhysical = part.WeightPhysical, WeightVolume = part.WeightVolume, UnitPrice = part.GetFinalSalePrice( clientGroup, personalMarkup ), Qty = line.Qty, StrictlyThisNumber = line.StrictlyThisNumber, VinCheckupData = string.Empty, OrderLineNotes = string.Empty, CurrentStatus = OrderLineStatusUtil.StatusByte( "PreOrder" ) }; orderLines.Add( ol ); infos.Add( new OrderItemResult() { ItemID = line.ItemID, ResultInfo = "Позиция принята успешно.", ResultCode = 1 } ); existSuccesItems = true; } } ////если нет ни одной ошибки, то размещаем заказ //int? orderID = null; //if (infos.Count == 0) //{ int? orderID = null; if (existSuccesItems) { orderID = OrderBO.CreateOrderForService(profile.UserId, profile.ClientId, "1", orderLines, "123" ); } //} OrderResult result = new OrderResult() { OrderID = orderID, ItemResults = infos.ToArray() }; return result; }
public Boolean IsParentForPartNumberTransition(Int32 orderLineID, OrderLine childOrderLine) { using (var dc = new DCFactory<StoreDataContext>()) { //List<SuperTypeTurn> list = (from db in entity.SuperTypeTurn.Include("TypeTurn").Include("TypeTurn.Turn") // from typeTurn in db.TypeTurn // from turn in typeTurn.Turn // orderby db.SortOrder, typeTurn.SortOrder, turn.SortOrder // select db).ToList(); //var el = from o in dc.OrderLines // where o.OrderLineID == orderLineID // select o; //IQueryable<EntitySet<OrderLine>> childOrderLines = from o in dc.OrderLines // select o.ChildOrderLines; // Нашли все дочерние //var childOrderLines = from o in dc.OrderLines // where o.ParentOrderLine.OrderLineID == orderLineID // select o; // deas 23.05.2011 task4130 Ускорение работы со статусами //var stPartNumberTransition = OrderLineStatusUtil.StatusByte(dc, "PartNumberTransition"); var stPartNumberTransition = OrderLineStatusUtil.StatusByte("PartNumberTransition"); //var el = from o in childOrderLines // where o.CurrentStatus == stPartNumberTransition // select o; if (childOrderLine.CurrentStatus == stPartNumberTransition) return true; else return false; } }