diff --git a/src/AssociationRegistry.Admin.Api/AssociationRegistry.Admin.Api.csproj b/src/AssociationRegistry.Admin.Api/AssociationRegistry.Admin.Api.csproj index c891a455c..6fb893dc5 100755 --- a/src/AssociationRegistry.Admin.Api/AssociationRegistry.Admin.Api.csproj +++ b/src/AssociationRegistry.Admin.Api/AssociationRegistry.Admin.Api.csproj @@ -67,6 +67,7 @@ + diff --git a/src/AssociationRegistry.Admin.Api/Infrastructure/Extensions/WolverineExtensions.cs b/src/AssociationRegistry.Admin.Api/Infrastructure/Extensions/WolverineExtensions.cs index 19d7cfe7a..c0f052a48 100644 --- a/src/AssociationRegistry.Admin.Api/Infrastructure/Extensions/WolverineExtensions.cs +++ b/src/AssociationRegistry.Admin.Api/Infrastructure/Extensions/WolverineExtensions.cs @@ -6,16 +6,21 @@ using Grar.AddressMatch; using Hosts.Configuration; using JasperFx.CodeGeneration; +using MessageHandling.Postgres.Dubbels; +using Messages; using Serilog; using Vereniging; using Wolverine; using Wolverine.AmazonSqs; using Wolverine.ErrorHandling; +using Wolverine.Postgresql; public static class WolverineExtensions { public static void AddWolverine(this WebApplicationBuilder builder) { + const string AanvaardDubbeleVerenigingQueueName = "aanvaard-dubbele-vereniging-queue"; + builder.Host.UseWolverine( (context, options) => { @@ -26,6 +31,8 @@ public static void AddWolverine(this WebApplicationBuilder builder) options.Discovery.IncludeType(); options.Discovery.IncludeType(); options.Discovery.IncludeType(); + options.Discovery.IncludeType(); + options.Discovery.IncludeType(); options.OnException().RetryWithCooldown( TimeSpan.FromSeconds(1), @@ -50,12 +57,19 @@ public static void AddWolverine(this WebApplicationBuilder builder) ConfigureAddressMatchPublisher(options, grarOptions.Sqs.AddressMatchQueueName); - ConfiguredAddressMatchListener(options, grarOptions.Sqs.AddressMatchQueueName, + ConfigureAddressMatchListener(options, grarOptions.Sqs.AddressMatchQueueName, grarOptions.Sqs.AddressMatchDeadLetterQueueName); ConfigureGrarSyncListener(options, grarOptions.Sqs.GrarSyncQueueName, grarOptions.Sqs.GrarSyncDeadLetterQueueName, grarOptions.Sqs.GrarSyncQueueListenerEnabled); + options.PersistMessagesWithPostgresql(context.Configuration.GetPostgreSqlOptionsSection().GetConnectionString()); + + options.PublishMessage() + .ToPostgresqlQueue(AanvaardDubbeleVerenigingQueueName); + + options.ListenToPostgresqlQueue(AanvaardDubbeleVerenigingQueueName); + if (grarOptions.Wolverine.AutoProvision) transportConfiguration.AutoProvision(); @@ -73,7 +87,7 @@ private static void ConfigureAddressMatchPublisher(WolverineOptions options, str .MessageBatchSize(1); } - private static void ConfiguredAddressMatchListener(WolverineOptions options, string sqsQueueName, string sqsDeadLetterQueueName) + private static void ConfigureAddressMatchListener(WolverineOptions options, string sqsQueueName, string sqsDeadLetterQueueName) { options.ListenToSqsQueue(sqsQueueName, configure: configure => { diff --git a/src/AssociationRegistry.Admin.Api/Infrastructure/ResponseWriter/ResponseWriter.cs b/src/AssociationRegistry.Admin.Api/Infrastructure/ResponseWriter/ResponseWriter.cs index 80c1bf469..a06b78012 100644 --- a/src/AssociationRegistry.Admin.Api/Infrastructure/ResponseWriter/ResponseWriter.cs +++ b/src/AssociationRegistry.Admin.Api/Infrastructure/ResponseWriter/ResponseWriter.cs @@ -1,6 +1,6 @@ namespace AssociationRegistry.Admin.Api.Infrastructure.ResponseWriter; -using AssociationRegistry.Admin.Api.Infrastructure.Extensions; +using Extensions; using Be.Vlaanderen.Basisregisters.Api.Exceptions; using Microsoft.AspNetCore.Mvc; diff --git a/src/AssociationRegistry.Admin.Api/Infrastructure/Sequence/SequenceGuarder.cs b/src/AssociationRegistry.Admin.Api/Infrastructure/Sequence/SequenceGuarder.cs index ebfd31759..d9138ae08 100644 --- a/src/AssociationRegistry.Admin.Api/Infrastructure/Sequence/SequenceGuarder.cs +++ b/src/AssociationRegistry.Admin.Api/Infrastructure/Sequence/SequenceGuarder.cs @@ -1,8 +1,8 @@ namespace AssociationRegistry.Admin.Api.Infrastructure.Sequence; -using AssociationRegistry.Admin.Api.Infrastructure.Extensions; -using AssociationRegistry.Admin.Schema.Detail; -using AssociationRegistry.EventStore; +using Extensions; +using Schema.Detail; +using EventStore; using Marten; public class SequenceGuarder : ISequenceGuarder diff --git a/src/AssociationRegistry.Admin.Api/Infrastructure/Validation/FluentValidatorExtensions.cs b/src/AssociationRegistry.Admin.Api/Infrastructure/Validation/FluentValidatorExtensions.cs index 29b45122f..813e0902a 100644 --- a/src/AssociationRegistry.Admin.Api/Infrastructure/Validation/FluentValidatorExtensions.cs +++ b/src/AssociationRegistry.Admin.Api/Infrastructure/Validation/FluentValidatorExtensions.cs @@ -1,6 +1,6 @@ namespace AssociationRegistry.Admin.Api.Infrastructure.Validation; -using AssociationRegistry.Admin.Api.Infrastructure.ExceptionHandlers; +using ExceptionHandlers; using FluentValidation; using System.Diagnostics.CodeAnalysis; diff --git a/src/AssociationRegistry.Admin.Api/MessageHandling/Postgres/Dubbels/AanvaardDubbeleVerenigingMessageHandler.cs b/src/AssociationRegistry.Admin.Api/MessageHandling/Postgres/Dubbels/AanvaardDubbeleVerenigingMessageHandler.cs new file mode 100644 index 000000000..fe023d60e --- /dev/null +++ b/src/AssociationRegistry.Admin.Api/MessageHandling/Postgres/Dubbels/AanvaardDubbeleVerenigingMessageHandler.cs @@ -0,0 +1,14 @@ +namespace AssociationRegistry.Admin.Api.MessageHandling.Postgres.Dubbels; + +using Messages; +using Wolverine; + +public class AanvaardDubbeleVerenigingMessageHandler(IMessageBus messageBus) +{ + public async Task Handle(AanvaardDubbeleVerenigingMessage message, CancellationToken cancellationToken) + { + var command = message.ToCommand(); + + await messageBus.InvokeAsync(command, cancellationToken); + } +} diff --git a/src/AssociationRegistry.Admin.Api/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs b/src/AssociationRegistry.Admin.Api/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs index b88914fa7..692e1e8c8 100644 --- a/src/AssociationRegistry.Admin.Api/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs +++ b/src/AssociationRegistry.Admin.Api/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs @@ -79,6 +79,7 @@ private static VerenigingDetail Map( Relaties = vereniging.Relaties.Select(relatie => Map(relatie, baseUrl)).ToArray(), Lidmaatschappen = vereniging.Lidmaatschappen.Select(lidmaatschap => Map(lidmaatschap, namenVoorLidmaatschapMapper)).ToArray(), Bron = vereniging.Bron, + IsDubbelVan = vereniging.IsDubbelVan, }; } diff --git a/src/AssociationRegistry.Admin.Api/Verenigingen/Detail/ResponseModels/VerenigingDetail.cs b/src/AssociationRegistry.Admin.Api/Verenigingen/Detail/ResponseModels/VerenigingDetail.cs index 3b153dc13..f7ece6314 100644 --- a/src/AssociationRegistry.Admin.Api/Verenigingen/Detail/ResponseModels/VerenigingDetail.cs +++ b/src/AssociationRegistry.Admin.Api/Verenigingen/Detail/ResponseModels/VerenigingDetail.cs @@ -15,7 +15,7 @@ public class VerenigingDetail // De unieke identificatie codes van de corresponderende verenigingen [DataMember(Name = "CorresponderendeVCodes")] - public string[] CorresponderendeVCodes { get; init; } = Array.Empty(); + public string[] CorresponderendeVCodes { get; init; } = []; /// Het type van deze vereniging [DataMember(Name = "Verenigingstype")] @@ -102,4 +102,8 @@ public class VerenigingDetail /// [DataMember(Name = "Bron")] public string Bron { get; set; } = null!; + + /// De VCode van de vereniging waarvan deze vereniging een dubbel is + [DataMember(Name = "IsDubbelVan")] + public string IsDubbelVan { get; set; } } diff --git a/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/Examples/MarkeerAlsDubbelVanRequestExamples.cs b/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/Examples/MarkeerAlsDubbelVanRequestExamples.cs new file mode 100644 index 000000000..4879f3235 --- /dev/null +++ b/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/Examples/MarkeerAlsDubbelVanRequestExamples.cs @@ -0,0 +1,13 @@ +namespace AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan.Examples; + +using RequestModels; +using Swashbuckle.AspNetCore.Filters; + +public class MarkeerAlsDubbelVanRequestExamples : IExamplesProvider +{ + public MarkeerAlsDubbelVanRequest GetExamples() + => new() + { + IsDubbelVan = "V0001002", + }; +} diff --git a/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanController.cs b/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanController.cs new file mode 100644 index 000000000..add8310d0 --- /dev/null +++ b/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanController.cs @@ -0,0 +1,87 @@ +namespace AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan; + +using Acties.MarkeerAlsDubbelVan; +using Asp.Versioning; +using Be.Vlaanderen.Basisregisters.Api; +using Be.Vlaanderen.Basisregisters.Api.Exceptions; +using Examples; +using FluentValidation; +using Framework; +using Hosts.Configuration.ConfigurationBindings; +using Infrastructure; +using Infrastructure.Extensions; +using Infrastructure.Middleware; +using Infrastructure.Swagger.Annotations; +using Infrastructure.Swagger.Examples; +using Infrastructure.Validation; +using Microsoft.AspNetCore.Mvc; +using RequestModels; +using Swashbuckle.AspNetCore.Filters; +using Vereniging; +using Wolverine; +using ProblemDetails = Be.Vlaanderen.Basisregisters.BasicApiProblem.ProblemDetails; +using ValidationProblemDetails = Be.Vlaanderen.Basisregisters.BasicApiProblem.ValidationProblemDetails; + +[ApiVersion("1.0")] +[AdvertiseApiVersions("1.0")] +[ApiRoute("verenigingen")] +[SwaggerGroup.DecentraalBeheer] +public class MarkeerAlsDubbelVanController : ApiController +{ + private readonly IMessageBus _messageBus; + private readonly IValidator _validator; + private readonly AppSettings _appSettings; + + public MarkeerAlsDubbelVanController(IMessageBus messageBus, IValidator validator, AppSettings appSettings) + { + _messageBus = messageBus; + _validator = validator; + _appSettings = appSettings; + } + + /// + /// Markeer een vereniging als dubbel van een andere vereniging. + /// + /// + /// Na het uitvoeren van deze actie wordt een sequentie teruggegeven via de `VR-Sequence` header. + /// Deze waarde kan gebruikt worden in andere endpoints om op te volgen of de aanpassing + /// al is doorgestroomd naar deze endpoints. + /// + /// De vCode van de vereniging. + /// De gegevens van de andere vereniging waarvan deze een dubbel is. + /// + /// If-Match header met ETag van de laatst gekende versie van de vereniging. + /// De vereniging werd als dubbel gemarkeerd. + /// Er was een probleem met de doorgestuurde waarden. + /// De gevraagde vereniging heeft niet de verwachte sequentiewaarde. + /// Er is een interne fout opgetreden. + [HttpPost("{vCode}/dubbelVan")] + [ConsumesJson] + [ProducesJson] + [SwaggerRequestExample(typeof(MarkeerAlsDubbelVanRequest), typeof(MarkeerAlsDubbelVanRequestExamples))] + [SwaggerResponseHeader(StatusCodes.Status202Accepted, WellknownHeaderNames.Sequence, type: "string", + description: "Het sequence nummer van deze request.")] + [SwaggerResponseHeader(StatusCodes.Status202Accepted, name: "ETag", type: "string", + description: "De versie van de vereniging die als dubbel werd gemarkeerd.")] + [SwaggerResponseExample(StatusCodes.Status400BadRequest, typeof(ProblemAndValidationProblemDetailsExamples))] + [SwaggerResponseExample(StatusCodes.Status412PreconditionFailed, typeof(PreconditionFailedProblemDetailsExamples))] + [SwaggerResponseExample(StatusCodes.Status500InternalServerError, typeof(InternalServerErrorResponseExamples))] + [ProducesResponseType(StatusCodes.Status202Accepted)] + [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status412PreconditionFailed)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] + public async Task Post( + [FromRoute] string vCode, + [FromBody] MarkeerAlsDubbelVanRequest request, + [FromServices] ICommandMetadataProvider metadataProvider, + [FromHeader(Name = "If-Match")] string? ifMatch = null) + { + await _validator.NullValidateAndThrowAsync(request); + + var metaData = metadataProvider.GetMetadata(IfMatchParser.ParseIfMatch(ifMatch)); + var envelope = new CommandEnvelope(request.ToCommand(vCode), metaData); + var commandResult = await _messageBus.InvokeAsync(envelope); + + return this.AcceptedCommand(_appSettings, commandResult); + } +} diff --git a/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanValidator.cs b/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanValidator.cs new file mode 100644 index 000000000..ca364cb3a --- /dev/null +++ b/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanValidator.cs @@ -0,0 +1,17 @@ +namespace AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan; + +using FluentValidation; +using Infrastructure.Validation; +using RequestModels; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +public class MarkeerAlsDubbelVanValidator : AbstractValidator +{ + public MarkeerAlsDubbelVanValidator() + { + RuleFor(r => r.IsDubbelVan) + .NotNull() + .NotEmpty() + .WithVeldIsVerplichtMessage(nameof(MarkeerAlsDubbelVanRequest.IsDubbelVan)); + } +} diff --git a/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/RequestModels/MarkeerAlsDubbelVanRequest.cs b/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/RequestModels/MarkeerAlsDubbelVanRequest.cs new file mode 100644 index 000000000..bd2e8c6e1 --- /dev/null +++ b/src/AssociationRegistry.Admin.Api/Verenigingen/Dubbels/FeitelijkeVereniging/MarkeerAlsDubbelVan/RequestModels/MarkeerAlsDubbelVanRequest.cs @@ -0,0 +1,16 @@ +namespace AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan.RequestModels; + +using Acties.MarkeerAlsDubbelVan; +using System.Runtime.Serialization; +using Vereniging; + +[DataContract] +public class MarkeerAlsDubbelVanRequest +{ + /// De VCode van de vereniging waarvan deze vereniging een dubbel is. + [DataMember(Name = "isDubbelVan")] + public string IsDubbelVan { get; set; } = null!; + + public MarkeerAlsDubbelVanCommand ToCommand(string vCode) + => new(VCode.Create(vCode), VCode.Create(IsDubbelVan)); +} diff --git a/src/AssociationRegistry.Admin.Api/Verenigingen/Registreer/MetRechtspersoonlijkheid/RequestModels/RegistreerVerenigingUitKboRequestValidator.cs b/src/AssociationRegistry.Admin.Api/Verenigingen/Registreer/MetRechtspersoonlijkheid/RequestModels/RegistreerVerenigingUitKboRequestValidator.cs index a8a231643..39d7c165c 100644 --- a/src/AssociationRegistry.Admin.Api/Verenigingen/Registreer/MetRechtspersoonlijkheid/RequestModels/RegistreerVerenigingUitKboRequestValidator.cs +++ b/src/AssociationRegistry.Admin.Api/Verenigingen/Registreer/MetRechtspersoonlijkheid/RequestModels/RegistreerVerenigingUitKboRequestValidator.cs @@ -1,7 +1,7 @@ // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract namespace AssociationRegistry.Admin.Api.Verenigingen.Registreer.MetRechtspersoonlijkheid.RequestModels; -using AssociationRegistry.Admin.Api.Infrastructure.Validation; +using Infrastructure.Validation; using FluentValidation; public class RegistreerVerenigingUitKboRequestValidator : AbstractValidator diff --git a/src/AssociationRegistry.Admin.ProjectionHost/Projections/Detail/BeheerVerenigingDetailProjection.cs b/src/AssociationRegistry.Admin.ProjectionHost/Projections/Detail/BeheerVerenigingDetailProjection.cs index c3b1c0fe5..13abd21b3 100644 --- a/src/AssociationRegistry.Admin.ProjectionHost/Projections/Detail/BeheerVerenigingDetailProjection.cs +++ b/src/AssociationRegistry.Admin.ProjectionHost/Projections/Detail/BeheerVerenigingDetailProjection.cs @@ -224,6 +224,12 @@ public async Task Project(IEvent @event, IDocumentOpe public async Task Project(IEvent @event, IDocumentOperations ops) => await Update(@event, ops, BeheerVerenigingDetailProjector.Apply); + public async Task Project(IEvent @event, IDocumentOperations ops) + => await Update(@event, ops, BeheerVerenigingDetailProjector.Apply); + + public async Task Project(IEvent @event, IDocumentOperations ops) + => await Update(@event, ops, BeheerVerenigingDetailProjector.Apply); + private async Task SoftDelete(string? streamKey, IDocumentOperations ops) => ops.Delete(streamKey); diff --git a/src/AssociationRegistry.Admin.ProjectionHost/Projections/Detail/BeheerVerenigingDetailProjector.cs b/src/AssociationRegistry.Admin.ProjectionHost/Projections/Detail/BeheerVerenigingDetailProjector.cs index 1d88cff20..fd72239f5 100644 --- a/src/AssociationRegistry.Admin.ProjectionHost/Projections/Detail/BeheerVerenigingDetailProjector.cs +++ b/src/AssociationRegistry.Admin.ProjectionHost/Projections/Detail/BeheerVerenigingDetailProjector.cs @@ -36,6 +36,7 @@ public static BeheerVerenigingDetailDocument Create(IEvent BeheerVerenigingDetailMapper.MapContactgegeven( c, feitelijkeVerenigingWerdGeregistreerd.Data.Bron, @@ -90,6 +91,7 @@ public static BeheerVerenigingDetailDocument Create( DatumLaatsteAanpassing = verenigingMetRechtspersoonlijkheidWerdGeregistreerd.GetHeaderInstant(MetadataHeaderNames.Tijdstip).FormatAsBelgianDate(), Status = VerenigingStatus.Actief, IsUitgeschrevenUitPubliekeDatastroom = false, + IsDubbelVan = "", Contactgegevens = [], Locaties = [], Vertegenwoordigers = [], @@ -746,4 +748,19 @@ public static void Apply(IEvent lidmaatschapWerdToeg .OrderBy(l => l.LidmaatschapId) .ToArray(); } + + + public static void Apply(IEvent verenigingWerdGemarkeerdAlsDubbel, BeheerVerenigingDetailDocument document) + { + document.Status = VerenigingStatus.Dubbel; + document.IsDubbelVan = verenigingWerdGemarkeerdAlsDubbel.Data.VCodeAuthentiekeVereniging; + } + + public static void Apply(IEvent verenigingAanvaardeDubbeleVereniging, BeheerVerenigingDetailDocument document) + { + document.CorresponderendeVCodes = + document.CorresponderendeVCodes + .Append(verenigingAanvaardeDubbeleVereniging.Data.VCodeDubbeleVereniging) + .ToArray(); + } } diff --git a/src/AssociationRegistry.Admin.Schema/Constants/VerenigingStatus.cs b/src/AssociationRegistry.Admin.Schema/Constants/VerenigingStatus.cs index 641ca5f3b..82dac9614 100644 --- a/src/AssociationRegistry.Admin.Schema/Constants/VerenigingStatus.cs +++ b/src/AssociationRegistry.Admin.Schema/Constants/VerenigingStatus.cs @@ -4,4 +4,5 @@ public static class VerenigingStatus { public const string Actief = "Actief"; public const string Gestopt = "Gestopt"; + public const string Dubbel = "Dubbel"; } diff --git a/src/AssociationRegistry.Admin.Schema/Detail/BeheerVerenigingDetailDocument.cs b/src/AssociationRegistry.Admin.Schema/Detail/BeheerVerenigingDetailDocument.cs index dbcfce69e..0dc1655fe 100644 --- a/src/AssociationRegistry.Admin.Schema/Detail/BeheerVerenigingDetailDocument.cs +++ b/src/AssociationRegistry.Admin.Schema/Detail/BeheerVerenigingDetailDocument.cs @@ -38,4 +38,5 @@ public record BeheerVerenigingDetailDocument : IVCode, ISoftDeleted, IMetadata [Identity] public string VCode { get; init; } = null!; public bool Deleted { get; set; } public DateTimeOffset? DeletedAt { get; set; } + public string IsDubbelVan { get; set; } = string.Empty; } diff --git a/src/AssociationRegistry.Public.Api/Infrastructure/Extensions/IQueryableExtensions.cs b/src/AssociationRegistry.Public.Api/Infrastructure/Extensions/IQueryableExtensions.cs index c5bf48df3..4a0ae5a87 100644 --- a/src/AssociationRegistry.Public.Api/Infrastructure/Extensions/IQueryableExtensions.cs +++ b/src/AssociationRegistry.Public.Api/Infrastructure/Extensions/IQueryableExtensions.cs @@ -13,8 +13,8 @@ public static class IQueryableExtensions public static IQueryable WithVCode(this IQueryable source, string vCode) where T : IVCode => source.Where(x => x.VCode.Equals(vCode, StringComparison.CurrentCultureIgnoreCase)); - public static IQueryable OnlyActief(this IQueryable source) - => source.Where(x => x.Status == VerenigingStatus.Actief); + public static IQueryable OnlyActiefOrDubbel(this IQueryable source) + => source.Where(x => x.Status == VerenigingStatus.Actief || x.Status == VerenigingStatus.Dubbel); public static IQueryable OnlyIngeschrevenInPubliekeDatastroom(this IQueryable source) where T : ICanBeUitgeschrevenUitPubliekeDatastroom diff --git a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/DetailVerenigingenController.cs b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/DetailVerenigingenController.cs index 05b60eb46..efdb2388c 100644 --- a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/DetailVerenigingenController.cs +++ b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/DetailVerenigingenController.cs @@ -68,6 +68,6 @@ public async Task Detail( .Query() .WithVCode(vCode) .OnlyIngeschrevenInPubliekeDatastroom() - .OnlyActief() + .OnlyActiefOrDubbel() .SingleOrDefaultAsync(); } diff --git a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/PubliekVerenigingDetailMapper.cs b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/PubliekVerenigingDetailMapper.cs index dc7c128a8..32146ff71 100644 --- a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/PubliekVerenigingDetailMapper.cs +++ b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/PubliekVerenigingDetailMapper.cs @@ -39,6 +39,8 @@ public static PubliekVerenigingDetailResponse Map( Sleutels = document.Sleutels.Select(Map).ToArray(), Relaties = document.Relaties.Select(r => Map(appSettings, r)).ToArray(), Lidmaatschappen = document.Lidmaatschappen.Select(l => Map(l, lidmaatschapMapper)).ToArray(), + IsDubbelVan = document.IsDubbelVan, + CorresponderendeVCodes = document.CorresponderendeVCodes, }, Metadata = new Metadata { DatumLaatsteAanpassing = document.DatumLaatsteAanpassing }, }; diff --git a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseExamples/DetailVerenigingResponseExamples.cs b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseExamples/DetailVerenigingResponseExamples.cs index 7e49f8cd1..6a22fee1c 100644 --- a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseExamples/DetailVerenigingResponseExamples.cs +++ b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseExamples/DetailVerenigingResponseExamples.cs @@ -149,6 +149,8 @@ public PubliekVerenigingDetailResponse GetExamples() AndereVereniging = "V0001111", }, ], + IsDubbelVan = "V0001002", + CorresponderendeVCodes = [], }, Metadata = new Metadata { DatumLaatsteAanpassing = "2023-05-15" }, }; diff --git a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseModels/Vereniging.cs b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseModels/Vereniging.cs index bd213cf89..dad80ca16 100644 --- a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseModels/Vereniging.cs +++ b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseModels/Vereniging.cs @@ -1,5 +1,6 @@ namespace AssociationRegistry.Public.Api.Verenigingen.Detail.ResponseModels; +using AssociationRegistry.Vereniging; using System.ComponentModel; using System.Runtime.Serialization; @@ -49,31 +50,37 @@ public class Vereniging /// De contactgegevens van deze vereniging [DataMember(Name = "Contactgegevens")] - public Contactgegeven[] Contactgegevens { get; init; } = Array.Empty(); + public Contactgegeven[] Contactgegevens { get; init; } = []; /// Alle locaties waar deze vereniging actief is [DataMember(Name = "Locaties")] - public Locatie[] Locaties { get; init; } = Array.Empty(); + public Locatie[] Locaties { get; init; } = []; /// De hoofdactivititeiten van deze vereniging volgens het verenigingsloket [DataMember(Name = "HoofdactiviteitenVerenigingsloket")] - public HoofdactiviteitVerenigingsloket[] HoofdactiviteitenVerenigingsloket { get; init; } = - Array.Empty(); + public HoofdactiviteitVerenigingsloket[] HoofdactiviteitenVerenigingsloket { get; init; } = []; /// De werkingsgebieden van deze vereniging [DataMember(Name = "Werkingsgebieden")] - public Werkingsgebied[] Werkingsgebieden { get; init; } = - Array.Empty(); + public Werkingsgebied[] Werkingsgebieden { get; init; } = []; /// De sleutels die deze vereniging beheren [DataMember(Name = "Sleutels")] - public Sleutel[] Sleutels { get; init; } = Array.Empty(); + public Sleutel[] Sleutels { get; init; } = []; /// De relaties van deze vereniging [DataMember(Name = "Relaties")] - public Relatie[] Relaties { get; init; } = Array.Empty(); + public Relatie[] Relaties { get; init; } = []; /// De lidmaatschappen van deze vereniging [DataMember(Name = "Lidmaatschappen")] - public Lidmaatschap[] Lidmaatschappen { get; init; } = Array.Empty(); + public Lidmaatschap[] Lidmaatschappen { get; init; } = []; + + /// De VCode van de vereniging waarvan deze vereniging een dubbel is + [DataMember(Name = "IsDubbelVan")] + public string IsDubbelVan { get; set; } + + // De unieke identificatie codes van de corresponderende verenigingen + [DataMember(Name = "CorresponderendeVCodes")] + public string[] CorresponderendeVCodes { get; init; } = []; } diff --git a/src/AssociationRegistry.Public.ProjectionHost/Projections/Detail/PubliekVerenigingDetailProjection.cs b/src/AssociationRegistry.Public.ProjectionHost/Projections/Detail/PubliekVerenigingDetailProjection.cs index 3d50817d8..eab6b261e 100644 --- a/src/AssociationRegistry.Public.ProjectionHost/Projections/Detail/PubliekVerenigingDetailProjection.cs +++ b/src/AssociationRegistry.Public.ProjectionHost/Projections/Detail/PubliekVerenigingDetailProjection.cs @@ -211,6 +211,12 @@ public async Task Project(IEvent @event, IDocumentOpe public async Task Project(IEvent @event, IDocumentOperations ops) => await Update(@event, ops, PubliekVerenigingDetailProjector.Apply); + public async Task Project(IEvent @event, IDocumentOperations ops) + => await Update(@event, ops, PubliekVerenigingDetailProjector.Apply); + + public async Task Project(IEvent @event, IDocumentOperations ops) + => await Update(@event, ops, PubliekVerenigingDetailProjector.Apply); + private static async Task Update( IEvent @event, IDocumentOperations ops, diff --git a/src/AssociationRegistry.Public.ProjectionHost/Projections/Detail/PubliekVerenigingDetailProjector.cs b/src/AssociationRegistry.Public.ProjectionHost/Projections/Detail/PubliekVerenigingDetailProjector.cs index dfb29c517..3e90a1b06 100644 --- a/src/AssociationRegistry.Public.ProjectionHost/Projections/Detail/PubliekVerenigingDetailProjector.cs +++ b/src/AssociationRegistry.Public.ProjectionHost/Projections/Detail/PubliekVerenigingDetailProjector.cs @@ -79,6 +79,8 @@ public static PubliekVerenigingDetailDocument Create( CodeerSysteem = CodeerSysteem.VR, }, ], + IsDubbelVan = "", + CorresponderendeVCodes = [], }; public static PubliekVerenigingDetailDocument Create( @@ -154,6 +156,8 @@ public static PubliekVerenigingDetailDocument Create( CodeerSysteem = CodeerSysteem.KBO, }, ], + IsDubbelVan = "", + CorresponderendeVCodes = [], }; private static PubliekVerenigingDetailDocument.HoofdactiviteitVerenigingsloket MapHoofdactiviteit( @@ -775,4 +779,18 @@ public static void Apply(IEvent lidmaatschapWerdVerw .OrderBy(l => l.LidmaatschapId) .ToArray(); } + + public static void Apply(IEvent verenigingWerdGemarkeerdAlsDubbel, PubliekVerenigingDetailDocument document) + { + document.Status = VerenigingStatus.Dubbel; + document.IsDubbelVan = verenigingWerdGemarkeerdAlsDubbel.Data.VCodeAuthentiekeVereniging; + } + + public static void Apply(IEvent verenigingAanvaardeDubbeleVereniging, PubliekVerenigingDetailDocument document) + { + document.CorresponderendeVCodes = + document.CorresponderendeVCodes + .Append(verenigingAanvaardeDubbeleVereniging.Data.VCodeDubbeleVereniging) + .ToArray(); + } } diff --git a/src/AssociationRegistry.Public.Schema/Constants/VerenigingStatus.cs b/src/AssociationRegistry.Public.Schema/Constants/VerenigingStatus.cs index 9df97d25c..5bc4e6afc 100644 --- a/src/AssociationRegistry.Public.Schema/Constants/VerenigingStatus.cs +++ b/src/AssociationRegistry.Public.Schema/Constants/VerenigingStatus.cs @@ -4,4 +4,5 @@ public static class VerenigingStatus { public const string Actief = "Actief"; public const string Gestopt = "Gestopt"; + public const string Dubbel = "Dubbel"; } diff --git a/src/AssociationRegistry.Public.Schema/Detail/VerenigingDetailDocument.cs b/src/AssociationRegistry.Public.Schema/Detail/VerenigingDetailDocument.cs index 674ef7645..58cf0a2b4 100644 --- a/src/AssociationRegistry.Public.Schema/Detail/VerenigingDetailDocument.cs +++ b/src/AssociationRegistry.Public.Schema/Detail/VerenigingDetailDocument.cs @@ -24,18 +24,15 @@ public class PubliekVerenigingDetailDocument : IVCode, ISoftDeleted, ICanBeUitge public string Status { get; set; } = null!; public string DatumLaatsteAanpassing { get; set; } = null!; public Locatie[] Locaties { get; set; } = null!; - public Contactgegeven[] Contactgegevens { get; set; } = Array.Empty(); + public Contactgegeven[] Contactgegevens { get; set; } = []; - public HoofdactiviteitVerenigingsloket[] HoofdactiviteitenVerenigingsloket { get; set; } = - Array.Empty(); + public HoofdactiviteitVerenigingsloket[] HoofdactiviteitenVerenigingsloket { get; set; } = []; - public Werkingsgebied[] Werkingsgebieden { get; set; } = - Array.Empty(); - - public Sleutel[] Sleutels { get; set; } = Array.Empty(); - public Relatie[] Relaties { get; set; } = Array.Empty(); - public Lidmaatschap[] Lidmaatschappen { get; set; } = Array.Empty(); + public Werkingsgebied[] Werkingsgebieden { get; set; } = []; + public Sleutel[] Sleutels { get; set; } = []; + public Relatie[] Relaties { get; set; } = []; + public Lidmaatschap[] Lidmaatschappen { get; set; } = []; public bool? IsUitgeschrevenUitPubliekeDatastroom { get; set; } [Identity] public string VCode { get; set; } = null!; @@ -130,7 +127,6 @@ public record Lidmaatschap( string Identificatie, string Beschrijving); - public class AdresId { public string? Broncode { get; set; } @@ -150,6 +146,8 @@ public class Adres public bool Deleted { get; set; } public DateTimeOffset? DeletedAt { get; set; } + public string IsDubbelVan { get; set; } = string.Empty; + public string[] CorresponderendeVCodes { get; set; } = []; } public class JsonLdMetadata diff --git a/src/AssociationRegistry/Acties/AanvaardDubbel/AanvaardDubbeleVerenigingCommand.cs b/src/AssociationRegistry/Acties/AanvaardDubbel/AanvaardDubbeleVerenigingCommand.cs new file mode 100644 index 000000000..6c6d62af8 --- /dev/null +++ b/src/AssociationRegistry/Acties/AanvaardDubbel/AanvaardDubbeleVerenigingCommand.cs @@ -0,0 +1,5 @@ +namespace AssociationRegistry.Acties.AanvaardDubbel; + +using AssociationRegistry.Vereniging; + +public record AanvaardDubbeleVerenigingCommand(VCode VCode, VCode VCodeDubbeleVereniging); diff --git a/src/AssociationRegistry/Acties/AanvaardDubbel/AanvaardDubbeleVerenigingCommandHandler.cs b/src/AssociationRegistry/Acties/AanvaardDubbel/AanvaardDubbeleVerenigingCommandHandler.cs new file mode 100644 index 000000000..6af8e9bb4 --- /dev/null +++ b/src/AssociationRegistry/Acties/AanvaardDubbel/AanvaardDubbeleVerenigingCommandHandler.cs @@ -0,0 +1,23 @@ +namespace AssociationRegistry.Acties.AanvaardDubbel; + +using AssociationRegistry.EventStore; +using AssociationRegistry.Framework; +using AssociationRegistry.Vereniging; +using NodaTime; + +public class AanvaardDubbeleVerenigingCommandHandler(IVerenigingsRepository repository) +{ + public async Task Handle(AanvaardDubbeleVerenigingCommand command, CancellationToken cancellationToken) + { + var vereniging = await repository.Load(command.VCode); + + vereniging.AanvaardDubbeleVereniging(command.VCodeDubbeleVereniging); + + await repository.Save( + vereniging, + new CommandMetadata(EventStore.DigitaalVlaanderenOvoNumber, + SystemClock.Instance.GetCurrentInstant(), + Guid.NewGuid()), + cancellationToken); + } +} diff --git a/src/AssociationRegistry/Acties/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanCommand.cs b/src/AssociationRegistry/Acties/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanCommand.cs new file mode 100644 index 000000000..77b1b36f5 --- /dev/null +++ b/src/AssociationRegistry/Acties/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanCommand.cs @@ -0,0 +1,5 @@ +namespace AssociationRegistry.Acties.MarkeerAlsDubbelVan; + +using Vereniging; + +public record MarkeerAlsDubbelVanCommand(VCode VCode, VCode VCodeAuthentiekeVereniging); diff --git a/src/AssociationRegistry/Acties/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanCommandHandler.cs b/src/AssociationRegistry/Acties/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanCommandHandler.cs new file mode 100644 index 000000000..6afd1616e --- /dev/null +++ b/src/AssociationRegistry/Acties/MarkeerAlsDubbelVan/MarkeerAlsDubbelVanCommandHandler.cs @@ -0,0 +1,47 @@ +namespace AssociationRegistry.Acties.MarkeerAlsDubbelVan; + +using Framework; +using Marten; +using Messages; +using Vereniging; +using Vereniging.Exceptions; +using Wolverine.Marten; + +public class MarkeerAlsDubbelVanCommandHandler +{ + private readonly IVerenigingsRepository _verenigingsRepository; + private readonly IMartenOutbox _outbox; + private readonly IDocumentSession _session; + + public MarkeerAlsDubbelVanCommandHandler( + IVerenigingsRepository verenigingsRepository, + IMartenOutbox outbox, + IDocumentSession session + ) + { + _verenigingsRepository = verenigingsRepository; + _outbox = outbox; + _session = session; + } + + public async Task Handle( + CommandEnvelope message, + CancellationToken cancellationToken = default) + { + var vereniging = await _verenigingsRepository.Load(message.Command.VCode, message.Metadata.ExpectedVersion); + + if (await _verenigingsRepository.IsVerwijderd(message.Command.VCodeAuthentiekeVereniging)) + throw new VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging(); + + if (await _verenigingsRepository.IsDubbel(message.Command.VCodeAuthentiekeVereniging)) + throw new VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel(); + + vereniging.MarkeerAlsDubbelVan(message.Command.VCodeAuthentiekeVereniging); + + await _outbox.SendAsync(new AanvaardDubbeleVerenigingMessage(message.Command.VCodeAuthentiekeVereniging, message.Command.VCode)); + + var result = await _verenigingsRepository.Save(vereniging, _session, message.Metadata, cancellationToken); + + return CommandResult.Create(message.Command.VCode, result); + } +} diff --git a/src/AssociationRegistry/EventStore/VerenigingsRepository.cs b/src/AssociationRegistry/EventStore/VerenigingsRepository.cs index d047752f6..59354e86a 100644 --- a/src/AssociationRegistry/EventStore/VerenigingsRepository.cs +++ b/src/AssociationRegistry/EventStore/VerenigingsRepository.cs @@ -74,4 +74,18 @@ private void ThrowIfVerwijderd(VerenigingState verenigingState) if (verenigingState.IsVerwijderd) throw new VerenigingWerdVerwijderd(verenigingState.VCode); } + + public async Task IsDubbel(VCode vCode) + { + var verenigingState = await _eventStore.Load(vCode, null); + + return verenigingState.IsDubbel; + } + + private void ThrowIfDubbel(VerenigingState verenigingState) + { + if (verenigingState.IsDubbel) + throw new VerenigingWerdVerwijderd(verenigingState.VCode); + } + } diff --git a/src/AssociationRegistry/Events/VerenigingWerdGermarkeerdAlsDubbelVan.cs b/src/AssociationRegistry/Events/VerenigingWerdGermarkeerdAlsDubbelVan.cs new file mode 100644 index 000000000..439e09ffe --- /dev/null +++ b/src/AssociationRegistry/Events/VerenigingWerdGermarkeerdAlsDubbelVan.cs @@ -0,0 +1,10 @@ +namespace AssociationRegistry.Events; + +using Framework; +using Vereniging; + +public record VerenigingWerdGermarkeerdAlsDubbelVan(string VCode, string VCodeAuthentiekeVereniging) : IEvent +{ + public static VerenigingWerdGermarkeerdAlsDubbelVan With(VCode vCode, VCode vCodeAuthentiekeVereniging) + => new(vCode, vCodeAuthentiekeVereniging); +} diff --git a/src/AssociationRegistry/Events/VerenigingWerdToegevoegdAlsDubbel.cs b/src/AssociationRegistry/Events/VerenigingWerdToegevoegdAlsDubbel.cs new file mode 100644 index 000000000..39e119df2 --- /dev/null +++ b/src/AssociationRegistry/Events/VerenigingWerdToegevoegdAlsDubbel.cs @@ -0,0 +1,12 @@ +namespace AssociationRegistry.Events; + +using Framework; +using Vereniging; + +public record VerenigingAanvaardeDubbeleVereniging(string VCode, string VCodeDubbeleVereniging) : IEvent +{ + public static VerenigingAanvaardeDubbeleVereniging With(VCode vCode, VCode dubbeleVereniging) + => new(vCode, dubbeleVereniging); +} + + diff --git a/src/AssociationRegistry/Messages/AanvaardDubbeleVerenigingMessage.cs b/src/AssociationRegistry/Messages/AanvaardDubbeleVerenigingMessage.cs new file mode 100644 index 000000000..f0997bb00 --- /dev/null +++ b/src/AssociationRegistry/Messages/AanvaardDubbeleVerenigingMessage.cs @@ -0,0 +1,10 @@ +namespace AssociationRegistry.Messages; + +using Acties.AanvaardDubbel; +using AssociationRegistry.Vereniging; + +public record AanvaardDubbeleVerenigingMessage(string VCode, string VCodeDubbeleVereniging) +{ + public AanvaardDubbeleVerenigingCommand ToCommand() + => new(AssociationRegistry.Vereniging.VCode.Create(VCode), AssociationRegistry.Vereniging.VCode.Create(VCodeDubbeleVereniging)); +} diff --git a/src/AssociationRegistry/Resources/ExceptionMessages.Designer.cs b/src/AssociationRegistry/Resources/ExceptionMessages.Designer.cs index be1d49c9e..3302dfe80 100644 --- a/src/AssociationRegistry/Resources/ExceptionMessages.Designer.cs +++ b/src/AssociationRegistry/Resources/ExceptionMessages.Designer.cs @@ -646,6 +646,33 @@ public static string UnsupportedOperationForVerenigingstype { } } + /// + /// Looks up a localized string similar to Een vereniging kan geen dubbel worden van vereniging die zelf al een dubbel is van een andere vereniging.. + /// + public static string VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel { + get { + return ResourceManager.GetString("VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Een vereniging kan geen dubbel worden van een verwijderde vereniging.. + /// + public static string VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging { + get { + return ResourceManager.GetString("VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Een vereniging kan geen dubbel worden van zichzelf.. + /// + public static string VerenigingKanGeenDubbelWordenVanZichzelf { + get { + return ResourceManager.GetString("VerenigingKanGeenDubbelWordenVanZichzelf", resourceCulture); + } + } + /// /// Looks up a localized string similar to Een vereniging kan geen lid worden van een verwijderde vereniging.. /// diff --git a/src/AssociationRegistry/Resources/ExceptionMessages.resx b/src/AssociationRegistry/Resources/ExceptionMessages.resx index e91eee846..de766dd98 100644 --- a/src/AssociationRegistry/Resources/ExceptionMessages.resx +++ b/src/AssociationRegistry/Resources/ExceptionMessages.resx @@ -187,6 +187,15 @@ Een vereniging kan geen lid worden van een verwijderde vereniging. + + Een vereniging kan geen dubbel worden van een verwijderde vereniging. + + + Een vereniging kan geen dubbel worden van vereniging die zelf al een dubbel is van een andere vereniging. + + + Een vereniging kan geen dubbel worden van zichzelf. + Een lidmaatschap mag niet overlappen voor eenzelfde vereniging. diff --git a/src/AssociationRegistry/Vereniging/Exceptions/VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel.cs b/src/AssociationRegistry/Vereniging/Exceptions/VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel.cs new file mode 100644 index 000000000..89ab75685 --- /dev/null +++ b/src/AssociationRegistry/Vereniging/Exceptions/VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel.cs @@ -0,0 +1,17 @@ +namespace AssociationRegistry.Vereniging.Exceptions; + +using Be.Vlaanderen.Basisregisters.AggregateSource; +using Resources; +using System.Runtime.Serialization; + +[Serializable] +public class VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel : DomainException +{ + public VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel() : base(ExceptionMessages.VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel) + { + } + + protected VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +} diff --git a/src/AssociationRegistry/Vereniging/Exceptions/VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging.cs b/src/AssociationRegistry/Vereniging/Exceptions/VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging.cs new file mode 100644 index 000000000..a2b6167c1 --- /dev/null +++ b/src/AssociationRegistry/Vereniging/Exceptions/VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging.cs @@ -0,0 +1,17 @@ +namespace AssociationRegistry.Vereniging.Exceptions; + +using Be.Vlaanderen.Basisregisters.AggregateSource; +using Resources; +using System.Runtime.Serialization; + +[Serializable] +public class VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging : DomainException +{ + public VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging() : base(ExceptionMessages.VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging) + { + } + + protected VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +} diff --git a/src/AssociationRegistry/Vereniging/Exceptions/VerenigingKanGeenDubbelWordenVanZichzelf.cs b/src/AssociationRegistry/Vereniging/Exceptions/VerenigingKanGeenDubbelWordenVanZichzelf.cs new file mode 100644 index 000000000..47a3504a6 --- /dev/null +++ b/src/AssociationRegistry/Vereniging/Exceptions/VerenigingKanGeenDubbelWordenVanZichzelf.cs @@ -0,0 +1,29 @@ +namespace AssociationRegistry.Vereniging.Exceptions; + +using Be.Vlaanderen.Basisregisters.AggregateSource; +using Resources; +using System.Runtime.Serialization; + +[Serializable] +public class VerenigingKanGeenDubbelWordenVanZichzelf : DomainException +{ + public VerenigingKanGeenDubbelWordenVanZichzelf() : base(ExceptionMessages.VerenigingKanGeenDubbelWordenVanZichzelf) + { + } + + protected VerenigingKanGeenDubbelWordenVanZichzelf(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +} + +[Serializable] +public class InvalidOperationVerenigingKanGeenDubbelWordenVanZichzelf : ApplicationException +{ + public InvalidOperationVerenigingKanGeenDubbelWordenVanZichzelf() : base(ExceptionMessages.VerenigingKanGeenDubbelWordenVanZichzelf) + { + } + + protected InvalidOperationVerenigingKanGeenDubbelWordenVanZichzelf(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +} diff --git a/src/AssociationRegistry/Vereniging/IVerenigingsRepository.cs b/src/AssociationRegistry/Vereniging/IVerenigingsRepository.cs index f2572b8ea..03ff7c6b9 100644 --- a/src/AssociationRegistry/Vereniging/IVerenigingsRepository.cs +++ b/src/AssociationRegistry/Vereniging/IVerenigingsRepository.cs @@ -11,4 +11,5 @@ public interface IVerenigingsRepository Task Load(VCode vCode, long? expectedVersion = null) where TVereniging : IHydrate, new(); Task Load(KboNummer kboNummer, long? expectedVersion = null); Task IsVerwijderd(VCode vCode); + Task IsDubbel(VCode vCode); } diff --git a/src/AssociationRegistry/Vereniging/Vereniging.cs b/src/AssociationRegistry/Vereniging/Vereniging.cs index e9aaa3bb8..e38e3f9e0 100644 --- a/src/AssociationRegistry/Vereniging/Vereniging.cs +++ b/src/AssociationRegistry/Vereniging/Vereniging.cs @@ -232,6 +232,18 @@ public void SchrijfInInPubliekeDatastroom() AddEvent(new VerenigingWerdIngeschrevenInPubliekeDatastroom()); } + public void MarkeerAlsDubbelVan(VCode isDubbelVan) + { + Throw.If(isDubbelVan.Equals(VCode)); + AddEvent(VerenigingWerdGermarkeerdAlsDubbelVan.With(VCode, isDubbelVan)); + } + + public void AanvaardDubbeleVereniging(VCode dubbeleVereniging) + { + Throw.If(dubbeleVereniging.Equals(VCode)); + AddEvent(VerenigingAanvaardeDubbeleVereniging.With(VCode, dubbeleVereniging)); + } + public void Hydrate(VerenigingState obj) { Throw.If(obj.Verenigingstype != Verenigingstype.FeitelijkeVereniging); diff --git a/src/AssociationRegistry/Vereniging/VerenigingState.cs b/src/AssociationRegistry/Vereniging/VerenigingState.cs index 9111188a3..a7e996133 100644 --- a/src/AssociationRegistry/Vereniging/VerenigingState.cs +++ b/src/AssociationRegistry/Vereniging/VerenigingState.cs @@ -41,6 +41,9 @@ public string Identity public bool IsIngeschrevenOpWijzigingenUitKbo { get; private init; } public List HandledIdempotenceKeys { get; set; } = new(); public bool IsVerwijderd { get; set; } + public bool IsDubbel { get; set; } + + public string[] CorresponderendeVCodes { get; set; } = []; public long Version { get; set; } public VerenigingState Apply(FeitelijkeVerenigingWerdGeregistreerd @event) @@ -661,4 +664,16 @@ public VerenigingState Apply(LocatieDuplicaatWerdVerwijderdNaAdresMatch @event) public VerenigingState Apply(AdresHeeftGeenVerschillenMetAdressenregister @event) => this; + + public VerenigingState Apply(VerenigingWerdGermarkeerdAlsDubbelVan @event) + => this with + { + IsDubbel = true, + }; + + public VerenigingState Apply(VerenigingAanvaardeDubbeleVereniging @event) + => this with + { + CorresponderendeVCodes = CorresponderendeVCodes.Append(@event.VCodeDubbeleVereniging).ToArray(), + }; } diff --git a/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/CommandHandling/Given_A_Vereniging.cs b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/CommandHandling/Given_A_Vereniging.cs new file mode 100644 index 000000000..41a768862 --- /dev/null +++ b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/CommandHandling/Given_A_Vereniging.cs @@ -0,0 +1,75 @@ +namespace AssociationRegistry.Test.Admin.Api.Commands.FeitelijkeVereniging.When_MarkeerAlsDubbelVan.CommandHandling; + +using Acties.MarkeerAlsDubbelVan; +using AssociationRegistry.Framework; +using AutoFixture; +using Common.AutoFixture; +using Common.Framework; +using Common.Scenarios.CommandHandling; +using Events; +using FluentAssertions; +using GrarConsumer.FusieEvents.When_Consuming_Merger_Events; +using Marten; +using Messages; +using Moq; +using Vereniging; +using Wolverine.Marten; +using Xunit; +using Xunit.Categories; + +[UnitTest] +public class Given_A_Vereniging +{ + private readonly Fixture _fixture; + private readonly FeitelijkeVerenigingWerdGeregistreerdScenario _scenario; + private readonly VerenigingRepositoryMock _verenigingRepositoryMock; + private readonly MarkeerAlsDubbelVanCommandHandler _commandHandler; + private AanvaardDubbeleVerenigingMessage _outboxMessage; + + public Given_A_Vereniging() + { + _fixture = new Fixture().CustomizeDomain(); + _scenario = new FeitelijkeVerenigingWerdGeregistreerdScenario(); + _verenigingRepositoryMock = new VerenigingRepositoryMock(_scenario.GetVerenigingState()); + + var martenOutbox = new Mock(); + martenOutbox.CaptureOutboxSendAsyncMessage(message => _outboxMessage = message); + + _commandHandler = new MarkeerAlsDubbelVanCommandHandler( + _verenigingRepositoryMock, + martenOutbox.Object, + Mock.Of() + ); + } + + [Fact] + public async Task Then_It_Saves_An_VerenigingWerdGermarkeerdAlsDubbel_Event() + { + var command = _fixture.Create() with + { + VCode = _scenario.VCode, + VCodeAuthentiekeVereniging = _fixture.Create(), + }; + + await _commandHandler.Handle(new CommandEnvelope(command, _fixture.Create())); + + _verenigingRepositoryMock.ShouldHaveSaved( + new VerenigingWerdGermarkeerdAlsDubbelVan( + _scenario.VCode, + command.VCodeAuthentiekeVereniging)); + } + + [Fact] + public async Task Then_It_Sends_A_Message_To_The_Outbox() + { + var command = _fixture.Create() with + { + VCode = _scenario.VCode, + VCodeAuthentiekeVereniging = _fixture.Create(), + }; + + await _commandHandler.Handle(new CommandEnvelope(command, _fixture.Create())); + + _outboxMessage.Should().BeEquivalentTo(new AanvaardDubbeleVerenigingMessage(command.VCodeAuthentiekeVereniging, command.VCode)); + } +} diff --git a/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/CommandHandling/Given_VCode_Equals_IsDubbelVan.cs b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/CommandHandling/Given_VCode_Equals_IsDubbelVan.cs new file mode 100644 index 000000000..4e46ed873 --- /dev/null +++ b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/CommandHandling/Given_VCode_Equals_IsDubbelVan.cs @@ -0,0 +1,56 @@ +namespace AssociationRegistry.Test.Admin.Api.Commands.FeitelijkeVereniging.When_MarkeerAlsDubbelVan.CommandHandling; + +using Acties.MarkeerAlsDubbelVan; +using AssociationRegistry.Framework; +using AutoFixture; +using Common.AutoFixture; +using Common.Framework; +using Common.Scenarios.CommandHandling; +using Events; +using FluentAssertions; +using Marten; +using Moq; +using Resources; +using Vereniging; +using Vereniging.Exceptions; +using Wolverine.Marten; +using Xunit; +using Xunit.Categories; + +[UnitTest] +public class Given_VCode_Equals_IsDubbelVan +{ + private readonly Fixture _fixture; + private readonly FeitelijkeVerenigingWerdGeregistreerdScenario _scenario; + private readonly VerenigingRepositoryMock _verenigingRepositoryMock; + private readonly MarkeerAlsDubbelVanCommandHandler _commandHandler; + + public Given_VCode_Equals_IsDubbelVan() + { + _fixture = new Fixture().CustomizeDomain(); + _scenario = new FeitelijkeVerenigingWerdGeregistreerdScenario(); + _verenigingRepositoryMock = new VerenigingRepositoryMock(_scenario.GetVerenigingState()); + + _commandHandler = new MarkeerAlsDubbelVanCommandHandler( + _verenigingRepositoryMock, + Mock.Of(), + Mock.Of() + ); + } + + [Fact] + public async Task Then_Throws_VerenigingKanGeenDubbelWordenVanZichzelf() + { + var command = _fixture.Create() with + { + VCode = _scenario.VCode, + VCodeAuthentiekeVereniging = _scenario.VCode, + }; + + var exception = await Assert + .ThrowsAsync + (async () => await _commandHandler.Handle( + new CommandEnvelope(command, _fixture.Create()))); + exception.Message.Should().Be(ExceptionMessages.VerenigingKanGeenDubbelWordenVanZichzelf); + } +} diff --git a/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestMapping/To_A_MarkeerAlsDubbelVanCommand.cs b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestMapping/To_A_MarkeerAlsDubbelVanCommand.cs new file mode 100644 index 000000000..dd7bdd0a5 --- /dev/null +++ b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestMapping/To_A_MarkeerAlsDubbelVanCommand.cs @@ -0,0 +1,32 @@ +namespace AssociationRegistry.Test.Admin.Api.Commands.FeitelijkeVereniging.When_MarkeerAlsDubbelVan.RequestMapping; + +using AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan.RequestModels; +using AutoFixture; +using Common.AutoFixture; +using FluentAssertions; +using Vereniging; +using Xunit; +using Xunit.Categories; + +[UnitTest] +public class To_A_MarkeerAlsDubbelVanCommand +{ + [Fact] + public void Then_We_Get_A_MarkeerAlsDubbelVanCommand() + { + var fixture = new Fixture().CustomizeAdminApi(); + + var vCodeA = fixture.Create(); + var vCodeB = fixture.Create(); + + var request = new MarkeerAlsDubbelVanRequest + { + IsDubbelVan = vCodeB.ToString(), + }; + + var actual = request.ToCommand(vCodeA); + + actual.VCode.Should().BeEquivalentTo(vCodeA); + actual.VCodeAuthentiekeVereniging.Should().BeEquivalentTo(vCodeB); + } +} diff --git a/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestValidating/Is_Empty.cs b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestValidating/Is_Empty.cs new file mode 100644 index 000000000..5b1f179e3 --- /dev/null +++ b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestValidating/Is_Empty.cs @@ -0,0 +1,25 @@ +namespace AssociationRegistry.Test.Admin.Api.Commands.FeitelijkeVereniging.When_MarkeerAlsDubbelVan.RequestValidating; + +using AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan; +using AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan.RequestModels; +using FluentValidation.TestHelper; +using Framework; +using Xunit; + +public class Is_Empty : ValidatorTest +{ + [Fact] + public void Has_validation_error_IsDubbelVan_is_verplicht() + { + var validator = new MarkeerAlsDubbelVanValidator(); + + var request = new MarkeerAlsDubbelVanRequest + { + IsDubbelVan = "", + }; + var result = validator.TestValidate(request); + + result.ShouldHaveValidationErrorFor(toeRequest => toeRequest.IsDubbelVan) + .WithErrorMessage($"'{nameof(MarkeerAlsDubbelVanRequest.IsDubbelVan)}' is verplicht."); + } +} diff --git a/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestValidating/Is_Null.cs b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestValidating/Is_Null.cs new file mode 100644 index 000000000..628d64510 --- /dev/null +++ b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestValidating/Is_Null.cs @@ -0,0 +1,25 @@ +namespace AssociationRegistry.Test.Admin.Api.Commands.FeitelijkeVereniging.When_MarkeerAlsDubbelVan.RequestValidating; + +using AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan; +using AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan.RequestModels; +using FluentValidation.TestHelper; +using Framework; +using Xunit; + +public class Is_Null : ValidatorTest +{ + [Fact] + public void Has_validation_error_IsDubbelVan_is_verplicht() + { + var validator = new MarkeerAlsDubbelVanValidator(); + + var request = new MarkeerAlsDubbelVanRequest + { + IsDubbelVan = null, + }; + var result = validator.TestValidate(request); + + result.ShouldHaveValidationErrorFor(toeRequest => toeRequest.IsDubbelVan) + .WithErrorMessage($"'{nameof(MarkeerAlsDubbelVanRequest.IsDubbelVan)}' is verplicht."); + } +} diff --git a/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestValidating/Is_Valid.cs b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestValidating/Is_Valid.cs new file mode 100644 index 000000000..ebb4e40ff --- /dev/null +++ b/test/AssociationRegistry.Test.Admin.Api/Commands/FeitelijkeVereniging/When_MarkeerAlsDubbelVan/RequestValidating/Is_Valid.cs @@ -0,0 +1,25 @@ +namespace AssociationRegistry.Test.Admin.Api.Commands.FeitelijkeVereniging.When_MarkeerAlsDubbelVan.RequestValidating; + +using AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan; +using AssociationRegistry.Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan.RequestModels; +using FluentValidation.TestHelper; +using Framework; +using Xunit; + +public class Is_Valid : ValidatorTest +{ + [Fact] + public void Has_no_validation_errors() + { + var validator = new MarkeerAlsDubbelVanValidator(); + + var request = new MarkeerAlsDubbelVanRequest + { + IsDubbelVan = "V0001001", + }; + + var result = validator.TestValidate(request); + + result.ShouldNotHaveAnyValidationErrors(); + } +} diff --git a/test/AssociationRegistry.Test.Admin.Api/Framework/templates/DetailVerenigingResponse.json b/test/AssociationRegistry.Test.Admin.Api/Framework/templates/DetailVerenigingResponse.json index faf513aea..7681a921a 100644 --- a/test/AssociationRegistry.Test.Admin.Api/Framework/templates/DetailVerenigingResponse.json +++ b/test/AssociationRegistry.Test.Admin.Api/Framework/templates/DetailVerenigingResponse.json @@ -179,7 +179,8 @@ }, {{end}} ], - "bron": "{{vereniging.bron}}" + "bron": "{{vereniging.bron}}", + "isDubbelVan":"" }, "metadata": { "datumLaatsteAanpassing": "{{datumlaatsteaanpassing}}" diff --git a/test/AssociationRegistry.Test.Admin.Api/GrarConsumer/FusieEvents/When_Consuming_Merger_Events/SetupMockExtension.cs b/test/AssociationRegistry.Test.Admin.Api/GrarConsumer/FusieEvents/When_Consuming_Merger_Events/SetupMockExtension.cs index 79e70026b..594a02295 100644 --- a/test/AssociationRegistry.Test.Admin.Api/GrarConsumer/FusieEvents/When_Consuming_Merger_Events/SetupMockExtension.cs +++ b/test/AssociationRegistry.Test.Admin.Api/GrarConsumer/FusieEvents/When_Consuming_Merger_Events/SetupMockExtension.cs @@ -8,6 +8,8 @@ using Grar.GrarUpdates.Fusies.TeHeradresserenLocaties; using Grar.GrarUpdates.Fusies.TeOntkoppelenLocaties; using Moq; +using Wolverine; +using Wolverine.Marten; public static class SetupMockExtension { @@ -16,6 +18,15 @@ public static void CaptureQueueOverkoepelendeGrarMessage( Action action) { sqsClientWrapper.Setup(v => v.QueueMessage(It.IsAny())) - .Callback(action); + .Callback(action); + } + + + public static void CaptureOutboxSendAsyncMessage( + this Mock outbox, + Action action) + { + outbox.Setup(v => v.SendAsync(It.IsAny(), It.IsAny())) + .Callback((arg1, _) => action(arg1)); } } diff --git a/test/AssociationRegistry.Test.Common/Framework/VerenigingRepositoryMock.cs b/test/AssociationRegistry.Test.Common/Framework/VerenigingRepositoryMock.cs index 81dc65cd5..4bab731db 100644 --- a/test/AssociationRegistry.Test.Common/Framework/VerenigingRepositoryMock.cs +++ b/test/AssociationRegistry.Test.Common/Framework/VerenigingRepositoryMock.cs @@ -73,6 +73,9 @@ public async Task Load(KboNummer kboNummer, public Task IsVerwijderd(VCode vCode) => Task.FromResult(false); + public Task IsDubbel(VCode vCode) + => Task.FromResult(false); + public void ShouldHaveLoaded(params string[] keys) where TVereniging : IHydrate, new() { _invocationsLoad.Should().BeEquivalentTo( diff --git a/test/AssociationRegistry.Test.E2E/Scenarios/Requests/FeitelijkeVereniging/MarkeerAlsDubbelVanRequestFactory.cs b/test/AssociationRegistry.Test.E2E/Scenarios/Requests/FeitelijkeVereniging/MarkeerAlsDubbelVanRequestFactory.cs new file mode 100644 index 000000000..79e37296d --- /dev/null +++ b/test/AssociationRegistry.Test.E2E/Scenarios/Requests/FeitelijkeVereniging/MarkeerAlsDubbelVanRequestFactory.cs @@ -0,0 +1,41 @@ +namespace AssociationRegistry.Test.E2E.Scenarios.Requests.FeitelijkeVereniging; + +using Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan.RequestModels; +using Alba; +using Framework.ApiSetup; +using Givens.FeitelijkeVereniging; +using Marten.Events; +using System.Net; +using Vereniging; + +public class MarkeerAlsDubbelVanRequestFactory : ITestRequestFactory +{ + private readonly MultipleWerdGeregistreerdScenario _scenario; + + public MarkeerAlsDubbelVanRequestFactory(MultipleWerdGeregistreerdScenario scenario) + { + _scenario = scenario; + } + + public async Task> ExecuteRequest(IApiSetup apiSetup) + { + var request = new MarkeerAlsDubbelVanRequest + { + IsDubbelVan = _scenario.AndereFeitelijkeVerenigingWerdGeregistreerd.VCode, + }; + + await apiSetup.AdminApiHost.Scenario(s => + { + s.Post + .Json(request, JsonStyle.Mvc) + .ToUrl($"/v1/verenigingen/{_scenario.FeitelijkeVerenigingWerdGeregistreerd.VCode}/dubbelVan"); + + s.StatusCodeShouldBe(HttpStatusCode.Accepted); + }); + + await apiSetup.AdminProjectionHost.WaitForNonStaleProjectionDataAsync(TimeSpan.FromSeconds(60)); + await apiSetup.PublicProjectionHost.WaitForNonStaleProjectionDataAsync(TimeSpan.FromSeconds(60)); + + return new RequestResult(VCode.Create(_scenario.FeitelijkeVerenigingWerdGeregistreerd.VCode), request); + } +} diff --git a/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Beheer/Detail/Returns_Detail_With_Dubbel_Van.cs b/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Beheer/Detail/Returns_Detail_With_Dubbel_Van.cs new file mode 100644 index 000000000..bb60d2a54 --- /dev/null +++ b/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Beheer/Detail/Returns_Detail_With_Dubbel_Van.cs @@ -0,0 +1,41 @@ +namespace AssociationRegistry.Test.E2E.When_Markeer_Als_Dubbel_Van.Beheer.Detail; + +using Admin.Api.Verenigingen.Detail.ResponseModels; +using Admin.Schema.Constants; +using FluentAssertions; +using Framework.AlbaHost; +using Xunit; + +[Collection(FullBlownApiCollection.Name)] +public class Returns_Detail_With_Dubbel_Van : IClassFixture, IAsyncLifetime +{ + private readonly MarkeerAlsDubbelVanContext _context; + + public Returns_Detail_With_Dubbel_Van(MarkeerAlsDubbelVanContext context) + { + _context = context; + } + + [Fact] + public void With_IsDubbelVan_VCode_Of_AndereFeitelijkeVerenigingWerdGeregistreerd() + { + Response.Vereniging.IsDubbelVan.Should().Be(_context.Scenario.AndereFeitelijkeVerenigingWerdGeregistreerd.VCode); + } + + [Fact] + public void With_Status_Is_Dubbel() + { + Response.Vereniging.Status.Should().Be(VerenigingStatus.Dubbel); + } + + public DetailVerenigingResponse Response { get; set; } + + public async Task InitializeAsync() + { + Response = _context.ApiSetup.AdminApiHost.GetBeheerDetail(_context.VCode); + } + + public async Task DisposeAsync() + { + } +} diff --git a/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Beheer/DetailAuthentiekeVereniging/Returns_Detail_AuthentiekeVereniging.cs b/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Beheer/DetailAuthentiekeVereniging/Returns_Detail_AuthentiekeVereniging.cs new file mode 100644 index 000000000..4b0c2b6eb --- /dev/null +++ b/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Beheer/DetailAuthentiekeVereniging/Returns_Detail_AuthentiekeVereniging.cs @@ -0,0 +1,66 @@ +namespace AssociationRegistry.Test.E2E.When_Markeer_Als_Dubbel_Van.Beheer.DetailAuthentiekeVereniging; + +using AssociationRegistry.Admin.Api.Verenigingen.Detail.ResponseModels; +using AssociationRegistry.Admin.Schema.Constants; +using AssociationRegistry.Test.E2E.Framework.AlbaHost; +using FluentAssertions; +using Xunit; +using Xunit.Abstractions; + +[Collection(FullBlownApiCollection.Name)] +public class Returns_Detail_AuthentiekeVereniging : IClassFixture, IAsyncLifetime +{ + private readonly MarkeerAlsDubbelVanContext _context; + private readonly ITestOutputHelper _helper; + + public Returns_Detail_AuthentiekeVereniging(MarkeerAlsDubbelVanContext context, ITestOutputHelper helper) + { + _context = context; + _helper = helper; + } + + [Fact] + public void With_IsDubbelVan_VCode_Of_AndereFeitelijkeVerenigingWerdGeregistreerd() + { + Response.Vereniging.IsDubbelVan.Should().BeEmpty(); + } + + [Fact] + public async Task With_DubbeleVereniging_In_CorresponderendeVCodes() + { + var tryCounter = 0; + + while (tryCounter < 20) + { + ++tryCounter; + await Task.Delay(500); + + _helper.WriteLine($"Looking for CorresponderendeVCodes (try {tryCounter})..."); + if (Response.Vereniging.CorresponderendeVCodes.Any()) + { + _helper.WriteLine("Found it!"); + break; + } + + _helper.WriteLine("Did not find any CorresponderendeVCodes."); + } + Response.Vereniging.CorresponderendeVCodes.Should().Contain(_context.Scenario.FeitelijkeVerenigingWerdGeregistreerd.VCode); + } + + [Fact] + public void With_Status_Is_Actief() + { + Response.Vereniging.Status.Should().Be(VerenigingStatus.Actief); + } + + public DetailVerenigingResponse Response { get; set; } + + public async Task InitializeAsync() + { + Response = _context.ApiSetup.AdminApiHost.GetBeheerDetail(_context.Scenario.AndereFeitelijkeVerenigingWerdGeregistreerd.VCode); + } + + public async Task DisposeAsync() + { + } +} diff --git a/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/MarkeerAlsDubbelVanContext.cs b/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/MarkeerAlsDubbelVanContext.cs new file mode 100644 index 000000000..aec3dbb6a --- /dev/null +++ b/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/MarkeerAlsDubbelVanContext.cs @@ -0,0 +1,31 @@ +namespace AssociationRegistry.Test.E2E.When_Markeer_Als_Dubbel_Van; + +using Admin.Api.Verenigingen.Dubbels.FeitelijkeVereniging.MarkeerAlsDubbelVan.RequestModels; +using Framework.ApiSetup; +using Framework.TestClasses; +using Marten.Events; +using Microsoft.Extensions.DependencyInjection; +using Nest; +using Scenarios.Givens.FeitelijkeVereniging; +using Scenarios.Requests.FeitelijkeVereniging; +using Vereniging; + +public class MarkeerAlsDubbelVanContext: TestContextBase +{ + public VCode VCode => RequestResult.VCode; + public MultipleWerdGeregistreerdScenario Scenario { get; } + + public MarkeerAlsDubbelVanContext(FullBlownApiSetup apiSetup) + { + ApiSetup = apiSetup; + Scenario = new(); + } + + public override async Task InitializeAsync() + { + await ApiSetup.ExecuteGiven(Scenario); + RequestResult = await new MarkeerAlsDubbelVanRequestFactory(Scenario).ExecuteRequest(ApiSetup); + await ApiSetup.AdminProjectionHost.WaitForNonStaleProjectionDataAsync(TimeSpan.FromSeconds(10)); + await ApiSetup.AdminApiHost.Services.GetRequiredService().Indices.RefreshAsync(Indices.All); + } +} diff --git a/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Publiek/Detail/Returns_Detail_With_Dubbel_Van.cs b/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Publiek/Detail/Returns_Detail_With_Dubbel_Van.cs new file mode 100644 index 000000000..d2058adc1 --- /dev/null +++ b/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Publiek/Detail/Returns_Detail_With_Dubbel_Van.cs @@ -0,0 +1,41 @@ +namespace AssociationRegistry.Test.E2E.When_Markeer_Als_Dubbel_Van.Publiek.Detail; + +using FluentAssertions; +using Framework.AlbaHost; +using Public.Api.Verenigingen.Detail.ResponseModels; +using Public.Schema.Constants; +using Xunit; + +[Collection(FullBlownApiCollection.Name)] +public class Returns_Detail_With_Dubbel_Van : IClassFixture, IAsyncLifetime +{ + private readonly MarkeerAlsDubbelVanContext _context; + + public Returns_Detail_With_Dubbel_Van(MarkeerAlsDubbelVanContext context) + { + _context = context; + } + + [Fact] + public void With_IsDubbelVan_VCode_Of_AndereFeitelijkeVerenigingWerdGeregistreerd() + { + Response.Vereniging.IsDubbelVan.Should().Be(_context.Scenario.AndereFeitelijkeVerenigingWerdGeregistreerd.VCode); + } + + [Fact] + public void With_Status_Is_Dubbel() + { + Response.Vereniging.Status.Should().Be(VerenigingStatus.Dubbel); + } + + public PubliekVerenigingDetailResponse Response { get; set; } + + public async Task InitializeAsync() + { + Response = _context.ApiSetup.PublicApiHost.GetPubliekDetail(_context.VCode); + } + + public async Task DisposeAsync() + { + } +} diff --git a/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Publiek/DetailAuthentiekeVereniging/Returns_Detail_AuthentiekeVereniging.cs b/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Publiek/DetailAuthentiekeVereniging/Returns_Detail_AuthentiekeVereniging.cs new file mode 100644 index 000000000..79aa9917d --- /dev/null +++ b/test/AssociationRegistry.Test.E2E/When_Markeer_Als_Dubbel_Van/Publiek/DetailAuthentiekeVereniging/Returns_Detail_AuthentiekeVereniging.cs @@ -0,0 +1,66 @@ +namespace AssociationRegistry.Test.E2E.When_Markeer_Als_Dubbel_Van.Publiek.DetailAuthentiekeVereniging; + +using FluentAssertions; +using Framework.AlbaHost; +using Public.Api.Verenigingen.Detail.ResponseModels; +using Public.Schema.Constants; +using Xunit; +using Xunit.Abstractions; + +[Collection(FullBlownApiCollection.Name)] +public class Returns_Detail_AuthentiekeVereniging : IClassFixture, IAsyncLifetime +{ + private readonly MarkeerAlsDubbelVanContext _context; + private readonly ITestOutputHelper _helper; + + public Returns_Detail_AuthentiekeVereniging(MarkeerAlsDubbelVanContext context, ITestOutputHelper helper) + { + _context = context; + _helper = helper; + } + + [Fact] + public void With_IsDubbelVan_VCode_Of_AndereFeitelijkeVerenigingWerdGeregistreerd() + { + Response.Vereniging.IsDubbelVan.Should().BeEmpty(); + } + + [Fact] + public async Task With_DubbeleVereniging_In_CorresponderendeVCodes() + { + var tryCounter = 0; + + while (tryCounter < 20) + { + ++tryCounter; + await Task.Delay(500); + + _helper.WriteLine($"Looking for CorresponderendeVCodes (try {tryCounter})..."); + if (Response.Vereniging.CorresponderendeVCodes.Any()) + { + _helper.WriteLine("Found it!"); + break; + } + + _helper.WriteLine("Did not find any CorresponderendeVCodes."); + } + Response.Vereniging.CorresponderendeVCodes.Should().Contain(_context.Scenario.FeitelijkeVerenigingWerdGeregistreerd.VCode); + } + + [Fact] + public void With_Status_Is_Actief() + { + Response.Vereniging.Status.Should().Be(VerenigingStatus.Actief); + } + + public PubliekVerenigingDetailResponse Response { get; set; } + + public async Task InitializeAsync() + { + Response = _context.ApiSetup.PublicApiHost.GetPubliekDetail(_context.Scenario.AndereFeitelijkeVerenigingWerdGeregistreerd.VCode); + } + + public async Task DisposeAsync() + { + } +} diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/Returns_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/Returns_DetailResponse.cs index 0ea8a34ef..0d59a1bac 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/Returns_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/Returns_DetailResponse.cs @@ -79,6 +79,7 @@ public async Task WithFeitelijkeVereniging() Relaties = MapRelaties([], TestContext.VCode), Lidmaatschappen = [], Sleutels = MapSleutels(Request, TestContext.VCode), + IsDubbelVan = string.Empty, }, compareConfig: AdminDetailComparisonConfig.Instance); private static Sleutel[] MapSleutels(RegistreerFeitelijkeVerenigingRequest request, string vCode) diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/Returns_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/Returns_DetailResponse.cs index 09ab14f24..faea515d3 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/Returns_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/Returns_DetailResponse.cs @@ -78,6 +78,8 @@ public async Task WithFeitelijkeVereniging() Locaties = MapLocaties(Request.Locaties, _testContext.VCode), Relaties = MapRelaties([], _testContext.VCode), Sleutels = MapSleutels(Request, _testContext.VCode), + IsDubbelVan = string.Empty, + CorresponderendeVCodes = [], }, compareConfig: AdminDetailComparisonConfig.Instance); private static Sleutel[] MapSleutels(RegistreerFeitelijkeVerenigingRequest request, string vCode) diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging_With_Potential_Duplicates/Beheer/Detail/Returns_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging_With_Potential_Duplicates/Beheer/Detail/Returns_DetailResponse.cs index 6aca743f9..041fe6084 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging_With_Potential_Duplicates/Beheer/Detail/Returns_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging_With_Potential_Duplicates/Beheer/Detail/Returns_DetailResponse.cs @@ -79,6 +79,7 @@ public async Task WithFeitelijkeVereniging() Relaties = MapRelaties([], TestContext.VCode), Sleutels = MapSleutels(Request, TestContext.VCode), Lidmaatschappen = [], + IsDubbelVan = string.Empty, }, compareConfig: AdminDetailComparisonConfig.Instance); private static Sleutel[] MapSleutels(RegistreerFeitelijkeVerenigingRequest request, string vCode) diff --git a/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens/Beheer/Detail/Returns_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens/Beheer/Detail/Returns_DetailResponse.cs index f31d9b936..d0ba25fb0 100644 --- a/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens/Beheer/Detail/Returns_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens/Beheer/Detail/Returns_DetailResponse.cs @@ -82,5 +82,6 @@ public async Task WithFeitelijkeVereniging() Relaties = BeheerDetailResponseMapper.MapRelaties([], TestContext.VCode), Lidmaatschappen = [], Sleutels = BeheerDetailResponseMapper.MapSleutels(Request, TestContext.VCode), + IsDubbelVan = string.Empty, }, compareConfig: AdminDetailComparisonConfig.Instance); } diff --git a/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens/Publiek/Detail/Returns_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens/Publiek/Detail/Returns_DetailResponse.cs index 89e629600..aa1b1b433 100644 --- a/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens/Publiek/Detail/Returns_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens/Publiek/Detail/Returns_DetailResponse.cs @@ -71,6 +71,8 @@ public async Task WithFeitelijkeVereniging() Locaties = PubliekDetailResponseMapper.MapLocaties(_testContext.RegistratieData.Locaties, _testContext.VCode), Relaties = PubliekDetailResponseMapper.MapRelaties([], _testContext.VCode), Sleutels = PubliekDetailResponseMapper.MapSleutels(Request, _testContext.VCode), + IsDubbelVan = string.Empty, + CorresponderendeVCodes = [], }, compareConfig: AdminDetailComparisonConfig.Instance); public override Func GetResponse diff --git a/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens_Kbo/Beheer/Detail/Returns_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens_Kbo/Beheer/Detail/Returns_DetailResponse.cs index ee891fb4e..b267a8c8a 100644 --- a/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens_Kbo/Beheer/Detail/Returns_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens_Kbo/Beheer/Detail/Returns_DetailResponse.cs @@ -76,6 +76,7 @@ public async Task WithVerenigingMetRechtspersoonlijkheid() Relaties = [], Lidmaatschappen = [], Sleutels = BeheerDetailResponseMapper.MapSleutels(TestContext.VCode, TestContext.RegistratieData.KboNummer), + IsDubbelVan = string.Empty, }, compareConfig: AdminDetailComparisonConfig.Instance); public override Func GetResponse diff --git a/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens_Kbo/Publiek/Detail/Returns_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens_Kbo/Publiek/Detail/Returns_DetailResponse.cs index e708f5875..a0c6a55c7 100644 --- a/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens_Kbo/Publiek/Detail/Returns_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Wijzig_Basisgegevens_Kbo/Publiek/Detail/Returns_DetailResponse.cs @@ -71,6 +71,8 @@ public async Task WithVerenigingMetRechtspersoonlijkheid() Locaties = [], Relaties = [], Sleutels = PubliekDetailResponseMapper.MapSleutels(_testContext.VCode, _testContext.RegistratieData.KboNummer), + IsDubbelVan = string.Empty, + CorresponderendeVCodes = [], }, compareConfig: AdminDetailComparisonConfig.Instance); public override Func GetResponse diff --git a/test/AssociationRegistry.Test.Projections/Beheer/Detail/Dubbels/Given_VerenigingWerdGemarkeerdAlsDubbelVan.cs b/test/AssociationRegistry.Test.Projections/Beheer/Detail/Dubbels/Given_VerenigingWerdGemarkeerdAlsDubbelVan.cs new file mode 100644 index 000000000..f65e7a9c7 --- /dev/null +++ b/test/AssociationRegistry.Test.Projections/Beheer/Detail/Dubbels/Given_VerenigingWerdGemarkeerdAlsDubbelVan.cs @@ -0,0 +1,21 @@ +namespace AssociationRegistry.Test.Projections.Beheer.Detail.Dubbels; + +using Admin.Schema.Constants; + +[Collection(nameof(ProjectionContext))] +public class Given_VerenigingWerdGemarkeerdAlsDubbelVan(BeheerDetailScenarioFixture fixture) + : BeheerDetailScenarioClassFixture +{ + [Fact] + public void Metadata_Is_Updated() + => fixture.Result + .Metadata.Version.Should().Be(2); + + [Fact] + public void Document_IsDubbelVan_Is_Updated() + => fixture.Result.IsDubbelVan.Should().Be(fixture.Scenario.VerenigingWerdGermarkeerdAlsDubbelVan.VCodeAuthentiekeVereniging); + + [Fact] + public void Document_Status_Is_Dubbel() + => fixture.Result.Status.Should().Be(VerenigingStatus.Dubbel); +} diff --git a/test/AssociationRegistry.Test.Projections/Beheer/Detail/Dubbels/Given_VerenigingWerdToegevoegdAlsDubbel.cs b/test/AssociationRegistry.Test.Projections/Beheer/Detail/Dubbels/Given_VerenigingWerdToegevoegdAlsDubbel.cs new file mode 100644 index 000000000..25f7ed1bc --- /dev/null +++ b/test/AssociationRegistry.Test.Projections/Beheer/Detail/Dubbels/Given_VerenigingWerdToegevoegdAlsDubbel.cs @@ -0,0 +1,25 @@ +namespace AssociationRegistry.Test.Projections.Beheer.Detail.Dubbels; + +using Admin.Schema.Constants; + +[Collection(nameof(ProjectionContext))] +public class Given_VerenigingWerdToegevoegdAlsDubbel(BeheerDetailScenarioFixture fixture) + : BeheerDetailScenarioClassFixture +{ + [Fact] + public void Metadata_Is_Updated() + => fixture.Result + .Metadata.Version.Should().Be(2); + + [Fact] + public void Document_IsDubbelVan_Is_Updated() + => fixture.Result.IsDubbelVan.Should().BeEmpty(); + + [Fact] + public void Document_Status_Is_Actief() + => fixture.Result.Status.Should().Be(VerenigingStatus.Actief); + + [Fact] + public void Document_Has_DubbeleVereniging_In_CorresponderendeVCodes() + => fixture.Result.CorresponderendeVCodes.Should().Contain(fixture.Scenario.DubbeleVerenigingWerdGeregistreerd.VCode); +} diff --git a/test/AssociationRegistry.Test.Projections/Publiek/Detail/Dubbels/Given_VerenigingWerdGemarkeerdAlsDubbelVan.cs b/test/AssociationRegistry.Test.Projections/Publiek/Detail/Dubbels/Given_VerenigingWerdGemarkeerdAlsDubbelVan.cs new file mode 100644 index 000000000..62b8369c3 --- /dev/null +++ b/test/AssociationRegistry.Test.Projections/Publiek/Detail/Dubbels/Given_VerenigingWerdGemarkeerdAlsDubbelVan.cs @@ -0,0 +1,16 @@ +namespace AssociationRegistry.Test.Projections.Publiek.Detail.Dubbels; + +using Public.Schema.Constants; + +[Collection(nameof(ProjectionContext))] +public class Given_VerenigingWerdGemarkeerdAlsDubbelVan(PubliekDetailScenarioFixture fixture) + : PubliekDetailScenarioClassFixture +{ + [Fact] + public void Document_IsDubbelVan_Is_Updated() + => fixture.Result.IsDubbelVan.Should().Be(fixture.Scenario.VerenigingWerdGermarkeerdAlsDubbelVan.VCodeAuthentiekeVereniging); + + [Fact] + public void Document_Status_Is_Dubbel() + => fixture.Result.Status.Should().Be(VerenigingStatus.Dubbel); +} diff --git a/test/AssociationRegistry.Test.Projections/Publiek/Detail/Dubbels/Given_VerenigingWerdToegevoegdAlsDubbel.cs b/test/AssociationRegistry.Test.Projections/Publiek/Detail/Dubbels/Given_VerenigingWerdToegevoegdAlsDubbel.cs new file mode 100644 index 000000000..33912bf77 --- /dev/null +++ b/test/AssociationRegistry.Test.Projections/Publiek/Detail/Dubbels/Given_VerenigingWerdToegevoegdAlsDubbel.cs @@ -0,0 +1,20 @@ +namespace AssociationRegistry.Test.Projections.Publiek.Detail.Dubbels; + +using Public.Schema.Constants; + +[Collection(nameof(ProjectionContext))] +public class Given_VerenigingWerdToegevoegdAlsDubbel(PubliekDetailScenarioFixture fixture) + : PubliekDetailScenarioClassFixture +{ + [Fact] + public void Document_IsDubbelVan_Is_Updated() + => fixture.Result.IsDubbelVan.Should().BeEmpty(); + + [Fact] + public void Document_Status_Is_Actief() + => fixture.Result.Status.Should().Be(VerenigingStatus.Actief); + + [Fact] + public void Document_Has_DubbeleVereniging_In_CorresponderendeVCodes() + => fixture.Result.CorresponderendeVCodes.Should().Contain(fixture.Scenario.DubbeleVerenigingWerdGeregistreerd.VCode); +} diff --git a/test/AssociationRegistry.Test.Projections/Scenario/VerenigingWerdGemarkeerdAlsDubbelVanScenario.cs b/test/AssociationRegistry.Test.Projections/Scenario/VerenigingWerdGemarkeerdAlsDubbelVanScenario.cs new file mode 100644 index 000000000..c2d00ae38 --- /dev/null +++ b/test/AssociationRegistry.Test.Projections/Scenario/VerenigingWerdGemarkeerdAlsDubbelVanScenario.cs @@ -0,0 +1,37 @@ +namespace AssociationRegistry.Test.Projections.Scenario; + +using AutoFixture; +using Events; + +public class VerenigingWerdGemarkeerdAlsDubbelVanScenario : ScenarioBase +{ + public FeitelijkeVerenigingWerdGeregistreerd DubbeleVerenigingWerdGeregistreerd { get; } + public FeitelijkeVerenigingWerdGeregistreerd AuthentiekeVerenigingWerdGeregistreerd { get; } + public VerenigingWerdGermarkeerdAlsDubbelVan VerenigingWerdGermarkeerdAlsDubbelVan { get; set; } + public VerenigingAanvaardeDubbeleVereniging VerenigingAanvaardeDubbeleVereniging { get; set; } + + public VerenigingWerdGemarkeerdAlsDubbelVanScenario() + { + DubbeleVerenigingWerdGeregistreerd = AutoFixture.Create(); + AuthentiekeVerenigingWerdGeregistreerd = AutoFixture.Create(); + + VerenigingWerdGermarkeerdAlsDubbelVan = AutoFixture.Create() with + { + VCode = DubbeleVerenigingWerdGeregistreerd.VCode, + }; + + VerenigingAanvaardeDubbeleVereniging = AutoFixture.Create() with + { + VCode = AuthentiekeVerenigingWerdGeregistreerd.VCode, + VCodeDubbeleVereniging = DubbeleVerenigingWerdGeregistreerd.VCode, + }; + } + + public override string VCode => DubbeleVerenigingWerdGeregistreerd.VCode; + + public override EventsPerVCode[] Events => + [ + new(VCode, DubbeleVerenigingWerdGeregistreerd, VerenigingWerdGermarkeerdAlsDubbelVan), + new(AuthentiekeVerenigingWerdGeregistreerd.VCode, AuthentiekeVerenigingWerdGeregistreerd, VerenigingAanvaardeDubbeleVereniging), + ]; +} diff --git a/test/AssociationRegistry.Test.Projections/Scenario/VerenigingWerdToegevoegdAlsDubbelScenario.cs b/test/AssociationRegistry.Test.Projections/Scenario/VerenigingWerdToegevoegdAlsDubbelScenario.cs new file mode 100644 index 000000000..d0f29a8bb --- /dev/null +++ b/test/AssociationRegistry.Test.Projections/Scenario/VerenigingWerdToegevoegdAlsDubbelScenario.cs @@ -0,0 +1,40 @@ +namespace AssociationRegistry.Test.Projections.Scenario; + +using AutoFixture; +using Events; + +/// +/// This is exactly the same as VerenigingWerdGemarkeerdAlsDubbelVanScenario, but from the POV of the AuthentiekeVereniging +/// +public class VerenigingWerdToegevoegdAlsDubbelScenario : ScenarioBase +{ + public FeitelijkeVerenigingWerdGeregistreerd DubbeleVerenigingWerdGeregistreerd { get; } + public FeitelijkeVerenigingWerdGeregistreerd AuthentiekeVerenigingWerdGeregistreerd { get; } + public VerenigingWerdGermarkeerdAlsDubbelVan VerenigingWerdGermarkeerdAlsDubbelVan { get; set; } + public VerenigingAanvaardeDubbeleVereniging VerenigingAanvaardeDubbeleVereniging { get; set; } + + public VerenigingWerdToegevoegdAlsDubbelScenario() + { + DubbeleVerenigingWerdGeregistreerd = AutoFixture.Create(); + AuthentiekeVerenigingWerdGeregistreerd = AutoFixture.Create(); + + VerenigingWerdGermarkeerdAlsDubbelVan = AutoFixture.Create() with + { + VCode = DubbeleVerenigingWerdGeregistreerd.VCode, + }; + + VerenigingAanvaardeDubbeleVereniging = AutoFixture.Create() with + { + VCode = AuthentiekeVerenigingWerdGeregistreerd.VCode, + VCodeDubbeleVereniging = DubbeleVerenigingWerdGeregistreerd.VCode, + }; + } + + public override string VCode => AuthentiekeVerenigingWerdGeregistreerd.VCode; + + public override EventsPerVCode[] Events => + [ + new(DubbeleVerenigingWerdGeregistreerd.VCode, DubbeleVerenigingWerdGeregistreerd, VerenigingWerdGermarkeerdAlsDubbelVan), + new(AuthentiekeVerenigingWerdGeregistreerd.VCode, AuthentiekeVerenigingWerdGeregistreerd, VerenigingAanvaardeDubbeleVereniging), + ]; +} diff --git a/test/AssociationRegistry.Test.Public.Api/templates/DetailVerenigingResponse.json b/test/AssociationRegistry.Test.Public.Api/templates/DetailVerenigingResponse.json index d5b2d1196..555d14029 100644 --- a/test/AssociationRegistry.Test.Public.Api/templates/DetailVerenigingResponse.json +++ b/test/AssociationRegistry.Test.Public.Api/templates/DetailVerenigingResponse.json @@ -137,7 +137,9 @@ }, {{end}} ], -"lidmaatschappen": [] +"lidmaatschappen": [], +"isDubbelVan": "", +"corresponderendeVCodes": [] }, "metadata": { "datumLaatsteAanpassing": "{{datumlaatsteaanpassing}}" diff --git a/test/AssociationRegistry.Test/When_AanvaardDubbeleVereniging/Given_VCode_And_VCodeDubbeleVereniging_Are_The_Same.cs b/test/AssociationRegistry.Test/When_AanvaardDubbeleVereniging/Given_VCode_And_VCodeDubbeleVereniging_Are_The_Same.cs new file mode 100644 index 000000000..7e5dae7b5 --- /dev/null +++ b/test/AssociationRegistry.Test/When_AanvaardDubbeleVereniging/Given_VCode_And_VCodeDubbeleVereniging_Are_The_Same.cs @@ -0,0 +1,34 @@ +namespace AssociationRegistry.Test.When_AanvaardDubbeleVereniging; + +using AssociationRegistry.Acties.AanvaardDubbel; +using AssociationRegistry.Test.Common.AutoFixture; +using AssociationRegistry.Test.Common.Framework; +using AssociationRegistry.Test.Common.Scenarios.CommandHandling; +using AssociationRegistry.Vereniging; +using AssociationRegistry.Vereniging.Exceptions; +using AutoFixture; +using FluentAssertions; +using Resources; +using Xunit; + +public class Given_VCode_And_VCodeDubbeleVereniging_Are_The_Same +{ + [Fact] + public async Task Then_Throws_InvalidOperationVerenigingKanGeenDubbelWordenVanZichzelf() + { + var fixture = new Fixture().CustomizeDomain(); + var scenario = new FeitelijkeVerenigingWerdGeregistreerdScenario(); + var repositoryMock = new VerenigingRepositoryMock(scenario.GetVerenigingState()); + var vCode = fixture.Create(); + var command = fixture.Create() with + { + VCode = scenario.VCode, + VCodeDubbeleVereniging = scenario.VCode, + }; + var sut = new AanvaardDubbeleVerenigingCommandHandler(repositoryMock); + + var exception = await Assert.ThrowsAsync( + async () => await sut.Handle(command, CancellationToken.None)); + exception.Message.Should().Be(ExceptionMessages.VerenigingKanGeenDubbelWordenVanZichzelf); + } +} diff --git a/test/AssociationRegistry.Test/When_AanvaardDubbeleVereniging/Given_Valid_AanvaardDubbeleVerenigingCommand.cs b/test/AssociationRegistry.Test/When_AanvaardDubbeleVereniging/Given_Valid_AanvaardDubbeleVerenigingCommand.cs new file mode 100644 index 000000000..1d85317dc --- /dev/null +++ b/test/AssociationRegistry.Test/When_AanvaardDubbeleVereniging/Given_Valid_AanvaardDubbeleVerenigingCommand.cs @@ -0,0 +1,30 @@ +namespace AssociationRegistry.Test.When_AanvaardDubbeleVereniging; + +using AssociationRegistry.Acties.AanvaardDubbel; +using AssociationRegistry.Events; +using AssociationRegistry.Test.Common.AutoFixture; +using AssociationRegistry.Test.Common.Framework; +using AssociationRegistry.Test.Common.Scenarios.CommandHandling; +using AutoFixture; +using Xunit; + +public class Given_Valid_AanvaardDubbeleVerenigingCommand +{ + [Fact] + public async Task Then_Throws_InvalidOperationVerenigingKanGeenDubbelWordenVanZichzelf() + { + var fixture = new Fixture().CustomizeDomain(); + var scenario = new FeitelijkeVerenigingWerdGeregistreerdScenario(); + var repositoryMock = new VerenigingRepositoryMock(scenario.GetVerenigingState()); + var command = fixture.Create() + with + { + VCode = scenario.VCode, + }; + var sut = new AanvaardDubbeleVerenigingCommandHandler(repositoryMock); + + await sut.Handle(command, CancellationToken.None); + + repositoryMock.ShouldHaveSaved(new VerenigingAanvaardeDubbeleVereniging(scenario.VCode, command.VCodeDubbeleVereniging)); + } +} diff --git a/test/AssociationRegistry.Test/When_Markeer_Als_Dubbel_Van/Given_IsDubbelVan_Vereniging_Is_Already_A_Dubbel.cs b/test/AssociationRegistry.Test/When_Markeer_Als_Dubbel_Van/Given_IsDubbelVan_Vereniging_Is_Already_A_Dubbel.cs new file mode 100644 index 000000000..5aad95275 --- /dev/null +++ b/test/AssociationRegistry.Test/When_Markeer_Als_Dubbel_Van/Given_IsDubbelVan_Vereniging_Is_Already_A_Dubbel.cs @@ -0,0 +1,39 @@ +namespace AssociationRegistry.Test.When_Markeer_Als_Dubbel_Van; + +using Acties.MarkeerAlsDubbelVan; +using AssociationRegistry.Framework; +using AutoFixture; +using Common.AutoFixture; +using FluentAssertions; +using Marten; +using Moq; +using Resources; +using Vereniging; +using Vereniging.Exceptions; +using Wolverine.Marten; +using Xunit; + +public class Given_IsDubbelVan_Vereniging_Is_Already_A_Dubbel +{ + [Fact] + public async Task Then_Throws_VerenigingKanGeenDubbelWordenVanDubbelVereniging() + { + var fixture = new Fixture().CustomizeDomain(); + var verenigingsRepositoryMock = new Mock(); + var command = fixture.Create(); + var commandEnvelope = new CommandEnvelope(command, fixture.Create()); + + verenigingsRepositoryMock.Setup(s => s.IsDubbel(command.VCodeAuthentiekeVereniging)) + .ReturnsAsync(true); + + var sut = new MarkeerAlsDubbelVanCommandHandler(verenigingsRepositoryMock.Object, + Mock.Of(), + Mock.Of() + ); + + var exception = await Assert.ThrowsAsync + (async () => await sut.Handle(commandEnvelope, CancellationToken.None)); + + exception.Message.Should().Be(ExceptionMessages.VerenigingKanGeenDubbelWordenVanEenVerenigingReedsGemarkeerdAlsDubbel); + } +} diff --git a/test/AssociationRegistry.Test/When_Markeer_Als_Dubbel_Van/Given_IsDubbelVan_Vereniging_Is_Verwijderd.cs b/test/AssociationRegistry.Test/When_Markeer_Als_Dubbel_Van/Given_IsDubbelVan_Vereniging_Is_Verwijderd.cs new file mode 100644 index 000000000..c949e5a30 --- /dev/null +++ b/test/AssociationRegistry.Test/When_Markeer_Als_Dubbel_Van/Given_IsDubbelVan_Vereniging_Is_Verwijderd.cs @@ -0,0 +1,39 @@ +namespace AssociationRegistry.Test.When_Markeer_Als_Dubbel_Van; + +using Acties.MarkeerAlsDubbelVan; +using AssociationRegistry.Framework; +using AutoFixture; +using Common.AutoFixture; +using FluentAssertions; +using Marten; +using Moq; +using Resources; +using Vereniging; +using Vereniging.Exceptions; +using Wolverine.Marten; +using Xunit; + +public class Given_IsDubbelVan_Vereniging_Is_Verwijderd +{ + [Fact] + public async Task Then_Throws_VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging() + { + var fixture = new Fixture().CustomizeDomain(); + var verenigingsRepositoryMock = new Mock(); + var command = fixture.Create(); + var commandEnvelope = new CommandEnvelope(command, fixture.Create()); + + verenigingsRepositoryMock.Setup(s => s.IsVerwijderd(command.VCodeAuthentiekeVereniging)) + .ReturnsAsync(true); + + var sut = new MarkeerAlsDubbelVanCommandHandler(verenigingsRepositoryMock.Object, + Mock.Of(), + Mock.Of() + ); + + var exception = await Assert.ThrowsAsync + (async () => await sut.Handle(commandEnvelope, CancellationToken.None)); + + exception.Message.Should().Be(ExceptionMessages.VerenigingKanGeenDubbelWordenVanVerwijderdeVereniging); + } +} diff --git a/test/AssociationRegistry.Test/WhenWijzigMaatschappelijkeZetel/Given_A_Second_Primair.cs b/test/AssociationRegistry.Test/When_WijzigMaatschappelijkeZetel/Given_A_Second_Primair.cs similarity index 100% rename from test/AssociationRegistry.Test/WhenWijzigMaatschappelijkeZetel/Given_A_Second_Primair.cs rename to test/AssociationRegistry.Test/When_WijzigMaatschappelijkeZetel/Given_A_Second_Primair.cs diff --git a/test/AssociationRegistry.Test/WhenWijzigMaatschappelijkeZetel/Given_All_Fields.cs b/test/AssociationRegistry.Test/When_WijzigMaatschappelijkeZetel/Given_All_Fields.cs similarity index 100% rename from test/AssociationRegistry.Test/WhenWijzigMaatschappelijkeZetel/Given_All_Fields.cs rename to test/AssociationRegistry.Test/When_WijzigMaatschappelijkeZetel/Given_All_Fields.cs diff --git a/test/AssociationRegistry.Test/WhenWijzigMaatschappelijkeZetel/Given_No_Changes.cs b/test/AssociationRegistry.Test/When_WijzigMaatschappelijkeZetel/Given_No_Changes.cs similarity index 100% rename from test/AssociationRegistry.Test/WhenWijzigMaatschappelijkeZetel/Given_No_Changes.cs rename to test/AssociationRegistry.Test/When_WijzigMaatschappelijkeZetel/Given_No_Changes.cs diff --git a/test/AssociationRegistry.Test/WhenWijzigMaatschappelijkeZetel/Given_Not_The_MaatschappelijkeZetelId.cs b/test/AssociationRegistry.Test/When_WijzigMaatschappelijkeZetel/Given_Not_The_MaatschappelijkeZetelId.cs similarity index 100% rename from test/AssociationRegistry.Test/WhenWijzigMaatschappelijkeZetel/Given_Not_The_MaatschappelijkeZetelId.cs rename to test/AssociationRegistry.Test/When_WijzigMaatschappelijkeZetel/Given_Not_The_MaatschappelijkeZetelId.cs diff --git a/test/AssociationRegistry.Test/WhenWijzigMaatschappelijkeZetel/Given_The_MaatschappelijkeZetelId.cs b/test/AssociationRegistry.Test/When_WijzigMaatschappelijkeZetel/Given_The_MaatschappelijkeZetelId.cs similarity index 100% rename from test/AssociationRegistry.Test/WhenWijzigMaatschappelijkeZetel/Given_The_MaatschappelijkeZetelId.cs rename to test/AssociationRegistry.Test/When_WijzigMaatschappelijkeZetel/Given_The_MaatschappelijkeZetelId.cs