diff --git a/src/administration/Administration.Service/BusinessLogic/CompanyDataBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/CompanyDataBusinessLogic.cs index 88f0ee94bb..a30af520ee 100644 --- a/src/administration/Administration.Service/BusinessLogic/CompanyDataBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/CompanyDataBusinessLogic.cs @@ -578,6 +578,28 @@ await _mailingService.SendMails(requesterEmail, mailParameters, Enumerable.Repea public IAsyncEnumerable GetCertificateTypes() => _portalRepositories.GetInstance().GetCertificateTypes(_identityData.CompanyId); + /// + public async IAsyncEnumerable GetCompanyCertificatesByBpn(string businessPartnerNumber) + { + if (string.IsNullOrWhiteSpace(businessPartnerNumber)) + { + throw new ControllerArgumentException("businessPartnerNumber must not be empty"); + } + + var companyCertificateRepository = _portalRepositories.GetInstance(); + + var companyId = await companyCertificateRepository.GetCompanyIdByBpn(businessPartnerNumber).ConfigureAwait(false); + if (companyId == Guid.Empty) + { + throw new ControllerArgumentException($"company does not exist for {businessPartnerNumber}"); + } + + await foreach (var data in companyCertificateRepository.GetCompanyCertificateData(companyId)) + { + yield return data; + } + } + public Task> GetAllCompanyCertificatesAsync(int page, int size, CertificateSorting? sorting, CompanyCertificateStatusId? certificateStatus, CompanyCertificateTypeId? certificateType) => Pagination.CreateResponseAsync( page, diff --git a/src/administration/Administration.Service/BusinessLogic/ICompanyDataBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/ICompanyDataBusinessLogic.cs index 14fb22eaed..f99c8629ad 100644 --- a/src/administration/Administration.Service/BusinessLogic/ICompanyDataBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/ICompanyDataBusinessLogic.cs @@ -53,7 +53,7 @@ public interface ICompanyDataBusinessLogic Task RejectCredential(Guid credentialId); IAsyncEnumerable GetCertificateTypes(); - + IAsyncEnumerable GetCompanyCertificatesByBpn(string businessPartnerNumber); Task CreateCompanyCertificate(CompanyCertificateCreationData data, CancellationToken cancellationToken); Task> GetAllCompanyCertificatesAsync(int page, int size, CertificateSorting? sorting, CompanyCertificateStatusId? certificateStatus, CompanyCertificateTypeId? certificateType); diff --git a/src/administration/Administration.Service/Controllers/CompanyDataController.cs b/src/administration/Administration.Service/Controllers/CompanyDataController.cs index 132faa3102..a29ae89001 100644 --- a/src/administration/Administration.Service/Controllers/CompanyDataController.cs +++ b/src/administration/Administration.Service/Controllers/CompanyDataController.cs @@ -293,6 +293,23 @@ public async Task CreateCompanyCertificate([FromForm] CompanyCe return NoContent(); } + /// + /// Gets the companyCertificates Details + /// + /// the companyCertificates details + /// Example: GET: api/administration/companydata/businessPartnerNumber}/companyCertificates + /// Returns the companyCertificates details. + [HttpGet] + [Authorize(Roles = "view_certificates")] + [Authorize(Policy = PolicyTypes.ValidCompany)] + [Route("company/{businessPartnerNumber}/companyCertificates")] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status409Conflict)] + public IAsyncEnumerable GetCompanyCertificatesByBpn(string businessPartnerNumber) => + _logic.GetCompanyCertificatesByBpn(businessPartnerNumber); + /// /// Retrieves all company certificates with respect userId. /// diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyCertificateBpnData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyCertificateBpnData.cs new file mode 100644 index 0000000000..ba98c67a83 --- /dev/null +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyCertificateBpnData.cs @@ -0,0 +1,31 @@ +/******************************************************************************** + * Copyright (c) 2021, 2024 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 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; +using System.Reflection.Metadata; + +namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; + +public record CompanyCertificateBpnData( + CompanyCertificateTypeId CompanyCertificateType, + CompanyCertificateStatusId CompanyCertificateStatus, + Guid DocumentId, + DateTimeOffset ValidFrom, + DateTimeOffset? ValidTill +); diff --git a/src/portalbackend/PortalBackend.DBAccess/PortalBackend.DBAccess.csproj b/src/portalbackend/PortalBackend.DBAccess/PortalBackend.DBAccess.csproj index 598e4dea3d..9a86f3e25a 100644 --- a/src/portalbackend/PortalBackend.DBAccess/PortalBackend.DBAccess.csproj +++ b/src/portalbackend/PortalBackend.DBAccess/PortalBackend.DBAccess.csproj @@ -1,45 +1,45 @@ - - - - - Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess - Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess - net7.0 - enable - enable - - - - - - - - - - - - - - - - - - + + + + + Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess + Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess + net7.0 + enable + enable + + + + + + + + + + + + + + + + + + diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyCertificateRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyCertificateRepository.cs index fcfc6d9773..a91fc8f23e 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyCertificateRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyCertificateRepository.cs @@ -21,6 +21,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; @@ -52,6 +53,25 @@ public CompanyCertificate CreateCompanyCertificate(Guid companyId, CompanyCertif return _context.CompanyCertificates.Add(companyCertificate).Entity; } + /// + public Task GetCompanyIdByBpn(string businessPartnerNumber) => + _context.Companies + .Where(x => x.BusinessPartnerNumber == businessPartnerNumber) + .Select(x => x.Id) + .SingleOrDefaultAsync(); + + /// + public IAsyncEnumerable GetCompanyCertificateData(Guid companyId) => + _context.CompanyCertificates + .Where(x => x.CompanyId == companyId && x.CompanyCertificateStatusId == CompanyCertificateStatusId.ACTIVE) + .Select(ccb => new CompanyCertificateBpnData( + ccb.CompanyCertificateTypeId, + ccb.CompanyCertificateStatusId, + ccb.DocumentId, + ccb.ValidFrom, + ccb.ValidTill)) + .ToAsyncEnumerable(); + public Func?>> GetActiveCompanyCertificatePaginationSource(CertificateSorting? sorting, CompanyCertificateStatusId? certificateStatus, CompanyCertificateTypeId? certificateType, Guid companyId) => (skip, take) => Pagination.CreateSourceQueryAsync( skip, @@ -60,7 +80,6 @@ public CompanyCertificate CreateCompanyCertificate(Guid companyId, CompanyCertif .AsNoTracking() .Where(x => x.CompanyId == companyId && - x.CompanyCertificateStatusId == CompanyCertificateStatusId.ACTIVE && (certificateStatus == null || x.CompanyCertificateStatusId == certificateStatus) && (certificateType == null || x.CompanyCertificateTypeId == certificateType)) .GroupBy(x => x.CompanyId), diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyCertificateRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyCertificateRepository.cs index 0cd34d68ca..400cd1b1f6 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyCertificateRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyCertificateRepository.cs @@ -19,7 +19,9 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; @@ -43,6 +45,20 @@ public interface ICompanyCertificateRepository /// The created entity CompanyCertificate CreateCompanyCertificate(Guid companyId, CompanyCertificateTypeId companyCertificateTypeId, Guid docId, Action? setOptionalFields = null); + /// + /// Get companyId against businessPartnerNumber + /// + /// bpn Id + /// company entity + Task GetCompanyIdByBpn(string businessPartnerNumber); + + /// + /// Gets company certificate details + /// + /// Id of the company + /// Returns the CompanyCertificateBpnData Details + IAsyncEnumerable GetCompanyCertificateData(Guid companyId); + /// /// Gets all company certificate data from the persistence storage as pagination /// diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/CompanyDataBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/CompanyDataBusinessLogicTests.cs index b8b1ffb6b7..53de568ba0 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/CompanyDataBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/CompanyDataBusinessLogicTests.cs @@ -1071,6 +1071,78 @@ public async Task CheckCompanyCertificateType_WithInvalidCall_ThrowsControllerAr } #endregion + #region GetCompanyCertificateWithBpnNumber + + [Fact] + public async Task GetCompanyCertificateWithNullOrEmptyBpn_ReturnsExpected() + { + // Act + async Task Act() => await _sut.GetCompanyCertificatesByBpn(string.Empty).ToListAsync().ConfigureAwait(false); + + // Assert + var error = await Assert.ThrowsAsync(Act).ConfigureAwait(false); + error.Message.Should().StartWith("businessPartnerNumber must not be empty"); + } + + [Fact] + public async Task GetCompanyCertificateWithNoCompanyId_ReturnsExpected() + { + // Arrange + var companyId = Guid.Empty; + var businessPartnerNumber = "BPNL07800HZ01644"; + + A.CallTo(() => _companyCertificateRepository.GetCompanyIdByBpn(businessPartnerNumber)) + .Returns(companyId); + + // Act + async Task Act() => await _sut.GetCompanyCertificatesByBpn(businessPartnerNumber).ToListAsync().ConfigureAwait(false); + + // Assert + var error = await Assert.ThrowsAsync(Act).ConfigureAwait(false); + error.Message.Should().StartWith($"company does not exist for {businessPartnerNumber}"); + } + + [Fact] + public async Task GetCompanyCertificateWithBpnNumber_WithValidRequest_ReturnsExpected() + { + // Arrange + var companyId = Guid.NewGuid(); + var data = _fixture.Build() + .With(x => x.CompanyCertificateStatus, CompanyCertificateStatusId.ACTIVE) + .With(x => x.CompanyCertificateType, CompanyCertificateTypeId.ISO_9001) + .With(x => x.DocumentId, Guid.NewGuid()) + .With(x => x.ValidFrom, DateTime.UtcNow) + .With(x => x.ValidTill, DateTime.UtcNow) + .CreateMany(5).ToAsyncEnumerable(); + A.CallTo(() => _companyCertificateRepository.GetCompanyIdByBpn("BPNL07800HZ01643")) + .Returns(companyId); + A.CallTo(() => _companyCertificateRepository.GetCompanyCertificateData(companyId)) + .Returns(data); + + // Act + var result = await _sut.GetCompanyCertificatesByBpn("BPNL07800HZ01643").ToListAsync().ConfigureAwait(false); + + // Assert + result.Should().HaveCount(5); + } + + [Fact] + public async Task GetCompanyCertificateWithBpnNumber_WithEmptyResult_ReturnsExpected() + { + // Arrange + var companyId = Guid.NewGuid(); + A.CallTo(() => _companyCertificateRepository.GetCompanyIdByBpn("BPNL07800HZ01643")) + .Returns(companyId); + + // Act + var result = await _sut.GetCompanyCertificatesByBpn("BPNL07800HZ01643").ToListAsync().ConfigureAwait(false); + + // Assert + result.Should().BeEmpty(); + } + + #endregion + #region GetCredentials [Fact] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyCertificateRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyCertificateRepositoryTests.cs index 3e6e82d408..846d866b8c 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyCertificateRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyCertificateRepositoryTests.cs @@ -21,6 +21,7 @@ using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Tests.Setup; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Tests; @@ -80,6 +81,7 @@ public async Task CreateCompanyCertificateData_WithValidData_ReturnsExpected() .Which.Entity.Should().BeOfType() .Which.CompanyCertificateStatusId.Should().Be(CompanyCertificateStatusId.ACTIVE); } + #endregion #region GetAllCertificateData @@ -97,12 +99,13 @@ public async Task GetAllCertificates_ReturnsExpectedResult(CertificateSorting so // Assert companyCertificateDetail.Should().NotBeNull(); - companyCertificateDetail!.Count.Should().Be(6); - companyCertificateDetail.Data.Should().HaveCount(6); + companyCertificateDetail!.Count.Should().Be(8); + companyCertificateDetail.Data.Should().HaveCount(8); if (sorting == CertificateSorting.CertificateTypeAsc) { companyCertificateDetail.Data.Select(data => data.companyCertificateType).Should().BeInAscendingOrder(); } + if (sorting == CertificateSorting.CertificateTypeDesc) { companyCertificateDetail.Data.Select(data => data.companyCertificateType).Should().BeInDescendingOrder(); @@ -136,7 +139,52 @@ public async Task GetAllCertificates_WithExistingCompanyCertificateAndCertificat #endregion + #region GetCompanyCertificatesBpn + + [Fact] + public async Task GetCompanyId_WithExistingData() + { + // Arrange + var sut = await CreateSut(); + + // Act + var result = await sut.GetCompanyIdByBpn("BPNL07800HZ01643").ConfigureAwait(false); + + // Assert + result.Should().NotBe(Guid.Empty); + result.Should().Be(new Guid("3390c2d7-75c1-4169-aa27-6ce00e1f3cdd")); + } + + [Fact] + public async Task GetCompanyId_WithNoExistingData() + { + // Arrange + var sut = await CreateSut(); + + // Act + var result = await sut.GetCompanyIdByBpn("BPNL07800HZ01644").ConfigureAwait(false); + + // Assert + result.Should().Be(Guid.Empty); + } + + [Fact] + public async Task GetCompanyCertificateData_NoResults_ReturnsExpected() + { + // Arrange + var sut = await CreateSut(); + + // Act + var result = await sut.GetCompanyCertificateData(Guid.NewGuid()).ToListAsync().ConfigureAwait(false); + + // Assert + result.Should().BeEmpty(); + } + + #endregion + #region Setup + private async Task CreateSut() { var context = await _dbTestDbFixture.GetPortalDbContext().ConfigureAwait(false);