Skip to content

Commit

Permalink
Merge pull request #516 from cabinetoffice/feature/DP-393-PPON-Servic…
Browse files Browse the repository at this point in the history
…e-Lookup-VAT-supplier-info

PPON Service - Lookup While adding VAT in supplier information
  • Loading branch information
dbgoaco committed Aug 30, 2024
2 parents 0fc76b7 + 153f476 commit 110cfcd
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using Amazon.S3;
using CO.CDP.EntityVerificationClient;
using CO.CDP.Organisation.WebApiClient;
using CO.CDP.OrganisationApp.Pages.Registration;
using CO.CDP.OrganisationApp.Pages.Supplier;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Moq;
Expand All @@ -10,12 +14,24 @@ namespace CO.CDP.OrganisationApp.Tests.Pages.Supplier;
public class SupplierVatModelQuestionTest
{
private readonly Mock<IOrganisationClient> _organisationClientMock;
private readonly Mock<IPponClient> _pponClientMock;
private static readonly Guid _organisationId = Guid.NewGuid();
private readonly SupplierVatQuestionModel _model;

public SupplierVatModelQuestionTest()
{
var httpContext = new DefaultHttpContext();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(_ => _.HttpContext).Returns(httpContext);

_organisationClientMock = new Mock<IOrganisationClient>();
_model = new SupplierVatQuestionModel(_organisationClientMock.Object);
_pponClientMock = new Mock<IPponClient>();
_model = new SupplierVatQuestionModel(_organisationClientMock.Object, _pponClientMock.Object, contextAccessor.Object);

_organisationClientMock.Setup(api => api.LookupOrganisationAsync(It.IsAny<string>(), It.IsAny<string>()))
.ThrowsAsync(new Organisation.WebApiClient.ApiException("Organisation does not exist", 404, "", null, null));
_pponClientMock.Setup(api => api.GetIdentifiersAsync(It.IsAny<string>()))
.ThrowsAsync(new EntityVerificationClient.ApiException("Organisation does not exist", 404, "", null, null));
}

[Fact]
Expand All @@ -41,7 +57,7 @@ public async Task OnGet_OrganisationNotFound_ReturnsRedirectToPageNotFound()
{
var id = Guid.NewGuid();
_organisationClientMock.Setup(client => client.GetOrganisationSupplierInformationAsync(id))
.ThrowsAsync(new ApiException("Unexpected error", 404, "", default, null));
.ThrowsAsync(new Organisation.WebApiClient.ApiException("Unexpected error", 404, "", default, null));

var result = await _model.OnGet(id);

Expand All @@ -66,6 +82,65 @@ public async Task OnPost_ValidModelState_ReturnsRedirectToSupplierBasicInformati
.Which.PageName.Should().Be("SupplierBasicInformation");
}

[Fact]
public async Task OnPost_WhenOrganisationExistsInOganisationService_ShouldRedirectToOrganisationAlreadyRegisteredPage()
{
var id = Guid.NewGuid();
_model.Id = id;
_model.HasVatNumber = true;
_model.VatNumber = "VAT12345";

_organisationClientMock.Setup(client => client.GetOrganisationAsync(id))
.ReturnsAsync(SupplierDetailsFactory.GivenOrganisationClientModel(id));

_organisationClientMock.Setup
(api => api.LookupOrganisationAsync(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(GivenOrganisationClientModel());

var result = await _model.OnPost();
result.Should().BeOfType<RedirectToPageResult>();
(result as RedirectToPageResult)?.PageName.Should().Be("/Registration/OrganisationAlreadyRegistered");
}

[Fact]
public async Task OnPost_WhenIdentifierExistsInEntityVerificationService_ShouldRedirectToOrganisationAlreadyRegisteredPage()
{
var id = Guid.NewGuid();
_model.Id = id;
_model.HasVatNumber = true;
_model.VatNumber = "VAT12345";

_organisationClientMock.Setup(client => client.GetOrganisationAsync(id))
.ReturnsAsync(SupplierDetailsFactory.GivenOrganisationClientModel(id));

_pponClientMock.Setup
(api => api.GetIdentifiersAsync(It.IsAny<string>()))
.ReturnsAsync(GivenEntityVerificationIdentifiers());

var result = await _model.OnPost();
result.Should().BeOfType<RedirectToPageResult>();
(result as RedirectToPageResult)?.PageName.Should().Be("/Registration/OrganisationAlreadyRegistered");
}

[Fact]
public async Task OnPost_WhenEntityVerificationServiceOffLine_ShouldRedirectToOrganisationServiceUnavailablePage()
{
var id = Guid.NewGuid();
_model.Id = id;
_model.HasVatNumber = true;
_model.VatNumber = "VAT12345";

_organisationClientMock.Setup(client => client.GetOrganisationAsync(id))
.ReturnsAsync(SupplierDetailsFactory.GivenOrganisationClientModel(id));

_pponClientMock.Setup(api => api.GetIdentifiersAsync(It.IsAny<string>()))
.ThrowsAsync(new Exception("Entity Verification service offline."));

var result = await _model.OnPost();
result.Should().BeOfType<RedirectToPageResult>();
(result as RedirectToPageResult)?.PageName.Should().Be("/Registration/OrganisationRegistrationUnavailable");
}

[Fact]
public async Task OnPost_InvalidModelState_ReturnsPageResult()
{
Expand All @@ -84,11 +159,21 @@ public async Task OnPost_OrganisationNotFound_ReturnsRedirectToPageNotFound()
_model.HasVatNumber = false;

_organisationClientMock.Setup(client => client.GetOrganisationAsync(id))
.ThrowsAsync(new ApiException("Unexpected error", 404, "", default, null));
.ThrowsAsync(new Organisation.WebApiClient.ApiException("Unexpected error", 404, "", default, null));

var result = await _model.OnPost();

result.Should().BeOfType<RedirectResult>().Which.Url.Should().Be("/page-not-found");
}

private static Organisation.WebApiClient.Organisation GivenOrganisationClientModel()
{
return new Organisation.WebApiClient.Organisation(null, null, null, _organisationId, null, "Test Org", []);
}

private static ICollection<EntityVerificationClient.Identifier> GivenEntityVerificationIdentifiers()
{
return new List<EntityVerificationClient.Identifier>() {
new EntityVerificationClient.Identifier("12345", "Acme Ltd", "VAT", new Uri("http://acme.org")) };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@

@model OrganisationAlreadyRegistered

<a href="@RegistrationStepModel.OrganisationIdentifierPage" class="govuk-back-link">Back</a>
@{
var backLink = RegistrationStepModel.OrganisationIdentifierPage;
var overrideBackLink = Request.Query.ContainsKey("backLink");

if (overrideBackLink)
{
backLink = Request.Query["backLink"];
}
}

<a href="@backLink" class="govuk-back-link">Back</a>

<main class="govuk-main-wrapper">
<div class="govuk-grid-row">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

@model OrganisationRegistrationUnavailable

<a href="@RegistrationStepModel.OrganisationIdentifierPage" class="govuk-back-link">Back</a>
@{
var backLink = RegistrationStepModel.OrganisationIdentifierPage;
var overrideBackLink = Request.Query.ContainsKey("backLink");

if (overrideBackLink)
{
backLink = Request.Query["backLink"];
}
}

<main class="govuk-main-wrapper">
<div class="govuk-grid-row">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
using CO.CDP.EntityVerificationClient;
using CO.CDP.Mvc.Validation;
using CO.CDP.Organisation.WebApiClient;
using CO.CDP.OrganisationApp.Models;
using CO.CDP.OrganisationApp.WebApiClients;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.ComponentModel.DataAnnotations;

namespace CO.CDP.OrganisationApp.Pages.Supplier;

[Authorize]
public class SupplierVatQuestionModel(IOrganisationClient organisationClient) : PageModel
public class SupplierVatQuestionModel(IOrganisationClient organisationClient,
IPponClient pponClient, IHttpContextAccessor httpContextAccessor) : PageModel
{
const string VatSchemeName = "VAT";

[BindProperty]
[Required(ErrorMessage = "Please select an option")]
public bool? HasVatNumber { get; set; }
Expand All @@ -31,15 +37,15 @@ public async Task<IActionResult> OnGet(Guid id)
if (composed.SupplierInfo.CompletedVat)
{
HasVatNumber = false;
var vatIdentifier = composed.Organisation.AdditionalIdentifiers.FirstOrDefault(i => i.Scheme == "VAT");
var vatIdentifier = composed.Organisation.AdditionalIdentifiers.FirstOrDefault(i => i.Scheme == VatSchemeName);
if (vatIdentifier != null)
{
HasVatNumber = !string.IsNullOrWhiteSpace(vatIdentifier.Id);
VatNumber = vatIdentifier.Id;
}
}
}
catch (ApiException ex) when (ex.StatusCode == 404)
catch (Organisation.WebApiClient.ApiException ex) when (ex.StatusCode == 404)
{
return Redirect("/page-not-found");
}
Expand All @@ -54,23 +60,69 @@ public async Task<IActionResult> OnPost()
return Page();
}

Organisation.WebApiClient.Organisation? organisation;
try
{
var organisation = await organisationClient.GetOrganisationAsync(Id);
organisation = await organisationClient.GetOrganisationAsync(Id);
}
catch (Organisation.WebApiClient.ApiException ex) when (ex.StatusCode == 404)
{
return Redirect("/page-not-found");
}

ICollection<OrganisationIdentifier> identifiers = [
ICollection<OrganisationIdentifier> identifiers = [
new OrganisationIdentifier(
id: HasVatNumber == true ? VatNumber : null,
legalName: organisation.Name,
scheme: "VAT")];
scheme: VatSchemeName)];

await organisationClient.UpdateOrganisationAdditionalIdentifiers(Id, identifiers);
if (HasVatNumber.GetValueOrDefault())
{
try
{
await LookupOrganisationAsync();
}
catch (Exception orgApiException) when (orgApiException is Organisation.WebApiClient.ApiException && ((Organisation.WebApiClient.ApiException)orgApiException).StatusCode == 404)
{
try
{
await LookupEntityVerificationAsync();
}
catch (Exception evApiException) when (evApiException is EntityVerificationClient.ApiException && ((EntityVerificationClient.ApiException)evApiException).StatusCode == 404)
{
await organisationClient.UpdateOrganisationAdditionalIdentifiers(Id, identifiers);
return RedirectToPage("SupplierBasicInformation", new { Id });
}
catch
{
return RedirectToPage("/Registration/OrganisationRegistrationUnavailable", SetRoute());
}
}
}
catch (ApiException ex) when (ex.StatusCode == 404)
else
{
return Redirect("/page-not-found");
return RedirectToPage("SupplierBasicInformation", new { Id });
}

return RedirectToPage("SupplierBasicInformation", new { Id });
return RedirectToPage("/Registration/OrganisationAlreadyRegistered", SetRoute());
}

private RouteValueDictionary SetRoute()
{
return new RouteValueDictionary
{
{ "backLink", httpContextAccessor!.HttpContext!.Request.Path }
};
}

private async Task<Organisation.WebApiClient.Organisation> LookupOrganisationAsync()
{
return await organisationClient.LookupOrganisationAsync(string.Empty,
$"{VatSchemeName}:{VatNumber}");
}

private async Task<ICollection<EntityVerificationClient.Identifier>> LookupEntityVerificationAsync()
{
return await pponClient.GetIdentifiersAsync($"{VatSchemeName}:{VatNumber}");
}
}

0 comments on commit 110cfcd

Please sign in to comment.