Skip to content

Commit

Permalink
feat(osp): add externalID and datecreated in registration network com…
Browse files Browse the repository at this point in the history
…panies api (#916)

change endpoint GET /api/administration/registration/network/companies
- add externalID field to the response body to represent the external identifier of the company.
- add dateCreated field to the response body to represent the creation date of the company record.
- add new (optional) query-parameter externalID to facilitate lookup using external identifiers.
- add new (optional) query parameter dateCreatedOrderFilter (values ASC, DESC) to specify order of result.
- implement sorting by dateCreated in both ascending (ASC) and descending (DESC) order.
---------
Co-authored-by: Norbert Truchsess <[email protected]>
  • Loading branch information
AnuragNagpure authored and evegufy committed Aug 13, 2024
1 parent 2949a32 commit 6ca675f
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public interface IRegistrationBusinessLogic
{
Task<CompanyWithAddressData> GetCompanyWithAddressAsync(Guid applicationId);
Task<Pagination.Response<CompanyApplicationDetails>> GetCompanyApplicationDetailsAsync(int page, int size, CompanyApplicationStatusFilter? companyApplicationStatusFilter, string? companyName);
Task<Pagination.Response<CompanyDetailsOspOnboarding>> GetOspCompanyDetailsAsync(int page, int size, CompanyApplicationStatusFilter? companyApplicationStatusFilter, string? companyName);
Task<Pagination.Response<CompanyDetailsOspOnboarding>> GetOspCompanyDetailsAsync(int page, int size, CompanyApplicationStatusFilter? companyApplicationStatusFilter, string? companyName, string? externalId, DateCreatedOrderFilter? dateCreatedOrderFilter);
Task<Pagination.Response<CompanyApplicationWithCompanyUserDetails>> GetAllCompanyApplicationsDetailsAsync(int page, int size, string? companyName);
Task UpdateCompanyBpn(Guid applicationId, string bpn);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,33 +162,37 @@ private async Task<CompanyWithAddressData> GetCompanyWithAddressAsyncInternal(Gu
.AsAsyncEnumerable()));
}

public Task<Pagination.Response<CompanyDetailsOspOnboarding>> GetOspCompanyDetailsAsync(int page, int size, CompanyApplicationStatusFilter? companyApplicationStatusFilter, string? companyName)
public Task<Pagination.Response<CompanyDetailsOspOnboarding>> GetOspCompanyDetailsAsync(int page, int size, CompanyApplicationStatusFilter? companyApplicationStatusFilter, string? companyName, string? externalId, DateCreatedOrderFilter? dateCreatedOrderFilter)
{
if (!string.IsNullOrEmpty(companyName) && !Company.IsMatch(companyName))
{
throw new ControllerArgumentException("CompanyName length must be 3-40 characters and *+=#%\\s not used as one of the first three characters in the company name", nameof(companyName));
}
var applications = portalRepositories.GetInstance<IApplicationRepository>()
var applicationsQuery = portalRepositories.GetInstance<IApplicationRepository>()
.GetExternalCompanyApplicationsFilteredQuery(_identityData.CompanyId,
companyName?.Length >= 3 ? companyName : null,
companyName?.Length >= 3 ? companyName : null, externalId,
GetCompanyApplicationStatusIds(companyApplicationStatusFilter));

var orderedQuery = dateCreatedOrderFilter == null || dateCreatedOrderFilter.Value == DateCreatedOrderFilter.DESC
? applicationsQuery.AsSplitQuery().OrderByDescending(application => application.DateCreated)
: applicationsQuery.AsSplitQuery().OrderBy(application => application.DateCreated);

return Pagination.CreateResponseAsync(
page,
size,
_settings.ApplicationsMaxPageSize,
(skip, take) => new Pagination.AsyncSource<CompanyDetailsOspOnboarding>(
applications.CountAsync(),
applications
.AsSplitQuery()
.OrderByDescending(application => application.DateCreated)
applicationsQuery.CountAsync(),
orderedQuery
.Skip(skip)
.Take(take)
.Select(application => new CompanyDetailsOspOnboarding(
application.CompanyId,
application.NetworkRegistration!.ExternalId,
application.Id,
application.ApplicationStatusId,
application.DateCreated,
application.Company!.DateCreated,
application.DateLastChanged,
application.Company!.Name,
application.Company.CompanyAssignedRoles.Select(companyAssignedRoles => companyAssignedRoles.CompanyRoleId),
Expand All @@ -211,7 +215,7 @@ private async Task<CompanyWithAddressData> GetCompanyWithAddressAsyncInternal(Gu
_settings.ApplicationsMaxPageSize,
(skip, take) => new Pagination.AsyncSource<CompanyApplicationWithCompanyUserDetails>(
applications.CountAsync(),
applications.OrderByDescending(application => application.DateCreated)
applications.OrderByDescending(application => application.Company!.DateCreated)
.Skip(skip)
.Take(take)
.Select(application => new
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ public async Task<NoContentResult> RetriggerDeleteCentralUser([FromRoute] Guid p
/// <param name="size">size to get number of records</param>
/// <param name="companyApplicationStatusFilter">Search by company applicationstatus</param>
/// <param name="companyName">search by company name</param>
/// <param name="externalId">search by external Id</param>
/// <param name="dateCreatedOrderFilter">sort result by dateCreated ascending or descending</param>
/// <returns>OSp Company Application Details</returns>
/// <remarks>
/// Example: GET: api/administration/registration/network/companies?companyName=Car&amp;page=0&amp;size=4&amp;companyApplicationStatus=Closed <br />
Expand All @@ -579,6 +581,7 @@ public async Task<NoContentResult> RetriggerDeleteCentralUser([FromRoute] Guid p
[Authorize(Policy = PolicyTypes.ValidCompany)]
[Route("network/companies")]
[ProducesResponseType(typeof(Pagination.Response<CompanyDetailsOspOnboarding>), StatusCodes.Status200OK)]
public Task<Pagination.Response<CompanyDetailsOspOnboarding>> GetOspCompanyDetailsAsync([FromQuery] int page, [FromQuery] int size, [FromQuery] CompanyApplicationStatusFilter? companyApplicationStatusFilter = null, [FromQuery] string? companyName = null) =>
_logic.GetOspCompanyDetailsAsync(page, size, companyApplicationStatusFilter, companyName);
public Task<Pagination.Response<CompanyDetailsOspOnboarding>> GetOspCompanyDetailsAsync([FromQuery] int page, [FromQuery] int size, [FromQuery] CompanyApplicationStatusFilter? companyApplicationStatusFilter = null, [FromQuery] string? companyName = null, [FromQuery] string? externalId = null, [FromQuery] DateCreatedOrderFilter? dateCreatedOrderFilter = null) =>
_logic.GetOspCompanyDetailsAsync(page, size, companyApplicationStatusFilter, companyName, externalId, dateCreatedOrderFilter);
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums;
namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models;

/// <summary>
/// Filter operations for the CompanyApplicationStatus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models;
public record CompanyDetailsOspOnboarding(

[property: JsonPropertyName("companyId")] Guid CompanyId,
[property: JsonPropertyName("externalId")] string? ExternalId,
[property: JsonPropertyName("applicationId")] Guid ApplicationId,
[property: JsonPropertyName("applicationStatus")] CompanyApplicationStatusId CompanyApplicationStatusId,
[property: JsonPropertyName("applicationDateCreated")] DateTimeOffset DateCreated,
[property: JsonPropertyName("applicationDateCreated")] DateTimeOffset ApplicationDateCreated,
[property: JsonPropertyName("dateCreated")] DateTimeOffset DateCreated,
[property: JsonPropertyName("lastChangedDate")] DateTimeOffset? DateLastChanged,
[property: JsonPropertyName("companyName")] string CompanyName,
[property: JsonPropertyName("companyRoles")] IEnumerable<CompanyRoleId> CompanyRoles,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/********************************************************************************
* Copyright (c) 2022 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models;

public enum DateCreatedOrderFilter
{
ASC,
DESC
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,13 @@ public IQueryable<CompanyApplication> GetCompanyApplicationsFilteredQuery(string
(companyName == null || EF.Functions.ILike(application.Company!.Name, $"{companyName.EscapeForILike()}%")) &&
(applicationStatusIds == null || applicationStatusIds.Contains(application.ApplicationStatusId)));

public IQueryable<CompanyApplication> GetExternalCompanyApplicationsFilteredQuery(Guid onboardingServiceProviderId, string? companyName, IEnumerable<CompanyApplicationStatusId> applicationStatusIds) =>
public IQueryable<CompanyApplication> GetExternalCompanyApplicationsFilteredQuery(Guid onboardingServiceProviderId, string? companyName, string? externalId, IEnumerable<CompanyApplicationStatusId> applicationStatusIds) =>
portalDbContext.CompanyApplications.AsNoTracking()
.Where(application =>
application.CompanyApplicationTypeId == CompanyApplicationTypeId.EXTERNAL &&
application.OnboardingServiceProviderId == onboardingServiceProviderId &&
(companyName == null || EF.Functions.ILike(application.Company!.Name, $"{companyName.EscapeForILike()}%")) &&
(externalId == null || application.NetworkRegistration!.ExternalId == externalId) &&
applicationStatusIds.Contains(application.ApplicationStatusId));

public Task<CompanyApplicationDetailData?> GetCompanyApplicationDetailDataAsync(Guid applicationId, Guid userCompanyId, Guid? companyId) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public interface IApplicationRepository
Task<(bool Exists, bool IsUserOfCompany, CompanyApplicationStatusId ApplicationStatus)> GetOwnCompanyApplicationStatusUserDataUntrackedAsync(Guid applicationId, Guid companyId);
Task<CompanyApplicationUserEmailData?> GetOwnCompanyApplicationUserEmailDataAsync(Guid applicationId, Guid companyUserId, IEnumerable<DocumentTypeId> submitDocumentTypeIds);
IQueryable<CompanyApplication> GetCompanyApplicationsFilteredQuery(string? companyName, IEnumerable<CompanyApplicationStatusId> applicationStatusIds);
IQueryable<CompanyApplication> GetExternalCompanyApplicationsFilteredQuery(Guid onboardingServiceProviderId, string? companyName, IEnumerable<CompanyApplicationStatusId> applicationStatusIds);
IQueryable<CompanyApplication> GetExternalCompanyApplicationsFilteredQuery(Guid onboardingServiceProviderId, string? companyName, string? externalId, IEnumerable<CompanyApplicationStatusId> applicationStatusIds);
Task<CompanyApplicationDetailData?> GetCompanyApplicationDetailDataAsync(Guid applicationId, Guid userCompanyId, Guid? companyId);
Task<(string CompanyName, string? FirstName, string? LastName, string? Email, IEnumerable<(Guid ApplicationId, CompanyApplicationStatusId ApplicationStatusId, IEnumerable<(string? FirstName, string? LastName, string? Email)> InvitedUsers)> Applications)> GetCompanyApplicationsDeclineData(Guid companyUserId, IEnumerable<CompanyApplicationStatusId> applicationStatusIds);
Task<(bool IsValidApplicationId, Guid CompanyId, bool IsSubmitted)> GetCompanyIdSubmissionStatusForApplication(Guid applicationId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public CompanyApplication(Guid id, Guid companyId, CompanyApplicationStatusId ap
public virtual Process? ChecklistProcess { get; set; }
public virtual CompanyApplicationType? CompanyApplicationType { get; set; }
public virtual Company? OnboardingServiceProvider { get; set; }
public virtual NetworkRegistration? NetworkRegistration { get; private set; }
public virtual NetworkRegistration? NetworkRegistration { get; set; }
public virtual Identity? LastEditor { get; private set; }
public virtual CompanyInvitation? CompanyInvitation { get; private set; }
public virtual ICollection<Invitation> Invitations { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,20 @@ public async Task GetCompanyApplicationDetailsAsync_WithClosedRequest_GetsExpect
#region GetOSPCompanyApplicationDetailsAsync

[Theory]
[InlineData(null)]
[InlineData(CompanyApplicationStatusFilter.Closed)]
[InlineData(CompanyApplicationStatusFilter.InReview)]
public async Task GetOspCompanyApplicationDetailsAsync_WithDefaultRequest_GetsExpectedEntries(CompanyApplicationStatusFilter? statusFilter)
[InlineData(null, null)]
[InlineData(null, DateCreatedOrderFilter.ASC)]
[InlineData(null, DateCreatedOrderFilter.DESC)]
[InlineData(CompanyApplicationStatusFilter.Closed, null)]
[InlineData(CompanyApplicationStatusFilter.InReview, null)]
[InlineData(CompanyApplicationStatusFilter.Closed, DateCreatedOrderFilter.ASC)]
[InlineData(CompanyApplicationStatusFilter.InReview, DateCreatedOrderFilter.ASC)]
[InlineData(CompanyApplicationStatusFilter.Closed, DateCreatedOrderFilter.DESC)]
[InlineData(CompanyApplicationStatusFilter.InReview, DateCreatedOrderFilter.DESC)]
public async Task GetOspCompanyApplicationDetailsAsync_WithDefaultRequest_GetsExpectedEntries(CompanyApplicationStatusFilter? statusFilter, DateCreatedOrderFilter? dateCreatedOrderFilter)
{
// Arrange
var companyName = _fixture.Create<string>();
var externalId = _fixture.Create<string>();
var data = _fixture.CreateMany<(Guid Id, Guid CompanyId, CompanyApplicationStatusId CompanyApplicationStatusId, DateTimeOffset Created)>(10)
.Select(x => new CompanyApplication(x.Id, x.CompanyId, x.CompanyApplicationStatusId, CompanyApplicationTypeId.EXTERNAL, x.Created)
{
Expand All @@ -207,42 +215,63 @@ public async Task GetOspCompanyApplicationDetailsAsync_WithDefaultRequest_GetsEx
Name = _fixture.Create<string>(),
BusinessPartnerNumber = _fixture.Create<string>(),
},
NetworkRegistration = new NetworkRegistration(Guid.NewGuid(), _fixture.Create<string>(), x.CompanyId, Guid.NewGuid(), Guid.NewGuid(), x.Id, x.Created)
{
ExternalId = _fixture.Create<string>(),
DateCreated = _fixture.Create<DateTimeOffset>(),
},
DateLastChanged = _fixture.Create<DateTimeOffset>()
}).ToImmutableList();

var queryData = new AsyncEnumerableStub<CompanyApplication>(data).AsQueryable();

A.CallTo(() => _applicationRepository.GetExternalCompanyApplicationsFilteredQuery(A<Guid>._, A<string?>._, A<IEnumerable<CompanyApplicationStatusId>>._))
A.CallTo(() => _applicationRepository.GetExternalCompanyApplicationsFilteredQuery(A<Guid>._, A<string?>._, A<string?>._, A<IEnumerable<CompanyApplicationStatusId>>._))
.Returns(queryData);

// Act
var result = await _logic.GetOspCompanyDetailsAsync(0, 3, statusFilter, null);
var result = await _logic.GetOspCompanyDetailsAsync(0, 3, statusFilter, companyName, externalId, dateCreatedOrderFilter);

// Assert
Assert.IsType<Pagination.Response<CompanyDetailsOspOnboarding>>(result);

switch (statusFilter)
{
case CompanyApplicationStatusFilter.Closed:
A.CallTo(() => _applicationRepository.GetExternalCompanyApplicationsFilteredQuery(CompanyId, null, A<IEnumerable<CompanyApplicationStatusId>>.That.IsSameSequenceAs(new[] { CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED }))).MustHaveHappenedOnceExactly();
A.CallTo(() => _applicationRepository.GetExternalCompanyApplicationsFilteredQuery(CompanyId, companyName, externalId, A<IEnumerable<CompanyApplicationStatusId>>.That.IsSameSequenceAs(new[] { CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED }))).MustHaveHappenedOnceExactly();
break;
case CompanyApplicationStatusFilter.InReview:
A.CallTo(() => _applicationRepository.GetExternalCompanyApplicationsFilteredQuery(CompanyId, null, A<IEnumerable<CompanyApplicationStatusId>>.That.IsSameSequenceAs(new[] { CompanyApplicationStatusId.SUBMITTED }))).MustHaveHappenedOnceExactly();
A.CallTo(() => _applicationRepository.GetExternalCompanyApplicationsFilteredQuery(CompanyId, companyName, externalId, A<IEnumerable<CompanyApplicationStatusId>>.That.IsSameSequenceAs(new[] { CompanyApplicationStatusId.SUBMITTED }))).MustHaveHappenedOnceExactly();
break;
default:
A.CallTo(() => _applicationRepository.GetExternalCompanyApplicationsFilteredQuery(CompanyId, null, A<IEnumerable<CompanyApplicationStatusId>>.That.IsSameSequenceAs(new[] { CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED }))).MustHaveHappenedOnceExactly();
A.CallTo(() => _applicationRepository.GetExternalCompanyApplicationsFilteredQuery(CompanyId, companyName, externalId, A<IEnumerable<CompanyApplicationStatusId>>.That.IsSameSequenceAs(new[] { CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED }))).MustHaveHappenedOnceExactly();
break;
}

result.Meta.NumberOfElements.Should().Be(10);

var sorted = data.OrderByDescending(application => application.DateCreated).ToImmutableArray();
var sorted = dateCreatedOrderFilter switch
{
DateCreatedOrderFilter.ASC => data.OrderBy(application => application.Company!.DateCreated).Take(3).ToImmutableArray(),
DateCreatedOrderFilter.DESC => data.OrderByDescending(application => application.Company!.DateCreated).Take(3).ToImmutableArray(),
_ => data.OrderByDescending(application => application.Company!.DateCreated).Take(3).ToImmutableArray()
};

result.Content.Should().HaveCount(3).And.Satisfy(
x => x.ApplicationId == sorted[0].Id && x.CompanyApplicationStatusId == sorted[0].ApplicationStatusId && x.DateCreated == sorted[0].DateCreated && x.DateLastChanged == sorted[0].DateLastChanged && x.CompanyId == sorted[0].CompanyId && x.CompanyName == sorted[0].Company!.Name && x.BusinessPartnerNumber == sorted[0].Company!.BusinessPartnerNumber,
x => x.ApplicationId == sorted[1].Id && x.CompanyApplicationStatusId == sorted[1].ApplicationStatusId && x.DateCreated == sorted[1].DateCreated && x.DateLastChanged == sorted[1].DateLastChanged && x.CompanyId == sorted[1].CompanyId && x.CompanyName == sorted[1].Company!.Name && x.BusinessPartnerNumber == sorted[1].Company!.BusinessPartnerNumber,
x => x.ApplicationId == sorted[2].Id && x.CompanyApplicationStatusId == sorted[2].ApplicationStatusId && x.DateCreated == sorted[2].DateCreated && x.DateLastChanged == sorted[2].DateLastChanged && x.CompanyId == sorted[2].CompanyId && x.CompanyName == sorted[2].Company!.Name && x.BusinessPartnerNumber == sorted[2].Company!.BusinessPartnerNumber
);

switch (dateCreatedOrderFilter)
{
case DateCreatedOrderFilter.ASC:
result.Content.Should().BeInAscendingOrder(x => x.DateCreated);
break;
case null:
case DateCreatedOrderFilter.DESC:
result.Content.Should().BeInDescendingOrder(x => x.DateCreated);
break;
}
}

#endregion
Expand Down
Loading

0 comments on commit 6ca675f

Please sign in to comment.