Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions app/DynamicsAdapter/DynamicsAdapter.Web/Mapping/Contructors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ public class Contructors
{
public static SearchRequestEntity ConstructSearchRequestEntity(SearchRequestOrdered src)
{
if (src?.Person?.Agency?.RequestId == null) throw new ArgumentNullException("SearchRequestOrdered.Person, Agency or RequestID are not allowed Null.");
if (src?.Person?.Agency?.RequestId == null)
{
throw new ArgumentNullException("SearchRequestOrdered.Person, Agency or RequestID are not allowed Null.");
}

SearchRequestEntity entity = new SearchRequestEntity();
#region agency part
entity.AgentEmail = src.Person.Agency.Email;
Expand All @@ -25,12 +29,14 @@ public static SearchRequestEntity ConstructSearchRequestEntity(SearchRequestOrde
else
entity.AgentFax = agencyFax?.PhoneNumber + " -" + agencyFax?.Extension;
}

if (src.Person.Agency.Agent != null)
{
Name agentName = src.Person.Agency.Agent;
entity.AgentFirstName = agentName.FirstName;
entity.AgentLastName = agentName.LastName;
}

if (src.Person.Agency.InformationRequested != null)
{
foreach (InformationRequested info in src.Person.Agency.InformationRequested)
Expand All @@ -55,9 +61,14 @@ public static SearchRequestEntity ConstructSearchRequestEntity(SearchRequestOrde
case InformationRequested.DateOfDeath: entity.DateOfDeathRequested = true; break;
case InformationRequested.IA: entity.IAStatusRequested = true; break;
case InformationRequested.SafetyConcern: entity.SafetyConcernRequested = true; break;
case InformationRequested.T1taxform: entity.T1taxform = true; break;
case InformationRequested.NoticeofAssessment: entity.NoticeofAssessment = true; break;
case InformationRequested.NoticeofReassessment: entity.NoticeofReassessment = true; break;
case InformationRequested.FinancialOtherIncome: entity.FinancialOtherIncome = true; break;
};
}
}

if (src.Person?.Agency.RequestId != null)
{
if (src.Person.Agency.RequestId.Length >= 30)
Expand All @@ -81,7 +92,6 @@ public static SearchRequestEntity ConstructSearchRequestEntity(SearchRequestOrde
}
#endregion


if (src.Person.Addresses != null)
{
Address applicantAddress = src.Person.Addresses.FirstOrDefault<Address>(m => m.Owner == OwnerType.Applicant);
Expand All @@ -104,6 +114,7 @@ public static SearchRequestEntity ConstructSearchRequestEntity(SearchRequestOrde
{
entity.ApplicantPhoneNumber = src.Person.Phones.FirstOrDefault<Phone>(m => m.Owner == OwnerType.Applicant)?.PhoneNumber;
}

if (src.Person.Identifiers != null)
{
entity.ApplicantSIN = src.Person.Identifiers.FirstOrDefault<PersonalIdentifier>(
Expand Down
3 changes: 3 additions & 0 deletions app/DynamicsAdapter/DynamicsAdapter.Web/Mapping/Resolvers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ public Agency Resolve(SSG_SearchApiRequest source, PersonSearchRequest destinati
ReasonCode = source.SearchRequest?.SearchReason?.ReasonCode switch
{
"EnfPayAgr" => SearchReasonCode.EnfPayAgr,
"ApplReasCd1" => SearchReasonCode.ApplReasCd1,
"ApplReasCd2" => SearchReasonCode.ApplReasCd2,
"ApplReasCd3" => SearchReasonCode.ApplReasCd3,
"ChngAccAgr" => SearchReasonCode.ChngAccAgr,
"ChngCustAg" => SearchReasonCode.ChngCustAg,
"AstRecpAgy" => SearchReasonCode.AstRecpAgy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,58 +43,109 @@ ISearchRequestRegister register
[OpenApiTag("Agency Search Request API")]
public async Task<IActionResult> CreateSearchRequest(string requestId, [FromBody]SearchRequestOrdered searchRequestOrdered)
{
using (LogContext.PushProperty("RequestRef", $"{requestId}"))
using (LogContext.PushProperty("AgencyCode", $"{searchRequestOrdered?.Person?.Agency?.Code}"))
using (LogContext.PushProperty("RequestRef", requestId ?? "(null)"))
using (LogContext.PushProperty("AgencyCode", searchRequestOrdered?.Person?.Agency?.Code))
{
_logger.LogInformation("Get CreateSearchRequest");
_logger.LogDebug(JsonConvert.SerializeObject(searchRequestOrdered));
if (string.IsNullOrEmpty(requestId)) return BadRequest(new { ReasonCode = "error", Message = "requestId cannot be empty." });
if (searchRequestOrdered == null) return BadRequest(new { ReasonCode = "error", Message = "SearchRequestOrdered cannot be empty." });
if (searchRequestOrdered.Action != RequestAction.NEW) return BadRequest(new { ReasonCode = "error", Message = "CreateSearchRequest should only get NEW request." });
_logger.LogInformation("➡️ Start CreateSearchRequest for RequestId: {RequestId}", requestId);

if (string.IsNullOrEmpty(requestId))
{
_logger.LogWarning("❌ requestId is missing.");
return BadRequest(new { ReasonCode = "error", Message = "requestId cannot be empty." });
}

if (searchRequestOrdered == null)
{
_logger.LogWarning("❌ SearchRequestOrdered payload is missing.");
return BadRequest(new { ReasonCode = "error", Message = "SearchRequestOrdered cannot be empty." });
}

if (searchRequestOrdered.Action != RequestAction.NEW)
{
_logger.LogWarning(
"❌ CreateSearchRequest should only receive NEW action, received: {Action}",
searchRequestOrdered.Action);

return BadRequest(new
{
ReasonCode = "error",
Message = "CreateSearchRequest should only get NEW request."
});
}

SSG_SearchRequest createdSearchRequest = null;
try
{
_logger.LogDebug("Processing SearchRequestOrdered via AgencyRequestService...");
createdSearchRequest = await _agencyRequestService.ProcessSearchRequestOrdered(searchRequestOrdered);

if (createdSearchRequest == null)
{
_logger.LogError("❌ _agencyRequestService returned NULL for ProcessSearchRequestOrdered");
return StatusCode(StatusCodes.Status500InternalServerError);
}

_logger.LogInformation("SearchRequest is created successfully.");

_logger.LogInformation(
"SearchRequest created successfully. SearchRequestId: {SearchRequestId}",
createdSearchRequest.SearchRequestId);
}
catch (AgencyRequestException ex)
{
_logger.LogInformation(ex.Message);
_logger.LogError(ex,
"❌ AgencyRequestException while creating SearchRequest. Reason: {Reason}",
ex.Message);
return StatusCode(StatusCodes.Status500InternalServerError, new { ReasonCode = ex.Message, Message = ex.InnerException?.Message });
}
catch (Exception ex)
{
_logger.LogError(ex, "❌ Unexpected error while creating SearchRequest.");

SSG_SearchRequest createdSR = _agencyRequestService.GetSSGSearchRequest();
if (createdSR != null)
{
_logger.LogWarning("Rolling back: cancelling partially created SSG_SearchRequest {SearchRequestId}", createdSR.SearchRequestId);
await _agencyRequestService.SystemCancelSSGSearchRequest(createdSR);
}
if( ex is Simple.OData.Client.WebRequestException)

if( ex is Simple.OData.Client.WebRequestException webEx)
{
_logger.LogError(((Simple.OData.Client.WebRequestException)ex).RequestUri?.AbsoluteUri);
_logger.LogError(((Simple.OData.Client.WebRequestException)ex).Response);
_logger.LogError("OData RequestUri: {Uri}", webEx.RequestUri?.AbsoluteUri);
_logger.LogError("OData Response: {Response}", webEx.Response);
}
_logger.LogError(ex.Message);

return StatusCode(StatusCodes.Status500InternalServerError, new { ReasonCode = ex.Message, Message = ex.InnerException?.Message });
}

//try to submit to queue and then get EstimatedDate and positionInQueue
try
{
_logger.LogDebug(
"Submitting SearchRequest {SearchRequestId} to queue...",
createdSearchRequest.SearchRequestId);

await _agencyRequestService.SubmitSearchRequestToQueue(createdSearchRequest.SearchRequestId);
createdSearchRequest = await _agencyRequestService.RefreshSearchRequest(createdSearchRequest.SearchRequestId);
}catch(Exception e)

_logger.LogInformation(
"SearchRequest submitted to queue successfully. SearchRequestId: {SearchRequestId}",
createdSearchRequest.SearchRequestId);
}catch(Exception ex)
{
_logger.LogError(e, "submit to queue or get current search request failed.");
_logger.LogError(ex,
"❌ Failed to submit SearchRequest {SearchRequestId} to queue.",
createdSearchRequest.SearchRequestId);
//default value, in case there is error, we still can return accept event.
createdSearchRequest.EstimatedCompletionDate = DateTime.UtcNow.AddMonths(3);
createdSearchRequest.QueuePosition = 9999;
}

_logger.LogInformation(
"Returning SearchRequestSaved event for RequestId {RequestId}",
requestId);
_logger.LogDebug(
"🏁 End CreateSearchRequest for RequestId: {RequestId}",
requestId);

return Ok(BuildSearchRequestSaved_Create(createdSearchRequest, searchRequestOrdered));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,24 +61,38 @@ public AgencyRequestService(ISearchRequestService searchRequestService, ILogger<

public async Task<SSG_SearchRequest> ProcessSearchRequestOrdered(SearchRequestOrdered searchRequestOrdered)
{
_logger.LogDebug("➡️ Start ProcessSearchRequestOrdered for RequestId {RequestId}", searchRequestOrdered.RequestId);

if (searchRequestOrdered == null)
{
_logger.LogError("❌ SearchRequestOrdered cannot be null.");
throw new ArgumentNullException(nameof(searchRequestOrdered));
}

_personSought = searchRequestOrdered.Person;
var cts = new CancellationTokenSource();
_cancellationToken = cts.Token;

SearchRequestEntity searchRequestEntity = _mapper.Map<SearchRequestEntity>(searchRequestOrdered);
searchRequestEntity.CreatedByApi = true;
searchRequestEntity.SendNotificationOnCreation = true;

_uploadedSearchRequest = await _searchRequestService.CreateSearchRequest(searchRequestEntity, cts.Token);
if (_uploadedSearchRequest == null) return null;
_logger.LogInformation("Create Search Request successfully");
if (_uploadedSearchRequest == null)
{
_logger.LogWarning("⚠️ CreateSearchRequest returned null");
return null;
}

_logger.LogInformation("Created base Search Request successfully. FileId: {FileId}", _uploadedSearchRequest?.FileId);

PersonEntity personEntity = _mapper.Map<PersonEntity>(_personSought);
personEntity.SearchRequest = _uploadedSearchRequest;
personEntity.InformationSource = InformationSourceType.Request.Value;
personEntity.IsCreatedByAgency = true;
personEntity.IsPrimary = true;
_uploadedPerson = await _searchRequestService.SavePerson(personEntity, _cancellationToken);
_logger.LogInformation("Create Person successfully");
_logger.LogInformation("Created Person successfully");

await UploadIdentifiers();
await UploadAddresses();
Expand All @@ -88,6 +102,9 @@ public async Task<SSG_SearchRequest> ProcessSearchRequestOrdered(SearchRequestOr
await UploadRelatedApplicant(_uploadedSearchRequest.ApplicantFirstName, _uploadedSearchRequest.ApplicantLastName);
await UploadAliases();
await UploadSafetyConcern();

_logger.LogDebug("🏁 End ProcessSearchRequestOrdered for RequestId {RequestId}", searchRequestOrdered.RequestId);

return _uploadedSearchRequest;
}

Expand Down
18 changes: 16 additions & 2 deletions app/DynamicsAdapter/DynamicsAdapter.Web/searchApi.openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,9 @@
"ChngPayAgr",
"EnfPayAgND",
"ChildAbduc",
"ApplReasCd1",
"ApplReasCd2",
"ApplReasCd3",
"AstRecpAgy",
"Unknown",
"Other"
Expand All @@ -517,6 +520,9 @@
"ChngPayAgr",
"EnfPayAgND",
"ChildAbduc",
"ApplReasCd1",
"ApplReasCd2",
"ApplReasCd3",
"AstRecpAgy",
"Unknown",
"Other"
Expand All @@ -536,7 +542,11 @@
"Carceration",
"DateOfDeath",
"IA",
"SafetyConcern"
"SafetyConcern",
"T1taxform",
"NoticeofAssessment",
"NoticeofReassessment",
"FinancialOtherIncome"
],
"enum": [
"Asset",
Expand All @@ -549,7 +559,11 @@
"Carceration",
"DateOfDeath",
"IA",
"SafetyConcern"
"SafetyConcern",
"T1taxform",
"NoticeofAssessment",
"NoticeofReassessment",
"FinancialOtherIncome"
]
},
"Name": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.Extensions.Logging;
using Simple.OData.Client;
using System;

namespace Fams3Adapter.Dynamics.Error
{
public static class DynamicsApiErrorLogger
{
public static void LogDynamicsError(Exception ex, ILogger logger)
{
logger.LogError(ex, "❌ Dynamics operation failed");

var inner = ex.InnerException;
while (inner != null)
{
logger.LogError("⛔ InnerException: {Message}", inner.Message);
inner = inner.InnerException;
}

if (ex is WebRequestException webEx && webEx.Response != null)
{
try
{
logger.LogError("📝 OData Response Content:\n{Response}", webEx.Response);
}
catch { }
}
}
}
}
Loading
Loading