diff --git a/src/registration/Registration.Service/BusinessLogic/RegistrationBusinessLogic.cs b/src/registration/Registration.Service/BusinessLogic/RegistrationBusinessLogic.cs index 5566c0c8f6..6cf42e4cae 100644 --- a/src/registration/Registration.Service/BusinessLogic/RegistrationBusinessLogic.cs +++ b/src/registration/Registration.Service/BusinessLogic/RegistrationBusinessLogic.cs @@ -543,14 +543,17 @@ public async Task SubmitRegistrationAsync(Guid applicationId) if (GetAndValidateUpdateApplicationStatus(applicationUserData.CompanyApplicationStatusId, UpdateApplicationSteps.SubmitRegistration) != CompanyApplicationStatusId.SUBMITTED) { - throw new UnexpectedConditionException("updateStatus should allways be SUBMITTED here"); + throw new UnexpectedConditionException("updateStatus should always be SUBMITTED here"); } - portalRepositories.GetInstance().AttachAndModifyDocuments( - applicationUserData.DocumentDatas.Select(x => new ValueTuple?, Action>( - x.DocumentId, - doc => doc.DocumentStatusId = x.StatusId, - doc => doc.DocumentStatusId = DocumentStatusId.LOCKED))); + if (applicationUserData.DocumentDatas != null && applicationUserData.DocumentDatas.Any()) + { + portalRepositories.GetInstance().AttachAndModifyDocuments( + applicationUserData.DocumentDatas.Select(x => new ValueTuple?, Action>( + x.DocumentId, + doc => doc.DocumentStatusId = x.StatusId, + doc => doc.DocumentStatusId = DocumentStatusId.LOCKED))); + } var entries = await checklistService.CreateInitialChecklistAsync(applicationId); @@ -637,7 +640,7 @@ private async ValueTask GetAndValidateCompanyDa { throw new ConflictException($"Agreement and Consent must not be empty"); } - if (!applicationUserData.DocumentDatas.Any()) + if (!_settings.IsSubmitDocumentValidationOptional && !applicationUserData.DocumentDatas.Any()) { throw new ConflictException($"At least one Document type Id must be [{string.Join(", ", docTypeIds)}]"); } diff --git a/src/registration/Registration.Service/BusinessLogic/RegistrationSettings.cs b/src/registration/Registration.Service/BusinessLogic/RegistrationSettings.cs index 92bd858b0e..f5c7c9d225 100644 --- a/src/registration/Registration.Service/BusinessLogic/RegistrationSettings.cs +++ b/src/registration/Registration.Service/BusinessLogic/RegistrationSettings.cs @@ -76,6 +76,14 @@ public class RegistrationSettings [DistinctValues] public IEnumerable SubmitDocumentTypeIds { get; set; } = null!; + /// + /// Is Submit DocumentType Validation Optional + /// + /// + [Required] + [DistinctValues] + public bool IsSubmitDocumentValidationOptional { get; set; } = false; + /// /// Url to the password resend of the portal /// diff --git a/src/registration/Registration.Service/appsettings.json b/src/registration/Registration.Service/appsettings.json index edff4031b9..35dec15d7a 100644 --- a/src/registration/Registration.Service/appsettings.json +++ b/src/registration/Registration.Service/appsettings.json @@ -33,7 +33,8 @@ "ApplicationDeclineStatusIds": [], "DocumentTypeIds": [], "RegistrationDocumentTypeIds": [], - "SubmitDocumentTypeIds": [] + "SubmitDocumentTypeIds": [], + "IsSubmitDocumentValidationOptional": false }, "BPN_Address": "", "Keycloak": { diff --git a/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs b/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs index f21f2f66c2..0cf28f18a7 100644 --- a/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs +++ b/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs @@ -2012,7 +2012,8 @@ public async Task SubmitRegistrationAsync_WithNotExistingApplication_ThrowsNotFo { SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - ] + ], + IsSubmitDocumentValidationOptional = false }; A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) .Returns(null); @@ -2031,135 +2032,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingApplication_ThrowsNotFo [Fact] public async Task SubmitRegistrationAsync_WithDocumentId_Success() { - // Arrange - var applicationId = _fixture.Create(); - var now = DateTimeOffset.Now; - var documents = new DocumentStatusData[] { - new(Guid.NewGuid(),DocumentStatusId.PENDING), - new(Guid.NewGuid(),DocumentStatusId.INACTIVE) - }; - var checklist = _fixture.CreateMany(3).Select(x => (x, ApplicationChecklistEntryStatusId.TO_DO)).ToImmutableArray(); - var stepTypeIds = _fixture.CreateMany(3).ToImmutableArray(); - var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); - var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new[] - { - (Guid.NewGuid(), ConsentStatusId.ACTIVE), - }; - var companyData = new CompanyData("Test Company", Guid.NewGuid(), "Strabe Street", "Munich", "Germany", uniqueIds, companyRoleIds); - A.CallTo(() => _dateTimeProvider.OffsetNow).Returns(now); - A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) - .Returns(new CompanyApplicationUserEmailData(CompanyApplicationStatusId.VERIFY, true, "test@mail.de", documents, companyData, agreementConsents)); - - var modifiedDocuments = new List<(Document Initial, Document Modified)>(); - - A.CallTo(() => _documentRepository.AttachAndModifyDocuments(A?, Action)>>._)) - .Invokes((IEnumerable<(Guid DocumentId, Action? Initialize, Action Modify)> documentKeyActions) => - { - foreach (var x in documentKeyActions) - { - var initial = new Document(x.DocumentId, null!, null!, null!, default, default, default, default); - x.Initialize?.Invoke(initial); - var modified = new Document(x.DocumentId, null!, null!, null!, default, default, default, default); - x.Modify(modified); - modifiedDocuments.Add((initial, modified)); - } - }); - - A.CallTo(() => _checklistService.CreateInitialChecklistAsync(applicationId)) - .Returns(checklist); - - A.CallTo(() => _checklistService.GetInitialProcessStepTypeIds(A>.That.IsSameSequenceAs(checklist))) - .Returns(stepTypeIds); - - var utcNow = DateTimeOffset.UtcNow; - - Process? process = null; - - A.CallTo(() => _processStepRepository.CreateProcess(ProcessTypeId.APPLICATION_CHECKLIST)) - .ReturnsLazily((ProcessTypeId processTypeId) => - { - process = new Process(Guid.NewGuid(), processTypeId, Guid.NewGuid()); - return process; - }); - - CompanyApplication? application = null; - - A.CallTo(() => _applicationRepository.AttachAndModifyCompanyApplication(A._, A>._)) - .Invokes((Guid applicationId, Action setOptionalParameters) => - { - application = new CompanyApplication(applicationId, Guid.Empty, default, default, default); - setOptionalParameters(application); - }); - - IEnumerable? processSteps = null; - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .ReturnsLazily((IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus) => - { - processSteps = processStepTypeStatus.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, utcNow)).ToImmutableArray(); - return processSteps; - }); - var settings = new RegistrationSettings - { - SubmitDocumentTypeIds = [ - DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - ] - }; - var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, _checklistService, _identityService, _dateTimeProvider, _mailingProcessCreation); - - // Act - await sut.SubmitRegistrationAsync(applicationId); - - // Assert - A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(applicationId, _identity.IdentityId, A>.That.IsSameSequenceAs(new[] { DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT }))) - .MustHaveHappenedOnceExactly(); - - A.CallTo(() => _documentRepository.AttachAndModifyDocuments(A?, Action)>>.That.Matches(x => x.Count() == 2))) - .MustHaveHappenedOnceExactly(); - - modifiedDocuments.Should().HaveCount(2).And.Satisfy( - x => x.Initial.Id == documents[0].DocumentId && x.Initial.DocumentStatusId == documents[0].StatusId && x.Modified.Id == documents[0].DocumentId && x.Modified.DocumentStatusId == DocumentStatusId.LOCKED, - x => x.Initial.Id == documents[1].DocumentId && x.Initial.DocumentStatusId == documents[1].StatusId && x.Modified.Id == documents[1].DocumentId && x.Modified.DocumentStatusId == DocumentStatusId.LOCKED - ); - - A.CallTo(() => _checklistService.CreateInitialChecklistAsync(applicationId)) - .MustHaveHappenedOnceExactly(); - - A.CallTo(() => _checklistService.GetInitialProcessStepTypeIds(A>.That.IsSameSequenceAs(checklist))) - .MustHaveHappenedOnceExactly(); - - A.CallTo(() => _processStepRepository.CreateProcess(ProcessTypeId.APPLICATION_CHECKLIST)) - .MustHaveHappenedOnceExactly(); - - process.Should().NotBeNull(); - process!.ProcessTypeId.Should().Be(ProcessTypeId.APPLICATION_CHECKLIST); - - A.CallTo(() => _applicationRepository.AttachAndModifyCompanyApplication(A._, A>._)) - .MustHaveHappenedOnceExactly(); - - application.Should().NotBeNull(); - application!.ChecklistProcessId.Should().Be(process!.Id); - application.ApplicationStatusId.Should().Be(CompanyApplicationStatusId.SUBMITTED); - application.DateLastChanged.Should().Be(now); - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustHaveHappenedOnceExactly(); - - processSteps.Should().NotBeNull() - .And.HaveCount(stepTypeIds.Length) - .And.AllSatisfy(x => - { - x.ProcessId.Should().Be(process.Id); - x.ProcessStepStatusId.Should().Be(ProcessStepStatusId.TODO); - }) - .And.Satisfy( - x => x.ProcessStepTypeId == stepTypeIds[0], - x => x.ProcessStepTypeId == stepTypeIds[1], - x => x.ProcessStepTypeId == stepTypeIds[2] - ); - - A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); + await SubmitRegistrationAsync_SuccessHelper(false); } [Theory] @@ -2192,7 +2065,8 @@ public async Task SubmitRegistrationAsync_InvalidStatus_ThrowsForbiddenException { SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - ] + ], + IsSubmitDocumentValidationOptional = false }; var companyData = new CompanyData("Test Company", Guid.NewGuid(), "Strabe Street", "Munich", "Germany", uniqueIds, companyRoleIds); A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) @@ -2238,7 +2112,8 @@ public async Task SubmitRegistrationAsync_AlreadyClosed_ThrowsForbiddenException { SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - ] + ], + IsSubmitDocumentValidationOptional = false }; A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) .Returns(new CompanyApplicationUserEmailData(statusId, true, _fixture.Create(), documents, companyData, agreementConsents)); @@ -2276,7 +2151,8 @@ public async Task SubmitRegistrationAsync_WithNotExistingCompanyUser_ThrowsForbi { SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - ] + ], + IsSubmitDocumentValidationOptional = false }; A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) .Returns(new CompanyApplicationUserEmailData(CompanyApplicationStatusId.VERIFY, false, null, null!, companyData, agreementConsents)); @@ -2314,7 +2190,8 @@ public async Task SubmitRegistrationAsync_WithNotExistingStreetName_ThrowsConfli { SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - ] + ], + IsSubmitDocumentValidationOptional = false }; A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(applicationId, userId, A>._)) .Returns(new CompanyApplicationUserEmailData(CompanyApplicationStatusId.VERIFY, true, _fixture.Create(), Enumerable.Empty(), companyData, agreementConsents)); @@ -2557,7 +2434,8 @@ public async Task SubmitRegistrationAsync_WithUserEmail_SendsMail() { SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - ] + ], + IsSubmitDocumentValidationOptional = false }; var application = _fixture.Build() .With(x => x.Id, applicationId) @@ -2607,7 +2485,8 @@ public async Task SubmitRegistrationAsync_WithoutUserEmail_DoesntSendMail() { SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - ] + ], + IsSubmitDocumentValidationOptional = false }; var application = _fixture.Build() .With(x => x.Id, applicationId) @@ -2636,6 +2515,296 @@ public async Task SubmitRegistrationAsync_WithoutUserEmail_DoesntSendMail() application.DateLastChanged.Should().Be(now); } + [Fact] + public async Task SubmitRegistrationAsync_WithMandatorySubmitDocument_ThrowsConflictException() + { + // Arrange + var userId = Guid.NewGuid(); + var identityData = A.Fake(); + A.CallTo(() => identityData.IdentityId).Returns(userId); + A.CallTo(() => identityData.IdentityTypeId).Returns(IdentityTypeId.COMPANY_USER); + A.CallTo(() => identityData.CompanyId).Returns(Guid.NewGuid()); + A.CallTo(() => _identityService.IdentityData).Returns(identityData); + var applicationId = _fixture.Create(); + var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); + var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); + var agreementConsents = new[] + { + (Guid.NewGuid(), ConsentStatusId.ACTIVE), + }; + var companyData = new CompanyData("Test Company", Guid.NewGuid(), "Strabe Street", "Munich", "Germany", uniqueIds, companyRoleIds); + var settings = new RegistrationSettings + { + SubmitDocumentTypeIds = [ + DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT + ], + IsSubmitDocumentValidationOptional = false, + }; + A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(applicationId, userId, A>._)) + .Returns(new CompanyApplicationUserEmailData(CompanyApplicationStatusId.VERIFY, true, _fixture.Create(), Enumerable.Empty(), companyData, agreementConsents)); + var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); + + // Act + Task Act() => sut.SubmitRegistrationAsync(applicationId); + + // Assert + var ex = await Assert.ThrowsAsync(Act); + ex.Message.Should().Be($"At least one Document type Id must be [{string.Join(", ", settings.SubmitDocumentTypeIds)}]"); + } + + [Fact] + public async Task SubmitRegistrationAsync_WithOptionalValidationEnableAndNoSubmitDocumentId_Success() + { + // Arrange + var applicationId = _fixture.Create(); + var now = DateTimeOffset.Now; + + var checklist = _fixture.CreateMany(3).Select(x => (x, ApplicationChecklistEntryStatusId.TO_DO)).ToImmutableArray(); + var stepTypeIds = _fixture.CreateMany(3).ToImmutableArray(); + var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); + var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); + var agreementConsents = new[] + { + (Guid.NewGuid(), ConsentStatusId.ACTIVE), + }; + var companyData = new CompanyData("Test Company", Guid.NewGuid(), "Strabe Street", "Munich", "Germany", uniqueIds, companyRoleIds); + A.CallTo(() => _dateTimeProvider.OffsetNow).Returns(now); + A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) + .Returns(new CompanyApplicationUserEmailData(CompanyApplicationStatusId.VERIFY, true, "test@mail.de", [], companyData, agreementConsents)); + + A.CallTo(() => _checklistService.CreateInitialChecklistAsync(applicationId)) + .Returns(checklist); + + A.CallTo(() => _checklistService.GetInitialProcessStepTypeIds(A>.That.IsSameSequenceAs(checklist))) + .Returns(stepTypeIds); + + var utcNow = DateTimeOffset.UtcNow; + + Process? process = null; + + A.CallTo(() => _processStepRepository.CreateProcess(ProcessTypeId.APPLICATION_CHECKLIST)) + .ReturnsLazily((ProcessTypeId processTypeId) => + { + process = new Process(Guid.NewGuid(), processTypeId, Guid.NewGuid()); + return process; + }); + + CompanyApplication? application = null; + + A.CallTo(() => _applicationRepository.AttachAndModifyCompanyApplication(A._, A>._)) + .Invokes((Guid applicationId, Action setOptionalParameters) => + { + application = new CompanyApplication(applicationId, Guid.Empty, default, default, default); + setOptionalParameters(application); + }); + + IEnumerable? processSteps = null; + + A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) + .ReturnsLazily((IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus) => + { + processSteps = processStepTypeStatus.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, utcNow)).ToImmutableArray(); + return processSteps; + }); + var settings = new RegistrationSettings + { + SubmitDocumentTypeIds = [ + DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT + ], + IsSubmitDocumentValidationOptional = true + }; + var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, _checklistService, _identityService, _dateTimeProvider, _mailingProcessCreation); + + // Act + await sut.SubmitRegistrationAsync(applicationId); + + // Assert + A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(applicationId, _identity.IdentityId, A>.That.IsSameSequenceAs(new[] { DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT }))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _documentRepository.AttachAndModifyDocuments( + A?, Action)>>.Ignored + )).MustNotHaveHappened(); + + A.CallTo(() => _checklistService.CreateInitialChecklistAsync(applicationId)) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _checklistService.GetInitialProcessStepTypeIds(A>.That.IsSameSequenceAs(checklist))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _processStepRepository.CreateProcess(ProcessTypeId.APPLICATION_CHECKLIST)) + .MustHaveHappenedOnceExactly(); + + process.Should().NotBeNull(); + process!.ProcessTypeId.Should().Be(ProcessTypeId.APPLICATION_CHECKLIST); + + A.CallTo(() => _applicationRepository.AttachAndModifyCompanyApplication(A._, A>._)) + .MustHaveHappenedOnceExactly(); + + application.Should().NotBeNull(); + application!.ChecklistProcessId.Should().Be(process!.Id); + application.ApplicationStatusId.Should().Be(CompanyApplicationStatusId.SUBMITTED); + application.DateLastChanged.Should().Be(now); + + A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) + .MustHaveHappenedOnceExactly(); + + processSteps.Should().NotBeNull() + .And.HaveCount(stepTypeIds.Length) + .And.AllSatisfy(x => + { + x.ProcessId.Should().Be(process.Id); + x.ProcessStepStatusId.Should().Be(ProcessStepStatusId.TODO); + }) + .And.Satisfy( + x => x.ProcessStepTypeId == stepTypeIds[0], + x => x.ProcessStepTypeId == stepTypeIds[1], + x => x.ProcessStepTypeId == stepTypeIds[2] + ); + + A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task SubmitRegistrationAsync_WithOptionalValidationEnableAndWithSubmitDocumentId_Success() + { + await SubmitRegistrationAsync_SuccessHelper(true); + } + + private async Task SubmitRegistrationAsync_SuccessHelper(bool isSubmitDocumentValidationOptional) + { + // Arrange + var applicationId = _fixture.Create(); + var now = DateTimeOffset.Now; + var documents = new DocumentStatusData[] { + new(Guid.NewGuid(),DocumentStatusId.PENDING), + new(Guid.NewGuid(),DocumentStatusId.INACTIVE) + }; + var checklist = _fixture.CreateMany(3).Select(x => (x, ApplicationChecklistEntryStatusId.TO_DO)).ToImmutableArray(); + var stepTypeIds = _fixture.CreateMany(3).ToImmutableArray(); + var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); + var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); + var agreementConsents = new[] + { + (Guid.NewGuid(), ConsentStatusId.ACTIVE), + }; + var companyData = new CompanyData("Test Company", Guid.NewGuid(), "Strabe Street", "Munich", "Germany", uniqueIds, companyRoleIds); + A.CallTo(() => _dateTimeProvider.OffsetNow).Returns(now); + A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) + .Returns(new CompanyApplicationUserEmailData(CompanyApplicationStatusId.VERIFY, true, "test@mail.de", documents, companyData, agreementConsents)); + + var modifiedDocuments = new List<(Document Initial, Document Modified)>(); + + A.CallTo(() => _documentRepository.AttachAndModifyDocuments(A?, Action)>>._)) + .Invokes((IEnumerable<(Guid DocumentId, Action? Initialize, Action Modify)> documentKeyActions) => + { + foreach (var x in documentKeyActions) + { + var initial = new Document(x.DocumentId, null!, null!, null!, default, default, default, default); + x.Initialize?.Invoke(initial); + var modified = new Document(x.DocumentId, null!, null!, null!, default, default, default, default); + x.Modify(modified); + modifiedDocuments.Add((initial, modified)); + } + }); + + A.CallTo(() => _checklistService.CreateInitialChecklistAsync(applicationId)) + .Returns(checklist); + + A.CallTo(() => _checklistService.GetInitialProcessStepTypeIds(A>.That.IsSameSequenceAs(checklist))) + .Returns(stepTypeIds); + + var utcNow = DateTimeOffset.UtcNow; + + Process? process = null; + + A.CallTo(() => _processStepRepository.CreateProcess(ProcessTypeId.APPLICATION_CHECKLIST)) + .ReturnsLazily((ProcessTypeId processTypeId) => + { + process = new Process(Guid.NewGuid(), processTypeId, Guid.NewGuid()); + return process; + }); + + CompanyApplication? application = null; + + A.CallTo(() => _applicationRepository.AttachAndModifyCompanyApplication(A._, A>._)) + .Invokes((Guid applicationId, Action setOptionalParameters) => + { + application = new CompanyApplication(applicationId, Guid.Empty, default, default, default); + setOptionalParameters(application); + }); + + IEnumerable? processSteps = null; + + A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) + .ReturnsLazily((IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus) => + { + processSteps = processStepTypeStatus.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, utcNow)).ToImmutableArray(); + return processSteps; + }); + var settings = new RegistrationSettings + { + SubmitDocumentTypeIds = [ + DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT + ], + IsSubmitDocumentValidationOptional = isSubmitDocumentValidationOptional + }; + var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, _checklistService, _identityService, _dateTimeProvider, _mailingProcessCreation); + + // Act + await sut.SubmitRegistrationAsync(applicationId); + + // Assert + A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(applicationId, _identity.IdentityId, A>.That.IsSameSequenceAs(new[] { DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT }))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _documentRepository.AttachAndModifyDocuments(A?, Action)>>.That.Matches(x => x.Count() == 2))) + .MustHaveHappenedOnceExactly(); + + modifiedDocuments.Should().HaveCount(2).And.Satisfy( + x => x.Initial.Id == documents[0].DocumentId && x.Initial.DocumentStatusId == documents[0].StatusId && x.Modified.Id == documents[0].DocumentId && x.Modified.DocumentStatusId == DocumentStatusId.LOCKED, + x => x.Initial.Id == documents[1].DocumentId && x.Initial.DocumentStatusId == documents[1].StatusId && x.Modified.Id == documents[1].DocumentId && x.Modified.DocumentStatusId == DocumentStatusId.LOCKED + ); + + A.CallTo(() => _checklistService.CreateInitialChecklistAsync(applicationId)) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _checklistService.GetInitialProcessStepTypeIds(A>.That.IsSameSequenceAs(checklist))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _processStepRepository.CreateProcess(ProcessTypeId.APPLICATION_CHECKLIST)) + .MustHaveHappenedOnceExactly(); + + process.Should().NotBeNull(); + process!.ProcessTypeId.Should().Be(ProcessTypeId.APPLICATION_CHECKLIST); + + A.CallTo(() => _applicationRepository.AttachAndModifyCompanyApplication(A._, A>._)) + .MustHaveHappenedOnceExactly(); + + application.Should().NotBeNull(); + application!.ChecklistProcessId.Should().Be(process!.Id); + application.ApplicationStatusId.Should().Be(CompanyApplicationStatusId.SUBMITTED); + application.DateLastChanged.Should().Be(now); + + A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) + .MustHaveHappenedOnceExactly(); + + processSteps.Should().NotBeNull() + .And.HaveCount(stepTypeIds.Length) + .And.AllSatisfy(x => + { + x.ProcessId.Should().Be(process.Id); + x.ProcessStepStatusId.Should().Be(ProcessStepStatusId.TODO); + }) + .And.Satisfy( + x => x.ProcessStepTypeId == stepTypeIds[0], + x => x.ProcessStepTypeId == stepTypeIds[1], + x => x.ProcessStepTypeId == stepTypeIds[2] + ); + + A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); + } + #endregion #region GetCompanyIdentifiers