using System; using System.Net; using System.Threading.Tasks; using Serilog; using Microsoft.AspNetCore.Mvc; using CRIF.ACTion.Services.Crif; using Landmark.OLA.Application.Common.Security; using Landmark.OLA.Application.DataAccessLayer; using Landmark.OLA.Models.Decisioning; using Landmark.OLA.Models.Decisioning.Enums; using Landmark.OLA.Models.Loan.Enums; namespace Landmark.OLA.Application.Controllers { [Route("api/LoanApplication/{loanApplicationId}/DecisioningDetails")] [ApiController] public class DecisioningController : ControllerBase { private readonly ICrifVendorClient VendorClient; private readonly ILoanApplicationDataAccess LoanApplicationStorage; public DecisioningController( ICrifVendorClient vendorClient, ILoanApplicationDataAccess loanApplicationDataAccess) { VendorClient = vendorClient; LoanApplicationStorage = loanApplicationDataAccess; } /// /// Use to start decisioning on a loan /// /// /// Returns status of decision start, on 202 you can begin requesting details. /// Cookies: Will expire existing cookies. /// Security: None required or provided. /// // PUT: api/Application/{loanApplicationId}/DecisioningDetails [HttpPut] [ProducesResponseType(202)] [ProducesResponseType(400)] [ProducesResponseType(500)] public async Task Put(string loanApplicationId, [FromBody] DecisioningDetails decisioningDetails) { if (decisioningDetails.DecisioningState != DecisioningState.Requested) { Log.Error("DecisioningState was not set to Requested."); return BadRequest("Must PUT a DecisioningState of Requested."); } Log.Information($"Sending loan {loanApplicationId} to decisioning."); try { var decisioningRequestSuccess = await VendorClient.SendToDecisioning(loanApplicationId); if (decisioningRequestSuccess) { CookieService.ExpireCookies(HttpContext); return new AcceptedResult(); } else { // SendToDecisioning did not succeed, "That's an error. That's all we know.", Check the server logs! Log.Error($"Loan #{loanApplicationId} could not be submitted to decisioning."); return StatusCode((int) System.Net.HttpStatusCode.InternalServerError); } } catch (TimeoutException te) { Log.Error(te.Message); return BadRequest( "The time taken to submit the loan application to the vendor has exceeded the configured timeout length."); } catch (InvalidOperationException ioe) { Log.Error(ioe.Message); return BadRequest(ioe.Message); } catch (Exception e) { Log.Error(e.Message); return StatusCode((int) HttpStatusCode.InternalServerError); } } /// /// Use to get details of a decision /// /// /// Returns a decision status, which may be empty if the decision is not ready. /// Cookies: None required or set. /// Security: None required or provided. /// // GET: api/Application/{loanApplicationId}/DecisioningDetails [HttpGet] [ProducesResponseType(typeof(DecisioningDetails), 200)] [ProducesResponseType(400)] [ProducesResponseType(500)] public async Task Get(string loanApplicationId) { try { var decisioningResult = await VendorClient.GetDecisionStatus(loanApplicationId); if (decisioningResult.DecisioningState == DecisioningState.Ready) { var cosmosId = LoanApplicationStorage.GetContainerIdByLoanId(loanApplicationId); LoanApplicationStorage.UpdateStatus(cosmosId, LoanStatus.Decisioned); } return Ok(decisioningResult); } catch (TimeoutException te) { Log.Error(te.Message); return BadRequest( "The time taken to decision the loan application has exceeded the configured timeout length."); } catch (ArgumentException ae) { Log.Error(ae.Message); return BadRequest(ae.Message); } catch (Error13Exception e13) { // We will remove these logs on Log.Error(e13.Message); var decisionResult = new DecisioningDetails() { DecisioningState = DecisioningState.Unknown, DecisioningResult = DecisioningResult.ProcessStatus_Incomplete }; return Ok(decisionResult); } catch (Exception e) { Log.Error(e.Message); return StatusCode((int) HttpStatusCode.InternalServerError); } } } }