diff --git a/OFM.Infrastructure.WebAPI/Extensions/SetupInfo.cs b/OFM.Infrastructure.WebAPI/Extensions/SetupInfo.cs index 98f6899c..07dfab44 100644 --- a/OFM.Infrastructure.WebAPI/Extensions/SetupInfo.cs +++ b/OFM.Infrastructure.WebAPI/Extensions/SetupInfo.cs @@ -49,6 +49,9 @@ public static class Emails public const Int16 CreateApplicationNotificationsId = 230; public const string CreateApplicationNotificationsName = "Create Email for Application Ineligilble"; + public const Int16 AllowanceApprovalDenialNotificationId= 240; + public const string AllowanceApprovalDenialNotificationName = "Create email and pdf for supplementary"; + } diff --git a/OFM.Infrastructure.WebAPI/Models/Fundings/Fundings.cs b/OFM.Infrastructure.WebAPI/Models/Fundings/Fundings.cs index 541b3bf5..e40aa974 100644 --- a/OFM.Infrastructure.WebAPI/Models/Fundings/Fundings.cs +++ b/OFM.Infrastructure.WebAPI/Models/Fundings/Fundings.cs @@ -1,4 +1,5 @@ using ECC.Core.DataContext; +using System.Text.Json.Serialization; namespace OFM.Infrastructure.WebAPI.Models.Fundings; @@ -148,6 +149,33 @@ public class SupplementaryApplication : ofm_allowance public new decimal? ofm_retroactive_amount { get; set; } public new SupplementarySchedule? ofm_supplementary_schedule { get; set; } public string _ofm_application_value { get; set; } + + public Guid ofm_allowanceid { get; set; } + public string ofm_allowance_number { get; set; } + public DateTime createdon { get; set; } + public int statuscode { get; set; } + public int ofm_renewal_term { get; set; } + [property: JsonPropertyName("con.ofm_first_name")] + + public string ofm_first_name { get; set; } + + [property: JsonPropertyName("con.ofm_last_name")] + + public string ofm_last_name { get; set; } + + [property: JsonPropertyName("app.ofm_contact")] + public Guid _ofm_contact_value { get; set; } + + [property: JsonPropertyName("app.ofm_summary_submittedby")] + public Guid _ofm_summary_submittedby_value { get; set; } + + [property: JsonPropertyName("app.statuscode")] + public int appstatuscode { get; set; } + [property: JsonPropertyName("app.ofm_funding_number_base")] + public string ofm_funding_number_base { get; set; } + [property: JsonPropertyName("funding.statuscode")] + public int fundingStatusCode { get; set; } + } public class BusinessClosure diff --git a/OFM.Infrastructure.WebAPI/Models/SettingsModels.cs b/OFM.Infrastructure.WebAPI/Models/SettingsModels.cs index a74530fb..01ab50f2 100644 --- a/OFM.Infrastructure.WebAPI/Models/SettingsModels.cs +++ b/OFM.Infrastructure.WebAPI/Models/SettingsModels.cs @@ -70,7 +70,10 @@ public record CommunicationTypes public class EmailTemplate { public int TemplateNumber { get; set; } - + + + public string Description { get; set; } + } public record ProcessSettings diff --git a/OFM.Infrastructure.WebAPI/OFM.Infrastructure.WebAPI.csproj b/OFM.Infrastructure.WebAPI/OFM.Infrastructure.WebAPI.csproj index a5abe2f0..b4e166c4 100644 --- a/OFM.Infrastructure.WebAPI/OFM.Infrastructure.WebAPI.csproj +++ b/OFM.Infrastructure.WebAPI/OFM.Infrastructure.WebAPI.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -58,6 +58,7 @@ + diff --git a/OFM.Infrastructure.WebAPI/Program.cs b/OFM.Infrastructure.WebAPI/Program.cs index b9d0c16e..45865559 100644 --- a/OFM.Infrastructure.WebAPI/Program.cs +++ b/OFM.Infrastructure.WebAPI/Program.cs @@ -75,7 +75,7 @@ services.AddScoped(); services.AddScoped(); services.AddScoped(); - +services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/OFM.Infrastructure.WebAPI/Services/D365WebApi/D365WebApiService.cs b/OFM.Infrastructure.WebAPI/Services/D365WebApi/D365WebApiService.cs index 6c44e23b..c793ad99 100644 --- a/OFM.Infrastructure.WebAPI/Services/D365WebApi/D365WebApiService.cs +++ b/OFM.Infrastructure.WebAPI/Services/D365WebApi/D365WebApiService.cs @@ -70,6 +70,10 @@ public async Task SendDocumentRequestAsync(AZAppUser spn, s { request = new(new D365EntityReference(entityNameSet, id), columnName: "ofm_input_document_memo", data, fileName); } + else if (entityNameSet.Equals("ofm_allowances")) + { + request = new(new D365EntityReference(entityNameSet, id), columnName: "ofm_approval_pdf", data, fileName); + } else { request = new(new D365EntityReference(entityNameSet, id), columnName: "ofm_file", data, fileName); diff --git a/OFM.Infrastructure.WebAPI/Services/Processes/Emails/IEmailRepository.cs b/OFM.Infrastructure.WebAPI/Services/Processes/Emails/IEmailRepository.cs index 38375593..f37ab2ce 100644 --- a/OFM.Infrastructure.WebAPI/Services/Processes/Emails/IEmailRepository.cs +++ b/OFM.Infrastructure.WebAPI/Services/Processes/Emails/IEmailRepository.cs @@ -1,8 +1,5 @@ using ECC.Core.DataContext; -using Microsoft.Xrm.Sdk.Messages; -using Microsoft.Xrm.Sdk; using OFM.Infrastructure.WebAPI.Extensions; -using OFM.Infrastructure.WebAPI.Messages; using OFM.Infrastructure.WebAPI.Models.Fundings; using OFM.Infrastructure.WebAPI.Services.AppUsers; using OFM.Infrastructure.WebAPI.Services.D365WebApi; @@ -10,23 +7,32 @@ using System.Text.Json.Nodes; using System.Net; using OFM.Infrastructure.WebAPI.Models; +using Microsoft.Extensions.Options; +using SelectPdf; namespace OFM.Infrastructure.WebAPI.Services.Processes.Fundings; public interface IEmailRepository { Task> LoadCommunicationTypeAsync(); - Task CreateAndUpdateEmail(string subject, string emailDescription, List toRecipient, Guid? senderId, string communicationType, ID365AppUserService appUserService, ID365WebApiService d365WebApiService, Int16 processId); + Task CreateAndUpdateEmail(string subject, string emailDescription, List toRecipient, Guid? senderId, string communicationType, ID365AppUserService appUserService, ID365WebApiService d365WebApiService, Int16 processId); Task GetTemplateDataAsync(int templateNumber); + string StripHTML(string source); + Task CreateAllowanceEmail(SupplementaryApplication allowance, Guid? senderId, string communicationType, Int16 processId, ID365WebApiService d365WebApiService); + Task NotificationSentSupp(Guid allowanceId, ID365WebApiService d365WebApiService, Int16 processId); + } -public class EmailRepository(ID365AppUserService appUserService, ID365WebApiService service, ID365DataService dataService, ILoggerFactory loggerFactory) : IEmailRepository +public class EmailRepository(ID365AppUserService appUserService, ID365WebApiService service, ID365DataService dataService, ILoggerFactory loggerFactory, IOptionsSnapshot notificationSettings) : IEmailRepository { private readonly ILogger _logger = loggerFactory.CreateLogger(LogCategory.Process); private readonly ID365DataService _dataService = dataService; private readonly ID365AppUserService _appUserService = appUserService; private readonly ID365WebApiService _d365webapiservice = service; + private readonly NotificationSettings _notificationSettings = notificationSettings.Value; private int _templateNumber; + Guid? newEmailId; + bool emailCreated = false; #region Pre-Defined Queries @@ -59,7 +65,7 @@ private string CommunicationTypeRequestUri private string TemplatetoRetrieveUri { get - { + { var fetchXml = $""" @@ -132,10 +138,10 @@ public async Task> LoadCommunicationTypeAsync #region Create and Update Email - public async Task CreateAndUpdateEmail(string subject, string emailDescription, List toRecipient, Guid? senderId, string communicationType, ID365AppUserService appUserService, ID365WebApiService d365WebApiService, Int16 processId) + public async Task CreateAndUpdateEmail(string subject, string emailDescription, List toRecipient, Guid? senderId, string communicationType, ID365AppUserService appUserService, ID365WebApiService d365WebApiService, Int16 processId) { - toRecipient.ForEach(async recipient => - { + toRecipient.ForEach(async recipient => + { var requestBody = new JsonObject(){ {"subject",subject }, {"description",emailDescription }, @@ -163,32 +169,317 @@ public async Task CreateAndUpdateEmail(string subject, string emailD return; } + else + { - var newEmail = await response.Content.ReadFromJsonAsync(); - var newEmailId = newEmail?["activityid"]; + var newEmail = await response.Content.ReadFromJsonAsync(); + newEmailId = (Guid)newEmail?["activityid"]; - var emailStatement = $"emails({newEmailId})"; + var emailStatement = $"emails({newEmailId})"; - var payload = new JsonObject { + var payload = new JsonObject { { "ofm_sent_on", DateTime.UtcNow }, { "statuscode", (int) Email_StatusCode.Completed }, { "statecode", (int) email_statecode.Completed }}; - var requestBody1 = JsonSerializer.Serialize(payload); + var requestBody1 = JsonSerializer.Serialize(payload); + + var patchResponse = await d365WebApiService.SendPatchRequestAsync(appUserService.AZSystemAppUser, emailStatement, requestBody1); + + if (!patchResponse.IsSuccessStatusCode) + { + var responseBody = await patchResponse.Content.ReadAsStringAsync(); + _logger.LogError(CustomLogEvent.Process, "Failed to patch the record with the server error {responseBody}", responseBody.CleanLog()); + + return; + } + } + }); + + + return await Task.FromResult(newEmailId); + } + public string StripHTML(string source) + { + try + { + string result; + // Remove HTML Development formatting + // Replace line breaks with space + // because browsers inserts space + result = source.Replace("\r", " "); + // Replace line breaks with space + // because browsers inserts space + result = result.Replace("\n", " "); + // Remove step-formatting + result = result.Replace("\t", string.Empty); + // Remove repeating spaces because browsers ignore them + result = System.Text.RegularExpressions.Regex.Replace(result, + @"( )+", " "); + // Remove the header (prepare first by clearing attributes) + result = System.Text.RegularExpressions.Regex.Replace(result, @"<( )*head([^>])*>", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"(<( )*(/)( )*head( )*>)", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, "().*()", string.Empty, System.Text.RegularExpressions.RegexOptions.IgnoreCase); + + // remove all scripts (prepare first by clearing attributes) + result = System.Text.RegularExpressions.Regex.Replace(result, @"<( )*script([^>])*>", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + + //result = System.Text.RegularExpressions.Regex.Replace(result, + //@"()])*()", + //string.Empty, + // System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"()", string.Empty, System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // remove all styles (prepare first by clearing attributes) + result = System.Text.RegularExpressions.Regex.Replace(result, @"<( )*style([^>])*>", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, "()", string.Empty, System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // insert tabs in spaces of tags + result = System.Text.RegularExpressions.Regex.Replace(result, @"<( )*td([^>])*>", "\t", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // insert line breaks in places of
and
  • tags + result = System.Text.RegularExpressions.Regex.Replace(result, @"<( )*br( )*>", "\r", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"<( )*li( )*>", "\r", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // insert line paragraphs (double line breaks) in place + // if

    ,

    and tags + result = System.Text.RegularExpressions.Regex.Replace(result, @"<( )*div([^>])*>", "\r\r", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"<( )*tr([^>])*>", "\r\r", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"<( )*p([^>])*>", "\r\r", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // Remove remaining tags like , links, images, + // comments etc - anything that's enclosed inside < > + result = System.Text.RegularExpressions.Regex.Replace(result, @"<[^>]*>", string.Empty, System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // replace special characters: + result = System.Text.RegularExpressions.Regex.Replace(result, @" ", " ", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"•", " * ", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"‹", "<", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"›", ">", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"™", "(tm)", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"⁄", "/", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"<", "<", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @">", ">", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"©", "(c)", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, @"®", "(r)", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // Remove all others. + result = System.Text.RegularExpressions.Regex.Replace(result, @"&(.{2,6});", string.Empty, System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // for testing + // System.Text.RegularExpressions.Regex.Replace(result, + //this.txtRegex.Text,string.Empty, + // System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // make line breaking consistent + result = result.Replace("\n", "\r"); + // Remove extra line breaks and tabs: + // replace over 2 breaks with 2 and over 4 tabs with 4. + // Prepare first to remove any whitespaces in between + // the escaped characters and remove redundant tabs in between line breaks + result = System.Text.RegularExpressions.Regex.Replace(result, "(\r)( )+(\r)", "\r\r", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, "(\t)( )+(\t)", "\t\t", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, "(\t)( )+(\r)", "\t\r", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + result = System.Text.RegularExpressions.Regex.Replace(result, "(\r)( )+(\t)", "\r\t", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // Remove redundant tabs + result = System.Text.RegularExpressions.Regex.Replace(result, "(\r)(\t)+(\r)", "\r\r", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + // Remove multiple tabs following a line break with just one tab + result = System.Text.RegularExpressions.Regex.Replace(result, "(\r)(\t)+", "\r\t", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + //Initial replacement target string for line breaks + string breaks = "\r\r\r"; + // Initial replacement target string for tabs + string tabs = "\t\t\t\t\t"; + for (int index = 0; index < result.Length; index++) + { + result = result.Replace(breaks, "\r\r"); + result = result.Replace(tabs, "\t\t\t\t"); + breaks = breaks + "\r"; + tabs = tabs + "\t"; + } + // That's it. + return result; + } + catch + { + //MessageBox.Show("Error"); + return source; + } + } + + public async Task CreateAllowanceEmail(SupplementaryApplication allowance, Guid? senderId, string communicationType, Int16 processId, ID365WebApiService d365WebApiService) + { + + var contactName = allowance.ofm_first_name + " " + allowance.ofm_last_name; + var MonthlyAmount = allowance.ofm_monthly_amount; + var RetroActiveAmount = allowance.ofm_retroactive_amount; + var allowanceType = (ecc_allowance_type)allowance.ofm_allowance_type; + var allowanceNumber = allowance.ofm_allowance_number; + var allownaceStatusReason = allowance.statuscode; + Guid applicationPrimaryContact = (Guid)allowance._ofm_contact_value != null ? (Guid)allowance._ofm_contact_value : Guid.Empty; + Guid submittedBy = allowance._ofm_summary_submittedby_value != null ? (Guid)allowance._ofm_summary_submittedby_value : Guid.Empty; + var fundingNumber = allowance.ofm_funding_number_base; + var effectiveDate = allowance.ofm_start_date; + var retroActiveDate = allowance.ofm_retroactive_date; + var VIN = allowance.ofm_transport_vehicle_vin; + // DateOnly retroActiveDate = allowance.ofm_ret; + + // funding status + _logger.LogInformation("Got the Status", allownaceStatusReason); + + + + //_allowanceId = _processParams.SupplementaryApplication.allowanceId; + if (allownaceStatusReason == (int)ofm_allowance_StatusCode.Approved) + { + ProcessData localDataTemplate = null; + + + _logger.LogInformation("Entered if Approved", allownaceStatusReason); + if (allowanceType == ecc_allowance_type.SupportNeedsProgramming) + // Get template details to create emails. + localDataTemplate = await GetTemplateDataAsync(_notificationSettings.EmailTemplates.First(t => t.Description == "SupportNeedsProgramAllowanceApproved").TemplateNumber); //240 + else if (allowanceType == ecc_allowance_type.IndigenousProgramming) + localDataTemplate = await GetTemplateDataAsync(_notificationSettings.EmailTemplates.First(t => t.Description == "IndigenousAllowanceApproved").TemplateNumber);//255 + else if (allowanceType == ecc_allowance_type.Transportation && RetroActiveAmount > 0) + localDataTemplate = await GetTemplateDataAsync(_notificationSettings.EmailTemplates.First(t => t.Description == "TransportationAllowanceApprovedwithRetroActive").TemplateNumber);//260 + else if (allowanceType == ecc_allowance_type.Transportation && (RetroActiveAmount == 0 || RetroActiveAmount == null)) + localDataTemplate = await GetTemplateDataAsync(_notificationSettings.EmailTemplates.First(t => t.Description == "TransportationAllowanceApprovedwithoutRetroActive").TemplateNumber);//290 - var patchResponse = await d365WebApiService.SendPatchRequestAsync(appUserService.AZSystemAppUser, emailStatement, requestBody1); + var serializedDataTemplate = JsonSerializer.Deserialize>(localDataTemplate.Data.ToString()); + _logger.LogInformation("Got the Template", serializedDataTemplate.Count); + + var templateobj = serializedDataTemplate?.FirstOrDefault(); + + string? subject = (string)templateobj?.subjectsafehtml; + subject = subject.Replace("#FANumber#", fundingNumber); + subject = StripHTML(subject); + + string? emaildescription = templateobj?.safehtml; + emaildescription = emaildescription?.Replace("[PrimaryContactName]", contactName); + emaildescription = emaildescription?.Replace("{Amount}", MonthlyAmount?.ToString()); + + //emaildescription = emaildescription?.Replace("{AllowanceType}", allowanceType.ToString()); + if (allowanceType == ecc_allowance_type.Transportation) + { + emaildescription = emaildescription?.Replace("{AllowanceStartDate}", effectiveDate?.ToString("MM/dd/yyyy")); + emaildescription = emaildescription?.Replace("{VINnumber}", VIN?.ToString()); + if (RetroActiveAmount > 0) + { + emaildescription = emaildescription?.Replace("{retroactiveAmount}", RetroActiveAmount?.ToString()); + emaildescription = emaildescription?.Replace("{retroactivedate}", retroActiveDate?.ToString("MM/dd/yyyy")); + } + } + + List recipientsList = new List(); + if (submittedBy != Guid.Empty) + { + _logger.LogInformation("Got the recipientsList submittedBy", submittedBy); + recipientsList.Add(submittedBy); + } + if (submittedBy != applicationPrimaryContact) + { + recipientsList.Add(applicationPrimaryContact); + } + //Task.Run(() => CreateAndUpdateEmail(subject, emaildescription, recipientsList, senderId, communicationType, appUserService, _d365webapiservice, processId)).Wait(); + // var result = Task.Run(() => CreateAndUpdateEmail(subject, emaildescription, recipientsList, senderId, communicationType, appUserService, _d365webapiservice, processId)).Result; + // await CreateAndUpdateEmail(subject, emaildescription, recipientsList, senderId, communicationType, appUserService, _d365webapiservice, processId); + //CreateAndUpdateEmail(subject, emaildescription, recipientsList, senderId, communicationType, appUserService, _d365webapiservice, processId).GetAwaiter().GetResult(); + + // if (task.Value != null) + + Guid? newEmailId = await CreateAndUpdateEmail(subject, emaildescription, recipientsList, senderId, communicationType, appUserService, _d365webapiservice, processId); + if (newEmailId != null) + await NotificationSentSupp(allowance.ofm_allowanceid, _d365webapiservice, processId); + + #region generate pdf for the email sent for approval + subject = "
     
    Subject: " + subject + "



    "; + emaildescription = string.Concat(Environment.NewLine, subject, Environment.NewLine, emaildescription); + SelectPdf.HtmlToPdf converter = new SelectPdf.HtmlToPdf(); + + try + { + SelectPdf.HtmlToPdfOptions options = new HtmlToPdfOptions(); + converter.Options.MarginTop = 100; converter.Options.MarginLeft = 50; converter.Options.MarginRight = 40; converter.Options.MarginBottom = 10; + converter.Options.PdfPageOrientation = PdfPageOrientation.Landscape; + converter.Options.PdfPageSize = PdfPageSize.A4; + SelectPdf.PdfDocument doc = converter.ConvertHtmlString(emaildescription); + byte[] bytes = doc.Save(); + HttpResponseMessage response1 = await _d365webapiservice.SendDocumentRequestAsync(_appUserService.AZPortalAppUser, ofm_allowance.EntitySetName, (Guid)allowance.ofm_allowanceid, bytes, string.Concat(allowanceNumber, ".pdf")); + + if (!response1.IsSuccessStatusCode) + { + var responseBody = await response1.Content.ReadAsStringAsync(); + _logger.LogError(CustomLogEvent.Process, "Failed to create notification pdf for approved supplementary the server error {responseBody}", responseBody.CleanLog()); + + //log the error + return await Task.FromResult(false); + + } + } + catch (Exception ex) + { + _logger.LogError(CustomLogEvent.Process, "Failed to create notification pdf for approved supplementary {responseBody}", ex.InnerException.Message); + + } + + #endregion + + } + if (allownaceStatusReason == (int)ofm_allowance_StatusCode.DeniedIneligible) + { + ProcessData localDataTemplate = null; + if (allowanceType == ecc_allowance_type.SupportNeedsProgramming) + // Get template details to create emails. + localDataTemplate = await GetTemplateDataAsync(_notificationSettings.EmailTemplates.First(t => t.Description == "SupportNeedsProgramAllowanceDenied").TemplateNumber);//275 + else if (allowanceType == ecc_allowance_type.IndigenousProgramming) + localDataTemplate = await GetTemplateDataAsync(_notificationSettings.EmailTemplates.First(t => t.Description == "IndigenousAllowanceDenied").TemplateNumber);//280 + else if (allowanceType == ecc_allowance_type.Transportation) + localDataTemplate = await GetTemplateDataAsync(_notificationSettings.EmailTemplates.First(t => t.Description == "TransportationAllowanceDenied").TemplateNumber);//285 + + var serializedDataTemplate = JsonSerializer.Deserialize>(localDataTemplate.Data.ToString()); + _logger.LogInformation("Got the Template", serializedDataTemplate.Count); + + var templateobj = serializedDataTemplate?.FirstOrDefault(); + + string? subject = (string)templateobj?.subjectsafehtml; + string? emaildescription = templateobj?.safehtml; + + List recipientsList = new List(); + if (submittedBy != Guid.Empty) + { + _logger.LogInformation("Got the recipientsList submittedBy", submittedBy); + recipientsList.Add(submittedBy); + } + if (submittedBy != applicationPrimaryContact) + { + recipientsList.Add(applicationPrimaryContact); + } + await CreateAndUpdateEmail(subject, emaildescription, recipientsList, senderId, communicationType, appUserService, _d365webapiservice, processId); + emailCreated = true; + + } + #endregion Create the Supp email notifications + + + return await Task.FromResult(emailCreated); + } + + public async Task NotificationSentSupp(Guid allowanceId, ID365WebApiService d365WebApiService, Int16 processId) + { + if (emailCreated) + { + var updateSupplementalUrl = @$"ofm_allowances({allowanceId})"; + var updateContent = new + { + ofm_notification_sent = true + }; + var requestBody = JsonSerializer.Serialize(updateContent); + var patchResponse = await d365WebApiService.SendPatchRequestAsync(_appUserService.AZSystemAppUser, updateSupplementalUrl, requestBody); + + _logger.LogDebug(CustomLogEvent.Process, "Update Supplemental Record {supplemental.ofm_allowanceid}", allowanceId); if (!patchResponse.IsSuccessStatusCode) { var responseBody = await patchResponse.Content.ReadAsStringAsync(); _logger.LogError(CustomLogEvent.Process, "Failed to patch the record with the server error {responseBody}", responseBody.CleanLog()); - - return; + // return ProcessResult.Failure(ProcessId, new String[] { responseBody }, 0, 0).SimpleProcessResult; } - }); - + } return ProcessResult.Completed(processId).SimpleProcessResult; } - #endregion + } \ No newline at end of file diff --git a/OFM.Infrastructure.WebAPI/Services/Processes/Emails/P240AllowanceApprovalDenialNotificationProvider.cs b/OFM.Infrastructure.WebAPI/Services/Processes/Emails/P240AllowanceApprovalDenialNotificationProvider.cs new file mode 100644 index 00000000..9504ea77 --- /dev/null +++ b/OFM.Infrastructure.WebAPI/Services/Processes/Emails/P240AllowanceApprovalDenialNotificationProvider.cs @@ -0,0 +1,152 @@ +using Microsoft.Extensions.Options; +using OFM.Infrastructure.WebAPI.Extensions; +using OFM.Infrastructure.WebAPI.Models; +using OFM.Infrastructure.WebAPI.Models.Fundings; +using OFM.Infrastructure.WebAPI.Services.AppUsers; +using OFM.Infrastructure.WebAPI.Services.D365WebApi; +using OFM.Infrastructure.WebAPI.Services.Processes.Fundings; +using System.Net; +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace OFM.Infrastructure.WebAPI.Services.Processes.Emails; + +public class P240AllowanceApprovalDenialNotificationProvider : ID365ProcessProvider +{ + const string EntityNameSet = "emails"; + private readonly NotificationSettings _notificationSettings; + private readonly ID365AppUserService _appUserService; + private readonly ID365WebApiService _d365webapiservice; + private readonly IFundingRepository _fundingRepository; + private readonly IEmailRepository _emailRepository; + private readonly ILogger _logger; + private readonly TimeProvider _timeProvider; + private ProcessData? _data; + private string[] _communicationTypesForEmailSentToUserMailBox = []; + private ProcessParameter? _processParams; + private string _requestUri = string.Empty; + private string? _fundingAgreementCommunicationType; + private string? _informationCommunicationType; + private Guid? _allowanceId; + private bool emailCreated = false; + + public P240AllowanceApprovalDenialNotificationProvider(IOptionsSnapshot notificationSettings, ID365AppUserService appUserService, ID365WebApiService d365WebApiService, ILoggerFactory loggerFactory, TimeProvider timeProvider, IFundingRepository fundingRepository, IEmailRepository emailRepository) + { + _notificationSettings = notificationSettings.Value; + _appUserService = appUserService; + _d365webapiservice = d365WebApiService; + _fundingRepository = fundingRepository; + _emailRepository = emailRepository; + _logger = loggerFactory.CreateLogger(LogCategory.Process); + _timeProvider = timeProvider; + } + + public Int16 ProcessId => Setup.Process.Emails.AllowanceApprovalDenialNotificationId; + public string ProcessName => Setup.Process.Emails.AllowanceApprovalDenialNotificationName; + + #region fetchxml queries + public string RequestUri + { + get + { + var fetchXml = $""" + + + + + + + + + + + + + + + + + + + + + + + + + + + + """; + + var requestUri = $""" + ofm_allowances?fetchXml={WebUtility.UrlEncode(fetchXml)} + """; + + return requestUri; + } + } + #endregion + + public async Task GetDataAsync() + { + _logger.LogDebug(CustomLogEvent.Process, "GetContactDataAsync"); + + var response = await _d365webapiservice.SendRetrieveRequestAsync(_appUserService.AZSystemAppUser, RequestUri); + + if (!response.IsSuccessStatusCode) + { + var responseBody = await response.Content.ReadAsStringAsync(); + _logger.LogError(CustomLogEvent.Process, "Failed to query Contact records with the server error {responseBody}", responseBody.CleanLog()); + + return await Task.FromResult(new ProcessData(string.Empty)); + } + + var jsonObject = await response.Content.ReadFromJsonAsync(); + + JsonNode d365Result = string.Empty; + if (jsonObject?.TryGetPropertyValue("value", out var currentValue) == true) + { + if (currentValue?.AsArray().Count == 0) + { + _logger.LogInformation(CustomLogEvent.Process, "No Contact records found with query {requestUri}", RequestUri.CleanLog()); + } + d365Result = currentValue!; + } + + _logger.LogDebug(CustomLogEvent.Process, "Query Result {queryResult}", d365Result.ToString().CleanLog()); + + return await Task.FromResult(new ProcessData(d365Result)); + } + + public async Task RunProcessAsync(ID365AppUserService appUserService, ID365WebApiService d365WebApiService, ProcessParameter processParams) + { + _processParams = processParams; + _allowanceId = _processParams.SupplementaryApplication.allowanceId; + + IEnumerable _communicationType = await _emailRepository!.LoadCommunicationTypeAsync(); + _informationCommunicationType = _communicationType.Where(c => c.ofm_communication_type_number == _notificationSettings.CommunicationTypes.Information) + .Select(s => s.ofm_communication_typeid).FirstOrDefault(); + var localData = await GetDataAsync(); + var deserializedData = JsonSerializer.Deserialize>(localData.Data.ToString()); + if (deserializedData == null || deserializedData.Count == 0) + { + _logger.LogInformation("No records returned from FetchXml", deserializedData.Count); + return ProcessResult.Completed(ProcessId).SimpleProcessResult; + } + try + { + await _emailRepository.CreateAllowanceEmail(deserializedData.First(), _processParams.Notification.SenderId, _informationCommunicationType, ProcessId, d365WebApiService); + } + catch (Exception ex) + { + _logger.LogError(CustomLogEvent.Process, "Failed to generate email notification for supplementary {responseBody}", ex.InnerException.Message); + + } + return ProcessResult.Completed(ProcessId).SimpleProcessResult; + + + } + + +} \ No newline at end of file diff --git a/tools/config/update-configmap.sh b/tools/config/update-configmap.sh index c289453a..8dadfcc7 100644 --- a/tools/config/update-configmap.sh +++ b/tools/config/update-configmap.sh @@ -167,7 +167,35 @@ D365_CONFIGURATION=$(jq << JSON { "TemplateNumber": 250, "Description": "Application Ineligible" - } + }, + { + "TemplateNumber": 240, + "Description": "SupportNeedsProgramAllowanceApproved" + }, + { + "TemplateNumber": 255, + "Description": "IndigenousAllowanceApproved" + }, + { + "TemplateNumber": 260, + "Description": "TransportationAllowanceApprovedwithRetroActive" + }, + { + "TemplateNumber": 290, + "Description": "TransportationAllowanceApprovedwithoutRetroActive" + }, + { + "TemplateNumber": 275, + "Description": "SupportNeedsProgramAllowanceDenied" + }, + { + "TemplateNumber": 280, + "Description": "IndigenousAllowanceDenied" + }, + { + "TemplateNumber": 285, + "Description": "TransportationAllowanceDenied" + } ], "CommunicationTypes": { "Information": 1,