using System.Xml.Linq; using CRIF.ACTion.Common; using CRIF.ACTion.Common.Parsers; using Serilog; using Landmark.OLA.Models.Decisioning; using Landmark.OLA.Models.Decisioning.Enums; namespace CRIF.ACTion.Decisioning { public class GetApplicationProductsResponseParser : IResponseParser { private string LoanApplicationId; private const string ApplicationsPath = "/actionAPI/getApplicationProducts/msg:appExportResponse/msg:applications/app:application"; private const string AppDetailsPath = "/app:application/app:appDetails"; private readonly XName AppDetailStatusesName = CrifNamespaces.App + "appDetailStatuses"; private readonly XName AppDetailStatusName = CrifNamespaces.App + "appDetailStatus"; private readonly XName StatusAttribute = CrifNamespaces.App + "statusType"; private const string DecisionTypeValue = "DecisionStatus"; private readonly XName DecisionResultName = CrifNamespaces.App + "status"; private readonly XName AppDetailStipulationsName = CrifNamespaces.App + "appDetailStipulations"; private readonly XName StipulationName = CrifNamespaces.App + "stipulation"; private readonly XName StipulationIdName = CrifNamespaces.Common + "stipulationID"; public GetApplicationProductsResponseParser() { } public void SetLoanId(string loanApplicationId) { LoanApplicationId = loanApplicationId; } public DecisioningDetails Parse(XElement xElement) { if (string.IsNullOrWhiteSpace(LoanApplicationId)) { throw new ArgumentException("Must set valid LoanApplicationId with SetLoanId(loanApplicationId)"); } var namespaceManager = CrifNamespaces.GetNamespaceManager(xElement); var applicationElement = xElement.XElementXPathSelectElement(ApplicationsPath, namespaceManager); if (applicationElement == null) { //CRIF didn't recognize this application ID throw new ArgumentException("The Application Id was not recognized by the decisioning system."); } if (!applicationElement.Attribute(CrifNamespaces.App + "applicationID").Value.Equals(LoanApplicationId)) { Log.Fatal("CRIF XML does not match expected loan ID {loanId}", LoanApplicationId); throw new InvalidOperationException("Unexpected vendor response."); } var appDetailElements = applicationElement.XElementXPathSelectElement(AppDetailsPath, namespaceManager).Elements().ToList(); for (int detailIndex = appDetailElements.Count - 1; detailIndex >= 0; detailIndex--) { var detail = appDetailElements[detailIndex]; var statuses = GetElementFromElement(detail, AppDetailStatusesName); var decision = GetElementFromElementWithAttributeIdentifier(statuses, AppDetailStatusName, StatusAttribute, DecisionTypeValue); if (decision == null) { appDetailElements.Remove(detail); continue; } var decisionResult = GetAttributeFromElement(decision, DecisionResultName); var status = (DecisioningResult)Enum.Parse(typeof(DecisioningResult), decisionResult.Value); if (status == DecisioningResult.DecisionStatus_Cancelled) { appDetailElements.Remove(detail); } } if (appDetailElements.Count != 1) { if (appDetailElements.Count == 0) { return new DecisioningDetails() { DecisioningState = DecisioningState.Unknown }; } throw new ArgumentException($"Application contains {appDetailElements.Count} appDetail elements. An appDetailID is required."); } var appDetailStatuses = GetElementFromElement(appDetailElements.SingleOrDefault(), AppDetailStatusesName); var decisionStatus = GetElementFromElementWithAttributeIdentifier(appDetailStatuses, AppDetailStatusName, StatusAttribute, DecisionTypeValue); var stipulations = GetStipulations(appDetailElements.Single().Element(AppDetailStipulationsName)); if (decisionStatus == null) { return new DecisioningDetails(stipulations) { DecisioningState = DecisioningState.Unknown, }; } else { var decisioningResult = GetAttributeFromElement(decisionStatus, DecisionResultName); var statusResult = (DecisioningResult)Enum.Parse(typeof(DecisioningResult), decisioningResult.Value); return new DecisioningDetails(stipulations) { DecisioningState = DecisioningState.Ready, DecisioningResult = statusResult, }; } } private ICollection GetStipulations(XElement appDetailStipulations) { var stipulations = new List(); if (appDetailStipulations is null) { return stipulations; } foreach (var stipulationElement in appDetailStipulations.Elements()) { var appDetailStipulation = stipulationElement.Element(StipulationName); var stipulationIdString = appDetailStipulation.Attribute(StipulationIdName).Value; if (int.TryParse(stipulationIdString, out int stipulationId)) { if (CrifConstants.StipulationsToShow.ContainsKey(stipulationId)) { stipulations.Add(stipulationId); } } } return stipulations; } private static XElement GetElementFromElement(XElement element, XName elementToFind) { return element.Element(elementToFind); } private static XElement GetElementFromElementWithAttributeIdentifier(XElement element, XName elementToSearch, XName attribute, string identifier) { return element.Elements(elementToSearch).SingleOrDefault(x => x.Attribute(attribute).Value.Equals(identifier)); } private static XAttribute GetAttributeFromElement(XElement element, XName attribute) { return element.Attribute(attribute); } } }