private void ListenForQueueMessagesInTask() { while (_keepQueueListening) { try { System.Threading.Thread.Sleep(queueListenerSleepTimeMs); ConfirmationFile confirmation = GetFileFromQueue(); if (confirmation != null) { try { _log.WriteInformationLog(string.Format("Pulling confirmation from queue using message ({0})", confirmation.MessageId)); ProcessIncomingConfirmation(confirmation); //Try to save the confirmation 5 times. Several threads are modifying the order history table, so there are occasional concurrency errors. KeithLink.Svc.Impl.Helpers.Retry.Do(() => _conversionLogic.SaveConfirmationAsOrderHistory(confirmation), TimeSpan.FromSeconds(1), 5); } catch (Exception e) { _log.WriteErrorLog("Error processing confirmation in Queue service", e); KeithLink.Common.Impl.Email.ExceptionEmail.Send(e, subject: "Exception processing Confirmation in Queue Service"); confirmation.ErrorMessage = e.Message; confirmation.ErrorStack = e.StackTrace; PublishToQueue(confirmation, ConfirmationQueueLocation.Error); } } } catch (Exception ex) { _log.WriteErrorLog("Error Moving Confirmations To Commerce Server", ex); } } }
private string SetCsHeaderInfo(ConfirmationFile confirmation, PurchaseOrder po, LineItem[] lineItems) { string trimmedConfirmationStatus = confirmation.Header.ConfirmationStatus.Trim().ToUpper(); if (trimmedConfirmationStatus == Constants.CONFIRMATION_HEADER_CONFIRMED_CODE) // if confirmation status is blank, then look for exceptions across all line items, not just those in the change order { string origOrderNumber = (string)po[Constants.CS_PURCHASE_ORDER_ORIGINAL_ORDER_NUMBER]; string currOrderNumber = po.TrackingNumber; bool isChangeOrder = origOrderNumber != currOrderNumber; SetCsPoStatusFromLineItems(po, lineItems, isChangeOrder); } else if (trimmedConfirmationStatus.Equals(Constants.CONFIRMATION_HEADER_IN_PROCESS_CODE)) { po.Status = Constants.CONFIRMATION_HEADER_IN_PROCESS_STATUS; } else if (trimmedConfirmationStatus.Equals(Constants.CONFIRMATION_HEADER_INVOICED_CODE)) { po.Status = Constants.CONFIRMATION_HEADER_INVOICED_STATUS; } else if (trimmedConfirmationStatus.Equals(Constants.CONFIRMATION_HEADER_DELETED_CODE)) { po.Status = Constants.CONFIRMATION_HEADER_DELETED_STATUS; } else if (trimmedConfirmationStatus.Equals(Constants.CONFIRMATION_HEADER_REJECTED_CODE)) { po.Status = Constants.CONFIRMATION_HEADER_REJECTED_STATUS; } po[Constants.CS_PURCHASE_ORDER_MASTER_NUMBER] = confirmation.Header.InvoiceNumber; // read this from the confirmation file return(trimmedConfirmationStatus); }
private void SubscriptionQueue_MessageReceived(object sender, RabbitMQ.Client.Events.BasicDeliverEventArgs args) { RabbitMQ.Client.Events.EventingBasicConsumer consumer = (RabbitMQ.Client.Events.EventingBasicConsumer)sender; try { ConfirmationFile confirmation = DeserializeConfirmation(args.Body); ProcessIncomingConfirmation(confirmation); //Try to save the confirmation 5 times. Several threads are modifying the order history table, so there are occasional concurrency errors. KeithLink.Svc.Impl.Helpers.Retry.Do(() => _conversionLogic.SaveConfirmationAsOrderHistory(confirmation), TimeSpan.FromSeconds(1), 5); genericSubscriptionQueue.Ack(consumer, args.DeliveryTag); } catch (QueueDataError <ConfirmationFile> dataException) { // Move to errror queue PublishToQueue(dataException.ProcessingObject, ConfirmationQueueLocation.Error); _log.WriteErrorLog(dataException.Message); } catch (Exception ex) { // Send NACK _log.WriteErrorLog("Error processing confirmation.", ex); genericSubscriptionQueue.Nack(consumer, args.DeliveryTag); } }
public void SaveOrderHistoryAsConfirmation(OrderHistoryFile histFile) { NewRelic.Api.Agent.NewRelic.AddCustomParameter("ControlNumber", histFile.Header.ControlNumber); NewRelic.Api.Agent.NewRelic.AddCustomParameter("CustomerNumber", histFile.Header.CustomerNumber); NewRelic.Api.Agent.NewRelic.AddCustomParameter("BranchId", histFile.Header.BranchId); if (histFile.Header.OrderSystem == Core.Enumerations.Order.OrderSource.Entree) { ConfirmationFile confirmation = histFile.ToConfirmationFile(); PurchaseOrder po = GetCsPurchaseOrderByNumber(histFile.Header.ControlNumber); if (po != null) { // need to save away pre and post status info, then if different, add something to the messaging LineItem[] currLineItems = new LineItem[po.LineItemCount]; LineItem[] origLineItems = new LineItem[po.LineItemCount]; po.OrderForms[0].LineItems.CopyTo(currLineItems, 0); po.OrderForms[0].LineItems.CopyTo(origLineItems, 0); string originalStatus = po.Status; SetCsLineInfo(currLineItems, confirmation); SetCsHeaderInfo(confirmation, po, currLineItems); po.Save(); } } }
private ConfirmationFile DeserializeConfirmation(byte[] bytes) { ConfirmationFile confirmation = null; try { confirmation = JsonConvert.DeserializeObject <ConfirmationFile>(Encoding.ASCII.GetString(bytes)); } catch (Exception ex) { throw new QueueDataError <string>("N/A", "DeserializeConfirmation", "Parsing confirmation to ConfirmationFile", ex.Message, ex); } return(confirmation); }
public static ConfirmationFile ToConfirmationFile(this OrderHistoryFile historyFile) { ConfirmationFile confirmation = new ConfirmationFile(); foreach (OrderHistoryDetail historyDetail in historyFile.Details) { ConfirmationDetail detail = new ConfirmationDetail() { RecordNumber = historyDetail.LineNumber.ToString(), ItemNumber = historyDetail.ItemNumber, QuantityOrdered = historyDetail.OrderQuantity, BrokenCase = (historyDetail.UnitOfMeasure == UnitOfMeasure.Package ? "Y" : "N"), QuantityShipped = historyDetail.ShippedQuantity, ShipWeight = historyDetail.TotalShippedWeight, SalesGross = historyDetail.SellPrice * historyDetail.ShippedQuantity, SalesNet = historyDetail.SellPrice * historyDetail.ShippedQuantity, PriceNet = (historyDetail.UnitOfMeasure == UnitOfMeasure.Case ? historyDetail.SellPrice : 0.0), PriceGross = (historyDetail.UnitOfMeasure == UnitOfMeasure.Case ? historyDetail.SellPrice : 0.0), SplitPriceNet = (historyDetail.UnitOfMeasure == UnitOfMeasure.Case ? 0.0 : historyDetail.SellPrice), SplitPriceGross = (historyDetail.UnitOfMeasure == UnitOfMeasure.Case ? 0.0 : historyDetail.SellPrice), ReasonNotShipped = historyDetail.ItemStatus //CaseCube //CaseWeight }; detail.ConfirmationMessage = detail.DisplayStatus(); confirmation.Detail.Add(detail); } confirmation.Header.Branch = historyFile.Header.BranchId; confirmation.Header.ConfirmationNumber = historyFile.Header.ControlNumber; confirmation.Header.CustomerNumber = historyFile.Header.CustomerNumber; confirmation.Header.InvoiceNumber = historyFile.Header.InvoiceNumber; confirmation.Header.ConfirmationDate = DateTime.Now.ToLongDateFormatWithTime(); confirmation.Header.ShipDate = historyFile.Header.DeliveryDate; confirmation.Header.RemoteOrderNumber = historyFile.Header.ControlNumber; // a confirmation will never have this data, and it is coming back wrong now //confirmation.Header.RouteNumber = historyFile.Header.RouteNumber; //confirmation.Header.StopNumber = historyFile.Header.StopNumber; confirmation.Header.TotalQuantityOrdered = confirmation.Detail.Sum(d => d.QuantityOrdered); confirmation.Header.TotalQuantityShipped = confirmation.Detail.Sum(d => d.QuantityShipped); //confirmation.Header.TotalInvoice confirmation.Header.ConfirmationStatus = historyFile.Header.OrderStatus; confirmation.Header.ConfirmationMessage = confirmation.Header.GetDisplayStatus(); //confirmation.Header.SpecialInstructions //confirmation.Header.SpecialInstructionsExtended //confirmation.Header.TotalCube //confirmation.Header.TotalWeight return(confirmation); }
/// <summary> /// Send serialized file to RabbitMQ, send object to commerce server /// </summary> /// <param name="file"></param> public void ProcessFileData(string[] file) { try { ConfirmationFile confirmation = ParseFile(file); confirmation.SenderApplicationName = Configuration.ApplicationName; confirmation.SenderProcessName = "Receive Confirmation From Mainframe"; PublishToQueue(confirmation, ConfirmationQueueLocation.Default); } catch (Exception e) { _log.WriteErrorLog(string.Format("ProcessFileData -\r\n{0}", string.Join("\r\n", file)), e); throw e; } }
private void SaveRejectedConfirmationAsOrderHistory(ConfirmationFile confFile) { //Assume we will only get rejections for Entree Orders Core.Enumerations.Order.OrderSource orderSource = Core.Enumerations.Order.OrderSource.Entree; EF.OrderHistoryHeader header = _historyRepo.ReadByConfirmationNumber(confFile.Header.ConfirmationNumber, orderSource.ToShortString()).FirstOrDefault(); if (header != null) { header.OrderStatus = Constants.CONFIRMATION_HEADER_REJECTED_CODE; header.InvoiceNumber = Constants.CONFIRMATION_HEADER_REJECTED_STATUS; _historyRepo.CreateOrUpdate(header); _uow.SaveChanges(); } }
public static OrderHistoryFile ToOrderHistoryFile(this ConfirmationFile confirmation) { OrderHistoryFile history = new OrderHistoryFile(); foreach (ConfirmationDetail confDetail in confirmation.Detail) { OrderHistoryDetail detail = new OrderHistoryDetail() { LineNumber = int.Parse(confDetail.RecordNumber), ItemNumber = confDetail.ItemNumber, OrderQuantity = confDetail.QuantityOrdered, UnitOfMeasure = confDetail.BrokenCase.Equals("Y", StringComparison.InvariantCultureIgnoreCase) ? UnitOfMeasure.Package : UnitOfMeasure.Case, ShippedQuantity = confDetail.QuantityShipped, TotalShippedWeight = confDetail.ShipWeight, SellPrice = (confDetail.BrokenCase.Equals("Y", StringComparison.InvariantCultureIgnoreCase) ? confDetail.SplitPriceNet : confDetail.PriceNet), ItemStatus = confDetail.ReasonNotShipped //CatchWeight, //FutureItem, //ItemDeleted, //ReplacedOriginalItemNumber, //SubbedOriginalItemNumber, }; history.Details.Add(detail); } history.Header.BranchId = confirmation.Header.Branch; history.Header.ControlNumber = confirmation.Header.ConfirmationNumber; history.Header.CustomerNumber = confirmation.Header.CustomerNumber; history.Header.InvoiceNumber = confirmation.Header.InvoiceNumber; history.Header.DeliveryDate = confirmation.Header.ShipDate; //history.Header.ControlNumber = confirmation.Header.RemoteOrderNumber; //history.Header.RouteNumber = confirmation.Header.RouteNumber; //history.Header.StopNumber = confirmation.Header.StopNumber; history.Header.OrderStatus = confirmation.Header.ConfirmationStatus; history.Header.OrderStatus = string.Empty; history.Header.OrderSystem = OrderSource.Entree; //history.Header.PONumber //history.Header.FutureItems //history.Header.ErrorStatus return(history); }
private void SetCsLineInfo(LineItem[] lineItems, ConfirmationFile confirmation) { foreach (var detail in confirmation.Detail) { // match incoming line items to CS line items int linePosition = Convert.ToInt32(detail.RecordNumber); LineItem orderFormLineItem = lineItems.Where(x => (int)x["LinePosition"] == (linePosition)).FirstOrDefault(); //LineItem orderFormLineItem = lineItems.Where(x => x.ProductId == detail.ItemNumber).FirstOrDefault(); if (orderFormLineItem != null) { SetCsLineItemInfo(orderFormLineItem, detail.QuantityOrdered, detail.QuantityShipped, detail.DisplayStatus(), detail.ItemNumber, detail.SubstitutedItemNumber(orderFormLineItem), detail.ItemStatus); } else { } } }
/// <summary> /// Parse an array of strings as a file /// </summary> /// <param name="data"></param> /// <returns></returns> private ConfirmationFile ParseFile(string[] data) { ConfirmationFile confirmation = new ConfirmationFile(); confirmation.Header.Parse(data[0]); // Start loop at detail, skip header for (int i = 1; i <= data.Length - 1; i++) { if (data[i].Contains("END###") == false) { ConfirmationDetail theDeets = new ConfirmationDetail(); theDeets.Parse(data[i]); confirmation.Detail.Add(theDeets); } } return(confirmation); }
private string SetCsHeaderInfo(ConfirmationFile confirmation, PurchaseOrder po, LineItem[] lineItems) { string trimmedConfirmationStatus = confirmation.Header.ConfirmationStatus.Trim().ToUpper(); switch (trimmedConfirmationStatus) { case Constants.CONFIRMATION_HEADER_CONFIRMED_CODE: string origOrderNumber = (string)po[Constants.CS_PURCHASE_ORDER_ORIGINAL_ORDER_NUMBER]; string currOrderNumber = po.TrackingNumber; bool isChangeOrder = origOrderNumber != currOrderNumber; SetCsPoStatusFromLineItems(po, lineItems, isChangeOrder); break; case Constants.CONFIRMATION_HEADER_IN_PROCESS_CODE: po.Status = Constants.CONFIRMATION_HEADER_IN_PROCESS_STATUS; break; case Constants.CONFIRMATION_HEADER_INVOICED_CODE: po.Status = Constants.CONFIRMATION_HEADER_INVOICED_STATUS; break; case Constants.CONFIRMATION_HEADER_DELETED_CODE: po.Status = Constants.CONFIRMATION_HEADER_DELETED_STATUS; break; case Constants.CONFIRMATION_HEADER_REJECTED_CODE: po.Status = Constants.CONFIRMATION_HEADER_REJECTED_STATUS; break; } if (confirmation.Header.ConfirmationStatus.Equals(Constants.CONFIRMATION_HEADER_REJECTED_CODE, StringComparison.InvariantCultureIgnoreCase)) { //po[Constants.CS_PURCHASE_ORDER_MASTER_NUMBER] = Constants.CONFIRMATION_HEADER_REJECTED_STATUS; } else { po[Constants.CS_PURCHASE_ORDER_MASTER_NUMBER] = confirmation.Header.InvoiceNumber; // read this from the confirmation file } return(trimmedConfirmationStatus); }
/// <summary> /// Publish confirmation file to queue /// </summary> /// <param name="file"></param> /// <param name="location"></param> public void PublishToQueue(ConfirmationFile file, ConfirmationQueueLocation location) { string serializedConfirmation = JsonConvert.SerializeObject(file); _log.WriteInformationLog(string.Format("Writing confirmation to the queue for message ({0}).{1}{1}{2}", file.MessageId, "\r\n", serializedConfirmation)); switch (location) { case ConfirmationQueueLocation.Default: genericeQueueRepository.PublishToQueue(serializedConfirmation, Configuration.RabbitMQConfirmationServer, Configuration.RabbitMQUserNamePublisher, Configuration.RabbitMQUserPasswordPublisher, Configuration.RabbitMQVHostConfirmation, Configuration.RabbitMQExchangeConfirmation); break; case ConfirmationQueueLocation.Error: genericeQueueRepository.PublishToQueue(serializedConfirmation, Configuration.RabbitMQConfirmationServer, Configuration.RabbitMQUserNamePublisher, Configuration.RabbitMQUserPasswordPublisher, Configuration.RabbitMQVHostConfirmation, Configuration.RabbitMQExchangeConfirmationErrors); break; default: break; } }
private void SetCsLineInfo(LineItem[] lineItems, ConfirmationFile confirmation) { List <LineItem> missingLineItems = new List <LineItem>(); foreach (LineItem orderFormLineItem in lineItems) { bool brokenCase = (bool)orderFormLineItem["Each"]; ConfirmationDetail detail = confirmation.Detail.Where(x => (x.ItemNumber == orderFormLineItem.ProductId || x.ConfirmationMessage.EndsWith(orderFormLineItem.ProductId)) && x.BrokenCase.Equals("y", StringComparison.InvariantCultureIgnoreCase) == brokenCase).FirstOrDefault(); if (detail == null) { // this adds the orderFormLineItem by reference and the ProcessMissingItems method updates the item and ultimately updates the original entry in the array missingLineItems.Add(orderFormLineItem); _log.WriteWarningLog(string.Format("Confirmation line not found for item {0}", orderFormLineItem.ProductId)); } else { SetCsLineItemInfo(orderFormLineItem, detail.QuantityOrdered, detail.QuantityShipped, detail.DisplayStatus(), detail.ItemNumber, detail.SubstitutedItemNumber(orderFormLineItem), GetItemPrice(brokenCase, detail), int.Parse(detail.RecordNumber)); } } if (missingLineItems.Count > 0) { ProcessMisingItems(missingLineItems, lineItems.Length); } }
public void SaveConfirmationAsOrderHistory(ConfirmationFile confFile) { if (confFile.Header.ConfirmationStatus.Equals(Constants.CONFIRMATION_HEADER_REJECTED_CODE, StringComparison.InvariantCultureIgnoreCase)) { SaveRejectedConfirmationAsOrderHistory(confFile); } else { OrderHistoryFile currentFile = confFile.ToOrderHistoryFile(); EF.OrderHistoryHeader header = _historyRepo.ReadForInvoice(currentFile.Header.BranchId, currentFile.Header.InvoiceNumber).FirstOrDefault(); // second attempt to find the order, look by confirmation number if (header == null) { header = _historyRepo.ReadByConfirmationNumber(currentFile.Header.ControlNumber, currentFile.Header.OrderSystem.ToShortString()).FirstOrDefault(); if (header != null) { header.InvoiceNumber = confFile.Header.InvoiceNumber; } } // last ditch effort is to create a new header if (header == null) { header = new EF.OrderHistoryHeader(); header.OrderDetails = new List <EF.OrderHistoryDetail>(); } currentFile.Header.MergeWithEntity(ref header); foreach (OrderHistoryDetail currentDetail in currentFile.Details) { EF.OrderHistoryDetail detail = null; if (header.OrderDetails != null && header.OrderDetails.Count > 0) { detail = header.OrderDetails.Where(d => (d.LineNumber == currentDetail.LineNumber)).FirstOrDefault(); } if (detail == null) { EF.OrderHistoryDetail tempDetail = currentDetail.ToEntityFrameworkModel(); tempDetail.BranchId = header.BranchId; tempDetail.InvoiceNumber = header.InvoiceNumber; header.OrderDetails.Add(currentDetail.ToEntityFrameworkModel()); } else { currentDetail.MergeWithEntityFrameworkModel(ref detail); detail.BranchId = header.BranchId; detail.InvoiceNumber = header.InvoiceNumber; } } //Mark missing items as deleted foreach (var deletedItem in header.OrderDetails.Where(d => !currentFile.Details.Any(c => c.LineNumber.Equals(d.LineNumber))).ToList()) { deletedItem.ItemDeleted = true; deletedItem.OrderQuantity = 0; deletedItem.ShippedQuantity = 0; } GetSubtotal(header); _historyRepo.CreateOrUpdate(header); _uow.SaveChangesAndClearContext(); } }
public bool ProcessIncomingConfirmation(ConfirmationFile confirmation) { if (String.IsNullOrEmpty(confirmation.Header.ConfirmationNumber)) { throw new QueueDataError <ConfirmationFile>(confirmation, "ProcessIncomingConfirmation", "Process incoming confirmations", "Confirmation Number is Required", new Exception()); } ; if (String.IsNullOrEmpty(confirmation.Header.InvoiceNumber)) { throw new QueueDataError <ConfirmationFile>(confirmation, "ProcessIncomingConfirmation", "Process incoming confirmations", "Invoice Number is Required", new Exception()); } ; if (confirmation.Header.ConfirmationStatus == null) { throw new QueueDataError <ConfirmationFile>(confirmation, "ProcessIncomingConfirmation", "Process incoming confirmations", "Confirmation Status is Required", new Exception()); } ; var poNum = confirmation.Header.ConfirmationNumber; PurchaseOrder po = GetCsPurchaseOrderByNumber(poNum); NewRelic.Api.Agent.NewRelic.AddCustomParameter("ConfirmationNumber", confirmation.Header.ConfirmationNumber); NewRelic.Api.Agent.NewRelic.AddCustomParameter("CustomerNumber", confirmation.Header.CustomerNumber); NewRelic.Api.Agent.NewRelic.AddCustomParameter("Branch", confirmation.Header.Branch); NewRelic.Api.Agent.NewRelic.AddCustomParameter("ItemCount", confirmation.Detail.Count()); if (po == null) { _log.WriteWarningLog("Could not find PO for confirmation number: {ConfirmationNumber}, Line: 399, Method: ProcessIncomingConfirmation".InjectSingleValue("ConfirmationNumber", poNum)); } else { // make sure that there are items to process if (po.LineItemCount == 0 || po.OrderForms[0].LineItems.Count == 0) { throw new QueueDataError <ConfirmationFile>(confirmation, "ProcessIncomingConfirmation", "Process incoming confirmations", "Purchase order has no line items", new Exception()); } // need to save away pre and post status info, then if different, add something to the messaging LineItem[] currLineItems = new LineItem[po.LineItemCount]; LineItem[] origLineItems = new LineItem[po.LineItemCount]; po.OrderForms[0].LineItems.CopyTo(currLineItems, 0); po.OrderForms[0].LineItems.CopyTo(origLineItems, 0); string originalStatus = po.Status; if (confirmation.Header.ConfirmationStatus.Equals(Constants.CONFIRMATION_HEADER_REJECTED_CODE, StringComparison.InvariantCultureIgnoreCase)) { // Update line item status' to rejected foreach (var item in currLineItems) { item["MainFrameStatus"] = "Rejected"; } } else { SetCsLineInfo(currLineItems, confirmation); } SetCsHeaderInfo(confirmation, po, currLineItems); string logMessage = string.Format("Updating purchase order status to '{0}' for tracking number {1}, confirmation number {2}, and invoice number {3}.", po.Status, po.TrackingNumber, confirmation.Header.ConfirmationNumber, confirmation.Header.InvoiceNumber); _log.WriteInformationLog(logMessage); po.Save(); // use internal messaging logic to put order up message on the queue OrderChange orderChange = BuildOrderChanges(po, currLineItems, origLineItems, originalStatus, confirmation.Header.SpecialInstructions, confirmation.Header.ShipDate); if (orderChange.OriginalStatus != orderChange.CurrentStatus || orderChange.ItemChanges.Count > 0) { OrderConfirmationNotification orderConfNotification = new OrderConfirmationNotification(); orderConfNotification.OrderChange = orderChange; orderConfNotification.OrderNumber = (string)po["OrderNumber"]; orderConfNotification.CustomerNumber = (string)po["CustomerId"]; orderConfNotification.BranchId = (string)po["BranchId"]; orderConfNotification.InvoiceNumber = confirmation.Header.InvoiceNumber; genericeQueueRepository.PublishToDirectedExchange(orderConfNotification.ToJson(), Configuration.RabbitMQNotificationServer, Configuration.RabbitMQNotificationUserNamePublisher, Configuration.RabbitMQNotificationUserPasswordPublisher, Configuration.RabbitMQVHostNotification, Configuration.RabbitMQExchangeNotificationV2, Constants.RABBITMQ_NOTIFICATION_ORDERCONFIRMATION_ROUTEKEY); } } return(true); }
public static string ToJson(this ConfirmationFile confirmation) { return(Newtonsoft.Json.JsonConvert.SerializeObject(confirmation)); }