From 43c5aca12a090bec2fc891a47322cc7b9bcc01b8 Mon Sep 17 00:00:00 2001 From: Thomas Ryan Date: Sat, 13 Jul 2024 16:17:44 -0700 Subject: [PATCH] Updated the daily email in support of #439. --- Messaging/Program.cs | 18 ++++++++-------- NumberSearch.Ingest/Orders.cs | 39 +++++++++++++++++++++++----------- NumberSearch.Ingest/Owned.cs | 34 +++++++++++++++++++---------- NumberSearch.Ingest/Program.cs | 4 ++-- 4 files changed, 61 insertions(+), 34 deletions(-) diff --git a/Messaging/Program.cs b/Messaging/Program.cs index ca7f786f..0968bb34 100644 --- a/Messaging/Program.cs +++ b/Messaging/Program.cs @@ -1297,7 +1297,7 @@ public static async Task, NotFound, BadRequest(messageRecord.ToForward); - var checkTo = PhoneNumbersNA.PhoneNumber.TryParse(toForward.To, out var toRegisteredNumber); + var checkTo = PhoneNumbersNA.PhoneNumber.TryParse(toForward?.To ?? string.Empty, out var toRegisteredNumber); if (toForward is not null && checkTo) { @@ -1399,7 +1399,7 @@ public static async Task, BadRequest, BadRequest numbers = new(); + List numbers = []; string[] toParse = message.To.Split(','); foreach (var number in toParse) @@ -1501,7 +1501,7 @@ public static async Task, BadRequest 0 && !string.IsNullOrWhiteSpace(message.MediaURLs.FirstOrDefault())) + if (message is not null && message.MediaURLs.Length > 0 && !string.IsNullOrWhiteSpace(message.MediaURLs.FirstOrDefault())) { var multipartContent = new MultipartFormDataContent { { new StringContent(appSettings.ConnectionStrings.PComNetUsername), "username" }, @@ -1705,10 +1705,10 @@ public static async Task, BadRequest, BadRequest, Ok, UnauthorizedHttpResult>> diff --git a/NumberSearch.Ingest/Orders.cs b/NumberSearch.Ingest/Orders.cs index 2e8fd9c5..c3df1d90 100644 --- a/NumberSearch.Ingest/Orders.cs +++ b/NumberSearch.Ingest/Orders.cs @@ -18,11 +18,11 @@ namespace NumberSearch.Ingest { public class Orders { - public static async Task EmailDailyAsync(IngestConfiguration appConfig) + public static async Task EmailDailyAsync(Owned.SMSRouteChange[] smsRouteChanges, IngestConfiguration appConfig) { DateTime start = DateTime.Now; - var checkBriefing = await Orders.DailyBriefingEmailAsync(appConfig); + var checkBriefing = await Orders.DailyBriefingEmailAsync(smsRouteChanges, appConfig); var combined = new IngestStatistics { @@ -51,7 +51,7 @@ public static async Task EmailDailyAsync(IngestConfiguration a return combined; } - public static async Task DailyBriefingEmailAsync(IngestConfiguration appConfig) + public static async Task DailyBriefingEmailAsync(Owned.SMSRouteChange[] smsRouteChanges, IngestConfiguration appConfig) { // Gather all of the info to put into the daily email. var orders = await Order.GetAllAsync(appConfig.Postgresql); @@ -88,7 +88,7 @@ public static async Task DailyBriefingEmailAsync(IngestConfiguration appCo else if (order.Quote is false && order.Completed is false) { var portRequest = await PortRequest.GetByOrderIdAsync(order.OrderId, appConfig.Postgresql); - if (portRequest is not null && portRequest?.State is not "COMPLETE" && portRequest.DateSubmitted > order.DateSubmitted) + if (portRequest is not null && portRequest?.State is not "COMPLETE" && portRequest?.DateSubmitted > order.DateSubmitted) { ordersWithUnfinishedPortRequests.Add(order); } @@ -97,7 +97,7 @@ public static async Task DailyBriefingEmailAsync(IngestConfiguration appCo else if (order.Quote is false && order.Completed is false) { var portRequest = await PortRequest.GetByOrderIdAsync(order.OrderId, appConfig.Postgresql); - if (portRequest is not null && portRequest?.State is not "COMPLETE" && portRequest.DateSubmitted < order.DateSubmitted) + if (portRequest is not null && portRequest?.State is not "COMPLETE" && portRequest?.DateSubmitted < order.DateSubmitted) { ordersWithUnsubmittedPortRequests.Add(order); } @@ -146,7 +146,7 @@ public static async Task DailyBriefingEmailAsync(IngestConfiguration appCo var salesEmail = string.IsNullOrWhiteSpace(item.SalesEmail) ? "No sales rep assigned" : item.SalesEmail; var installDate = item?.InstallDate is not null ? item?.InstallDate.GetValueOrDefault().ToShortDateString() : "No install date set"; var paid = item?.DateUpfrontInvoicePaid is not null && item.DateUpfrontInvoicePaid.Value > item.DateSubmitted ? $"Paid {item.DateUpfrontInvoicePaid.Value.ToShortDateString()}" : "Unpaid"; - output.Append($"
  • {orderName} - Install Date {installDate} - {paid}
  • "); + output.Append($"
  • {orderName} - Install Date {installDate} - {paid}
  • "); } output.Append(""); } @@ -163,7 +163,7 @@ public static async Task DailyBriefingEmailAsync(IngestConfiguration appCo var orderName = string.IsNullOrWhiteSpace(item.BusinessName) ? $"{item.FirstName} {item.LastName}" : item.BusinessName; var salesEmail = string.IsNullOrWhiteSpace(item.SalesEmail) ? "support@acceleratenetworks.com" : item.SalesEmail; var completedDate = item?.DateCompleted is not null ? item?.DateCompleted.GetValueOrDefault().ToShortDateString() : "No completed date set"; - output.Append($"
  • {orderName} submitted on {item.DateSubmitted.ToShortDateString()} - Completed on {completedDate}
  • "); + output.Append($"
  • {orderName} submitted on {item?.DateSubmitted.ToShortDateString()} - Completed on {completedDate}
  • "); } output.Append(""); } @@ -180,7 +180,7 @@ public static async Task DailyBriefingEmailAsync(IngestConfiguration appCo var orderName = string.IsNullOrWhiteSpace(item.BusinessName) ? $"{item.FirstName} {item.LastName}" : item.BusinessName; var salesEmail = string.IsNullOrWhiteSpace(item.SalesEmail) ? "No sales rep assigned" : item.SalesEmail; var installDate = item?.InstallDate is not null ? item?.InstallDate.GetValueOrDefault().ToShortDateString() : "No install date set"; - output.Append($"
  • {orderName} - {orderName}\">{salesEmail}
  • "); + output.Append($"
  • {orderName} - {orderName}\">{salesEmail}
  • "); } output.Append(""); } @@ -255,6 +255,21 @@ public static async Task DailyBriefingEmailAsync(IngestConfiguration appCo // output.Append("
  • None
  • "); //} + output.Append("

    Owned Numbers who's SMS Routing changed from yesterday:

    "); + output.Append("

    You can investigate these numbers and refresh their Upstream Status, attempt to Reregister them, and look at their current Carrier in Ops => Messaging Users

    "); + } + else + { + output.Append("
  • None
  • "); + } + output.Append("

    Incomplete orders where the install date has passed in the last quarter:

      "); if (ordersToMarkCompleted.Count > 0) { @@ -263,7 +278,7 @@ public static async Task DailyBriefingEmailAsync(IngestConfiguration appCo var orderName = string.IsNullOrWhiteSpace(item.BusinessName) ? $"{item.FirstName} {item.LastName}" : item.BusinessName; var salesEmail = string.IsNullOrWhiteSpace(item.SalesEmail) ? "No sales rep assigned" : item.SalesEmail; var installDate = item?.InstallDate is not null ? item?.InstallDate.GetValueOrDefault().ToShortDateString() : "No install date set"; - output.Append($"
    • {orderName} - {orderName}\">{salesEmail} - {installDate}
    • "); + output.Append($"
    • {orderName} - {orderName}\">{salesEmail} - {installDate}
    • "); } output.Append("
    "); } @@ -281,7 +296,7 @@ public static async Task DailyBriefingEmailAsync(IngestConfiguration appCo var orderName = string.IsNullOrWhiteSpace(item.BusinessName) ? $"{item.FirstName} {item.LastName}" : item.BusinessName; var salesEmail = string.IsNullOrWhiteSpace(item.SalesEmail) ? "No sales rep assigned" : item.SalesEmail; var installDate = item?.InstallDate is not null ? item?.InstallDate.GetValueOrDefault().ToShortDateString() : "No install date set"; - output.Append($"
  • {orderName} - {orderName}\">{salesEmail} - {installDate}
  • "); + output.Append($"
  • {orderName} - {orderName}\">{salesEmail} - {installDate}
  • "); } output.Append(""); } @@ -298,7 +313,7 @@ public static async Task DailyBriefingEmailAsync(IngestConfiguration appCo var orderName = string.IsNullOrWhiteSpace(item.BusinessName) ? $"{item.FirstName} {item.LastName}" : item.BusinessName; var salesEmail = string.IsNullOrWhiteSpace(item.SalesEmail) ? "No sales rep assigned" : item.SalesEmail; var installDate = item?.InstallDate is not null ? item?.InstallDate.GetValueOrDefault().ToShortDateString() : "No install date set"; - output.Append($"
  • {orderName} - {orderName}\">{salesEmail} - {installDate}
  • "); + output.Append($"
  • {orderName} - {orderName}\">{salesEmail} - {installDate}
  • "); } output.Append(""); } @@ -315,7 +330,7 @@ public static async Task DailyBriefingEmailAsync(IngestConfiguration appCo var orderName = string.IsNullOrWhiteSpace(item.BusinessName) ? $"{item.FirstName} {item.LastName}" : item.BusinessName; var salesEmail = string.IsNullOrWhiteSpace(item.SalesEmail) ? "No sales rep assigned" : item.SalesEmail; var installDate = item?.InstallDate is not null ? item?.InstallDate.GetValueOrDefault().ToShortDateString() : "No install date set"; - output.Append($"
  • {orderName} - {orderName}\">{salesEmail} - {installDate}
  • "); + output.Append($"
  • {orderName} - {orderName}\">{salesEmail} - {installDate}
  • "); } output.Append(""); } diff --git a/NumberSearch.Ingest/Owned.cs b/NumberSearch.Ingest/Owned.cs index a9022b1d..dccdf5c3 100644 --- a/NumberSearch.Ingest/Owned.cs +++ b/NumberSearch.Ingest/Owned.cs @@ -24,7 +24,7 @@ namespace NumberSearch.Ingest public class Owned { - public static async Task OwnedDailyAsync(IngestConfiguration appConfig) + public static async Task OwnedDailyAsync(IngestConfiguration appConfig) { // Prevent another run from starting while this is still going. @@ -42,14 +42,16 @@ public static async Task OwnedDailyAsync(IngestConfiguration appConfig) Lock = true }; - var checkLock = await lockingStats.PostAsync(appConfig.Postgresql).ConfigureAwait(false); - await Owned.IngestAsync(appConfig); + await lockingStats.PostAsync(appConfig.Postgresql).ConfigureAwait(false); + var smsRouteChanges = await Owned.IngestAsync(appConfig); // Remove the lock from the database to prevent it from getting cluttered with blank entries. - var checkRemoveLock = await lockingStats.DeleteAsync(appConfig.Postgresql).ConfigureAwait(false); + await lockingStats.DeleteAsync(appConfig.Postgresql).ConfigureAwait(false); + + return smsRouteChanges; } - public async static Task IngestAsync(IngestConfiguration configuration) + public async static Task IngestAsync(IngestConfiguration configuration) { Log.Information("[OwnedNumbers] Ingesting data for OwnedNumbers."); var allNumbers = new List(); @@ -143,7 +145,7 @@ public async static Task IngestAsync(IngestConfiguration configuration) await MatchOwnedNumbersToFusionPBXAsync(configuration.Postgresql, configuration.FusionPBXUsername, configuration.FusionPBXPassword); // Verify SMS routing with Endstream. - await VerifySMSRoutingAsync(configuration.Postgresql, configuration.PComNetUsername, configuration.PComNetPassword); + var smsRouteChanges = await VerifySMSRoutingAsync(configuration.Postgresql, configuration.PComNetUsername, configuration.PComNetPassword); // Update the statuses on old or orphaned port requests and ported numbers. await PortRequests.UpdatePortRequestsAndNumbersByExternalIdAsync(configuration); @@ -178,12 +180,18 @@ public async static Task IngestAsync(IngestConfiguration configuration) { Log.Fatal("[OwnedNumbers] Failed to completed the ingest process."); } + + return smsRouteChanges; } - public static async Task VerifySMSRoutingAsync(string connectionString, string pComNetUsername, string pComNetPassword) + public record SMSRouteChange(string DialedNumber, string OldRoute, string NewRoute, string Message); + + public static async Task VerifySMSRoutingAsync(string connectionString, string pComNetUsername, string pComNetPassword) { Log.Information($"[OwnedNumbers] Verifying SMS Routing for Owned Phone numbers."); + var changes = new List(); + var ownedNumbers = await OwnedPhoneNumber.GetAllAsync(connectionString).ConfigureAwait(false); foreach (var number in ownedNumbers.Where(x => x.Status is "Active")) @@ -197,6 +205,7 @@ public static async Task VerifySMSRoutingAsync(string connectionString, string p // Update the owned number with the route. if (number.SMSRoute != checkSMSRouting.route) { + changes.Add(new SMSRouteChange(number.DialedNumber, number.SMSRoute, checkSMSRouting.route, checkSMSRouting.QueryResult.text)); number.SMSRoute = checkSMSRouting.route; updated = true; } @@ -207,6 +216,7 @@ public static async Task VerifySMSRoutingAsync(string connectionString, string p // Update the owned number with the route. if (number.SMSRoute != checkSMSRouting.QueryResult.text) { + changes.Add(new SMSRouteChange(number.DialedNumber, number.SMSRoute, checkSMSRouting.route, checkSMSRouting.QueryResult.text)); number.SMSRoute = checkSMSRouting.QueryResult.text; updated = true; } @@ -225,6 +235,8 @@ public static async Task VerifySMSRoutingAsync(string connectionString, string p } Log.Information($"[OwnedNumbers] Verified SMS Routing for {ownedNumbers.Count()} Owned Phone numbers."); + + return [.. changes]; } public static async Task MatchOwnedNumbersToFusionPBXAsync(string connectionString, string fusionPBXUsername, string fusionPBXPassword) @@ -547,7 +559,7 @@ public static async Task OfferUnassignedNumberForSaleAsync(str NXX = phoneNumber.NXX, XXXX = phoneNumber.XXXX, DialedNumber = phoneNumber.DialedNumber ?? string.Empty, - DateIngested = item.DateIngested, + DateIngested = item?.DateIngested ?? DateTime.Now, IngestedFrom = "OwnedNumber", Purchased = false }; @@ -555,11 +567,11 @@ public static async Task OfferUnassignedNumberForSaleAsync(str newUnassigned.Add(number); ingestedNew++; - Log.Information($"[Ingest] [OwnedNumber] Put unassigned number {item.DialedNumber} up for sale."); + Log.Information($"[Ingest] [OwnedNumber] Put unassigned number {item?.DialedNumber} up for sale."); } else { - Log.Fatal($"[Ingest] [OwnedNumber] Failed to put unassigned number {item.DialedNumber} up for sale. Number could not be parsed."); + Log.Fatal($"[Ingest] [OwnedNumber] Failed to put unassigned number {item?.DialedNumber} up for sale. Number could not be parsed."); } } else @@ -784,7 +796,7 @@ public static async Task VerifyEmergencyInformationAsync(string connectionString var ownedNumber = ownedNumbers.FirstOrDefault(x => x.DialedNumber == number.DialedNumber); if (checkParse && ownedNumber is not null && ownedNumber.EmergencyInformationId is not null && ownedNumber.EmergencyInformationId.HasValue) { - var existing = emergencyInformation.FirstOrDefault(x => x.EmergencyInformationId == ownedNumber.EmergencyInformationId.GetValueOrDefault()); + var existing = emergencyInformation?.FirstOrDefault(x => x.EmergencyInformationId == ownedNumber.EmergencyInformationId.GetValueOrDefault()); if (existing is not null && existing.DialedNumber == number.DialedNumber) { diff --git a/NumberSearch.Ingest/Program.cs b/NumberSearch.Ingest/Program.cs index 9d0a5994..27ad014f 100644 --- a/NumberSearch.Ingest/Program.cs +++ b/NumberSearch.Ingest/Program.cs @@ -92,8 +92,8 @@ await Provider.VerifyAddToCartAsync(AreaCode.Priority, "Executive", appConfig.Po var bulkVS = await Provider.BulkVSDailyAsync(appConfig); var firstPointCom = await Provider.FirstPointComDailyAsync(appConfig); - await Owned.OwnedDailyAsync(appConfig); - var email = await Orders.EmailDailyAsync(appConfig); + var smsRouteChanges = await Owned.OwnedDailyAsync(appConfig); + var email = await Orders.EmailDailyAsync(smsRouteChanges, appConfig); } Log.Information("[Heartbeat] Cycle complete. Daily Timer {Elapsed:000} ms.", dailyTimer.ElapsedMilliseconds);