public void LogManualOrderChanges( [CosmosDBTrigger( databaseName: "sourcing-engine", collectionName: "manual-orders", LeaseCollectionName = "sourcing-leases", ConnectionStringSetting = "AzureCosmosDBConnectionString", CreateLeaseCollectionIfNotExists = true), SwaggerIgnore] IReadOnlyList <Document> documents, [CosmosDB(ConnectionStringSetting = "AzureCosmosDBConnectionString"), SwaggerIgnore] DocumentClient documentClient, ILogger log) { log.LogInformation(@"Documents: {0}", documents); foreach (var document in documents) { ManualOrder mOrder = (dynamic)document; log.LogInformation(@"Order ID: {0} Manual Order: {1}", mOrder.atgOrderId, mOrder); // Track changes to specific properties log.LogInformation($"Order ID: {mOrder.atgOrderId}"); log.LogInformation($"Order ID: {mOrder.atgOrderId} Order complete: {mOrder.orderComplete}"); log.LogInformation($"Order ID: {mOrder.atgOrderId} Time completed: {mOrder.timeCompleted}"); log.LogInformation($"Order ID: {mOrder.atgOrderId} Claimed: {mOrder.claimed}"); log.LogInformation($"Order ID: {mOrder.atgOrderId} Time claimed: {mOrder.timeClaimed}"); log.LogInformation($"Order ID: {mOrder.atgOrderId} Notes: {mOrder.notes}"); } }
/// <summary> /// Updates an existing ManualOrder based on the ATG Order values, but does not overwrite the existing claimed, completed or notes values. /// </summary> /// <param name="atgOrderRes">ATG Order with sourcing fields.</param> /// <param name="manualOrderDoc">CosmosDB document that can be parsed to get the existing manual order.</param> /// <returns>The updated ManualOrder object.</returns> public ManualOrder UpdateManualOrder(AtgOrderRes atgOrderRes, Document manualOrderDoc) { try { ManualOrder existingManualOrder = (dynamic)manualOrderDoc; var updatedManualOrder = new ManualOrder(atgOrderRes) { // Do not overwrite values that can be set by an ATG rep claimed = existingManualOrder.claimed, timeClaimed = existingManualOrder.timeClaimed, orderComplete = existingManualOrder.orderComplete, timeCompleted = existingManualOrder.timeCompleted, notes = existingManualOrder.notes }; SetLogons(updatedManualOrder); return(updatedManualOrder); } catch (Exception ex) { var title = $"Error in UpdateManualOrder. Order ID: {atgOrderRes.atgOrderId}."; _logger.LogError(@"{Title} {Ex}", title, ex); #if RELEASE var teamsMessage = new TeamsMessage(title, $"Error message: {ex.Message}. Stacktrace: {ex.StackTrace}", "red", SourcingEngineFunctions.errorLogsUrl); teamsMessage.LogToTeams(teamsMessage); #endif throw; } }
/// <summary> /// Sets the TrilogieStatus, TrilogieErrorMessage and TrilogieOrderID fieldson the ManualOrder in CosmosDB based on the request values. /// </summary> /// <param name="atgOrderId">ID of the original ATG order.</param> /// <param name="document">Cosmos DocumentDB client.</param> /// <param name="trilogieReq">Request containing the results of submitting the order to Trilogie.</param> public static async Task UpdateTrilogieStatusOnManualOrder(string atgOrderId, DocumentClient document, TrilogieRequest trilogieReq) { try { var manualOrderDoc = await GetOrder <ManualOrder>(atgOrderId, document); ManualOrder manualOrder = (dynamic)manualOrderDoc; if (manualOrder != null) { await SetTrilogieFieldsOnManualOrder(trilogieReq, manualOrder); } else // create a new manual order { var orderController = new OrderController(new LocationController()); var orderDoc = await GetOrder <AtgOrderRes>(atgOrderId, document); AtgOrderRes atgOrder = (dynamic)orderDoc; manualOrder = orderController.CreateManualOrder(atgOrder, trilogieReq); } var containerName = Environment.GetEnvironmentVariable("MANUAL_ORDERS_CONTAINER_NAME"); var collectionUri = UriFactory.CreateDocumentCollectionUri("sourcing-engine", containerName); _ = document.UpsertDocumentAsync(collectionUri, manualOrder); } catch (Exception ex) { _logger.LogError(ex, "Exception in UpdateTrilogieStatusOnManualOrder"); throw; } }
public static async Task RunSourcingOnStaleOrders( [HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req, [CosmosDB(ConnectionStringSetting = "AzureCosmosDBConnectionString"), SwaggerIgnore] DocumentClient documentClient, ILogger log) { try { var manualOrdersCollectionUri = UriFactory.CreateDocumentCollectionUri("sourcing-engine", "manual-orders"); var query = new SqlQuerySpec { QueryText = "SELECT * FROM c WHERE c.orderComplete = false AND c.claimed = false" }; var incompleteOrderDocs = documentClient.CreateDocumentQuery <Document>(manualOrdersCollectionUri, query, option).AsEnumerable(); log.LogInformation($"Incomplete Order Count: {incompleteOrderDocs.Count()}"); if (incompleteOrderDocs.Count() == 0) { return; } foreach (var orderDoc in incompleteOrderDocs) { try { ManualOrder manualOrder = (dynamic)orderDoc; log.LogInformation($"Order ID: {manualOrder.atgOrderId}"); var atgOrderDoc = await OrderController.GetOrder <AtgOrderRes>(manualOrder.atgOrderId, documentClient); AtgOrderRes atgOrderRes = (dynamic)atgOrderDoc; log.LogInformation(@"ATG Order: {0}", atgOrderRes); var sourcingController = InitializeSourcingController(log); await sourcingController.StartSourcing(documentClient, atgOrderRes); } catch (Exception ex) { var title = "Error in RunSourcingOnStaleOrders loop"; var teamsMessage = new TeamsMessage(title, $"Error message: {ex.Message}. Stacktrace: {ex.StackTrace}", "yellow", errorLogsUrl); teamsMessage.LogToTeams(teamsMessage); log.LogError(@"{0}: {1}", title, ex); } } } catch (Exception ex) { var title = "Error in RunSourcingOnStaleOrders"; var teamsMessage = new TeamsMessage(title, $"Error message: {ex.Message}. Stacktrace: {ex.StackTrace}", "red", errorLogsUrl); teamsMessage.LogToTeams(teamsMessage); log.LogError(@"{0}: {1}", title, ex); } }
/// <summary> /// Sets the shipFromLogon value for each line item based on the shipFrom value. /// </summary> /// <param name="manualOrder">Manual Order object containing shipFrom values for each line item.</param> public void SetLogons(ManualOrder manualOrder) { manualOrder.sellLogon = locationController.GetBranchLogonID(manualOrder.sellWhse); manualOrder.sourcing.ForEach(source => { if (!string.IsNullOrEmpty(source.shipFrom)) { source.shipFromLogon = locationController.GetBranchLogonID(source.shipFrom); } }); }
/// <summary> /// Creates a new manual order object for orders that cannot be auto-sourced and require manual intervention by a rep. /// </summary> /// <param name="atgOrderRes">ATG Order with sourcing fields.</param> /// <returns>The manual order object that was created from the ATG order.</returns> public ManualOrder CreateManualOrder(AtgOrderRes atgOrderRes, TrilogieRequest trilogieReq = null) { try { var manualOrder = new ManualOrder(atgOrderRes, trilogieReq); SetLogons(manualOrder); return(manualOrder); } catch (Exception ex) { var title = $"Error in CreateOrUpdateManualOrder. Order ID: {atgOrderRes.atgOrderId}."; _logger.LogError(@"{Title} {Ex}", title, ex); #if RELEASE var teamsMessage = new TeamsMessage(title, $"Error message: {ex.Message}. Stacktrace: {ex.StackTrace}", "red", SourcingEngineFunctions.errorLogsUrl); teamsMessage.LogToTeams(teamsMessage); #endif throw; } }
public static async Task ReSourceBackorderedItems( [TimerTrigger("0 */15 * * * *")] TimerInfo timer, // every 15 mins [CosmosDB(ConnectionStringSetting = "AzureCosmosDBConnectionString"), SwaggerIgnore] DocumentClient documentClient, ILogger log) { try { var currentHour = OrderController.GetCurrentEasternHour(); log.LogInformation($"Current Hour: {currentHour}"); // Only run within 6am - 7pm EST if (currentHour < 6 || currentHour >= 19) { return; } // Get open orders with backordered item(s) var query = new SqlQuerySpec { QueryText = @" SELECT VALUE c FROM c JOIN s IN c.sourcing JOIN i IN s.items WHERE c.orderComplete = false AND c.claimed = false AND (i.sourcingMessage = 'Backordered.' OR CONTAINS(i.sourcingMessage, 'does not have the required quantity'))" }; var manualOrdersCollectionUri = UriFactory.CreateDocumentCollectionUri("sourcing-engine", "manual-orders"); var manualOrderDocs = documentClient.CreateDocumentQuery <Document>(manualOrdersCollectionUri, query, option).AsEnumerable(); // Get the matching ATG Order from query results and run sourcing foreach (var manualOrderDoc in manualOrderDocs) { try { ManualOrder manualOrder = (dynamic)manualOrderDoc; log.LogInformation($"Order ID: {manualOrder.atgOrderId}"); var atgOrderDoc = await OrderController.GetOrder <AtgOrderRes>(manualOrder.atgOrderId, documentClient); AtgOrderRes atgOrder = (dynamic)atgOrderDoc; await InitializeSourcingController(log).StartSourcing(documentClient, atgOrder); } catch (Exception ex) { var title = "Error in ReSourceBackorderedItems foreach loop."; var teamsMessage = new TeamsMessage(title, $"Error message: {ex.Message}. Stacktrace: {ex.StackTrace}", "yellow", errorLogsUrl); teamsMessage.LogToTeams(teamsMessage); log.LogError(ex, title); } } } catch (Exception ex) { var title = "Error in ReSourceBackorderedItems."; var teamsMessage = new TeamsMessage(title, $"Error message: {ex.Message}. Stacktrace: {ex.StackTrace}", "red", errorLogsUrl); teamsMessage.LogToTeams(teamsMessage); log.LogError(ex, title); } }
/// <summary> /// Sets the Trilogie fields on the Manual Order, incld. error message, status and order ID. /// </summary> /// <param name="trilogieReq">Request containing the results of submitting the order to Trilogie.</param> /// <param name="manualOrder">Manual Order object that matches the ATG Order from the request.</param> public static async Task SetTrilogieFieldsOnManualOrder(TrilogieRequest trilogieReq, ManualOrder manualOrder) { manualOrder.trilogieErrorMessage = trilogieReq.TrilogieErrorMessage; manualOrder.trilogieOrderId = trilogieReq.TrilogieOrderId; manualOrder.trilogieStatus = trilogieReq.TrilogieStatus.ToString(); #if DEBUG // Sets to false if order failed in Trilogie manualOrder.orderComplete = trilogieReq.TrilogieStatus == TrilogieStatus.Pass; if (manualOrder.orderComplete) { manualOrder.timeCompleted = GetCurrentEasternTime(); } else { manualOrder.timeCompleted = null; } #endif }