From dc620c82ab5c5cc6674a73111ed7edf14b4fd31b Mon Sep 17 00:00:00 2001 From: Jack Wong <108699279+bergomi02@users.noreply.github.com> Date: Fri, 28 Jun 2024 13:23:30 -0700 Subject: [PATCH] PRIME-2529 Fill missing organization registration id (#2483) * initial commit * fix PR issue * more fix * fix PR issues --- .../Controllers/JobsController.cs | 22 ++++++- .../Org Book API/IOrgBookClient.cs | 11 ++++ .../HttpClients/Org Book API/OrgBookClient.cs | 60 +++++++++++++++++++ .../Services/OrganizationService.cs | 30 +++++++++- .../interfaces/IOrganizationService.cs | 1 + prime-dotnet-webapi/Startup.cs | 2 + 6 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 prime-dotnet-webapi/HttpClients/Org Book API/IOrgBookClient.cs create mode 100644 prime-dotnet-webapi/HttpClients/Org Book API/OrgBookClient.cs diff --git a/prime-dotnet-webapi/Controllers/JobsController.cs b/prime-dotnet-webapi/Controllers/JobsController.cs index 47ce14dfb5..ec3c0145f9 100644 --- a/prime-dotnet-webapi/Controllers/JobsController.cs +++ b/prime-dotnet-webapi/Controllers/JobsController.cs @@ -15,10 +15,14 @@ namespace Prime.Controllers public class JobsController : PrimeControllerBase { private readonly IReportingService _reportingService; + private readonly IOrganizationService _organizationService; + public JobsController( - IReportingService reportingService) + IReportingService reportingService, + IOrganizationService organizationService) { _reportingService = reportingService; + _organizationService = organizationService; } // POST: api/jobs/populate/practitioner @@ -53,7 +57,6 @@ public async Task UpdatePractitionerTable() return Ok(result); } - // POST: api/jobs/populate/transaction-log-temp /// /// copy transaction log to temp table for reporting. @@ -77,5 +80,20 @@ public async Task PopulateTransactionLogTemp(int numberOfDays) var result = await _reportingService.PopulateTransactionLogTempAsync(numberOfDays); return Ok(result); } + + // POST: api/jobs/populate/organization-registration-id + /// + /// execute job to update organization registration ID where the registration ID is missing, then return the number of organizations updated. + /// + [HttpPost("populate/organization-registration-id", Name = nameof(UpdateMissingRegistrationIds))] + [Authorize(Roles = Roles.PrimeApiServiceAccount)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public async Task UpdateMissingRegistrationIds() + { + var result = await _organizationService.UpdateMissingRegistrationIds(); + return Ok(result); + } } } diff --git a/prime-dotnet-webapi/HttpClients/Org Book API/IOrgBookClient.cs b/prime-dotnet-webapi/HttpClients/Org Book API/IOrgBookClient.cs new file mode 100644 index 0000000000..6dfe3a3714 --- /dev/null +++ b/prime-dotnet-webapi/HttpClients/Org Book API/IOrgBookClient.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; + +using Prime.HttpClients.PharmanetCollegeApiDefinitions; + +namespace Prime.HttpClients +{ + public interface IOrgBookClient + { + Task GetOrgBookRegistrationIdAsync(string orgName); + } +} diff --git a/prime-dotnet-webapi/HttpClients/Org Book API/OrgBookClient.cs b/prime-dotnet-webapi/HttpClients/Org Book API/OrgBookClient.cs new file mode 100644 index 0000000000..767ae37f50 --- /dev/null +++ b/prime-dotnet-webapi/HttpClients/Org Book API/OrgBookClient.cs @@ -0,0 +1,60 @@ +using System; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using System.Web; +using Newtonsoft.Json.Linq; +using Microsoft.Extensions.Logging; + +namespace Prime.HttpClients +{ + public class OrgBookClient : BaseClient, IOrgBookClient + { + private readonly HttpClient _client; + private readonly ILogger _logger; + + public OrgBookClient(HttpClient client, + ILogger logger) + : base(PropertySerialization.CamelCase) + { + _client = client ?? throw new ArgumentNullException(nameof(client)); + _logger = logger; + } + + public async Task GetOrgBookRegistrationIdAsync(string orgName) + { + string registrationId = null; + HttpResponseMessage response = null; + try + { + response = await _client.GetAsync($"https://www.orgbook.gov.bc.ca/api/v2/search/credential/topic/facets?name=${HttpUtility.UrlEncode(orgName)}"); + } + catch (Exception ex) + { + _logger.LogError($"Exception: {ex.Message} for orgName: {orgName}"); + } + + if (response != null) + { + string searchResult = await response.Content.ReadAsStringAsync(); + + try + { + var json = JObject.Parse(searchResult); + + var objectResults = json["objects"]["results"].Where(r => r["topic"]["names"][0]["text"].ToString() == orgName); + if (objectResults.Count() > 0) + { + registrationId = objectResults.First()["topic"]["source_id"].ToString(); + } + } + catch (Exception ex) + { + _logger.LogError($"Exception: {ex.Message} for orgName: {orgName}"); + } + } + + return registrationId; + } + } +} diff --git a/prime-dotnet-webapi/Services/OrganizationService.cs b/prime-dotnet-webapi/Services/OrganizationService.cs index 0f01354e5c..b5ec597405 100644 --- a/prime-dotnet-webapi/Services/OrganizationService.cs +++ b/prime-dotnet-webapi/Services/OrganizationService.cs @@ -22,6 +22,7 @@ public class OrganizationService : BaseService, IOrganizationService private readonly IMapper _mapper; private readonly IOrganizationClaimService _organizationClaimService; private readonly IPartyService _partyService; + private readonly IOrgBookClient _orgBookClient; public OrganizationService( ApiDbContext context, @@ -30,7 +31,8 @@ public OrganizationService( IDocumentManagerClient documentClient, IMapper mapper, IOrganizationClaimService organizationClaimService, - IPartyService partyService) + IPartyService partyService, + IOrgBookClient orgBookClient) : base(context, logger) { _businessEventService = businessEventService; @@ -38,6 +40,7 @@ public OrganizationService( _mapper = mapper; _organizationClaimService = organizationClaimService; _partyService = partyService; + _orgBookClient = orgBookClient; } public async Task OrganizationExistsAsync(int organizationId) @@ -381,5 +384,30 @@ public async Task RemoveUnsignedOrganizationAgreementsAsync(int organizationId) _context.RemoveRange(pendingAgreements); await _context.SaveChangesAsync(); } + + // update organization registration ID calling OrgBook API with organization name in PRIME, then return the number of organizations updated + public async Task UpdateMissingRegistrationIds() + { + var targetOrganizations = await _context.Organizations.Where(o => o.RegistrationId == null) + .OrderBy(o => o.Id) + .ToListAsync(); + int numUpdated = 0; + if (targetOrganizations.Any()) + { + foreach (var org in targetOrganizations) + { + string registrationId = await _orgBookClient.GetOrgBookRegistrationIdAsync(org.Name); + if (registrationId != null) + { + org.RegistrationId = registrationId; + numUpdated++; + _logger.LogInformation($"Organization (ID:{org.Id}) registration ID is set to {registrationId}."); + } + } + await _context.SaveChangesAsync(); + } + + return numUpdated; + } } } diff --git a/prime-dotnet-webapi/Services/interfaces/IOrganizationService.cs b/prime-dotnet-webapi/Services/interfaces/IOrganizationService.cs index 925c155bfd..9711731c2c 100644 --- a/prime-dotnet-webapi/Services/interfaces/IOrganizationService.cs +++ b/prime-dotnet-webapi/Services/interfaces/IOrganizationService.cs @@ -29,5 +29,6 @@ public interface IOrganizationService Task RemoveUnsignedOrganizationAgreementsAsync(int organizationId); Task IsOrganizationTransferCompleteAsync(int organizationId); Task FlagPendingTransferIfOrganizationAgreementsRequireSignaturesAsync(int organizationId); + Task UpdateMissingRegistrationIds(); } } diff --git a/prime-dotnet-webapi/Startup.cs b/prime-dotnet-webapi/Startup.cs index 295e2bd16c..77b4d90427 100644 --- a/prime-dotnet-webapi/Startup.cs +++ b/prime-dotnet-webapi/Startup.cs @@ -221,6 +221,8 @@ private void ConfigureClients(IServiceCollection services) client.BaseAddress = new Uri(PrimeConfiguration.Current.VerifiableCredentialApi.Url.EnsureTrailingSlash()); client.DefaultRequestHeaders.Add("x-api-key", PrimeConfiguration.Current.VerifiableCredentialApi.Key); }); + + services.AddHttpClient(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.