From 3030b91e2ca30ff7c6929c652becf92e5d74daff Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 6 Mar 2025 10:06:45 +0100 Subject: [PATCH] working API with patching partner person directly into partner --- .../partner/HsOfficePartnerController.java | 2 +- .../partner/HsOfficePartnerEntityPatcher.java | 8 +- .../HsOfficeRelationEntityPatcher.java | 45 ++-- .../hs-office/hs-office-partner-schemas.yaml | 1 + .../hs-office/hs-office-relation-schemas.yaml | 5 + .../HsOfficePartnerControllerRestTest.java | 8 - .../HsOfficePartnerEntityPatcherUnitTest.java | 15 +- ...HsOfficeRelationEntityPatcherUnitTest.java | 227 ++++++++++++++++++ .../HsOfficeRelationPatcherUnitTest.java | 11 +- ...ceDeceasedPartnerWithCommunityOfHeirs.java | 155 ++++++------ .../rbac/test/PatchUnitTestBase.java | 8 +- 11 files changed, 356 insertions(+), 129 deletions(-) create mode 100644 src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationEntityPatcherUnitTest.java diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java index 7e7bf0b5..a0bcc25d 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java @@ -159,7 +159,7 @@ public class HsOfficePartnerController implements HsOfficePartnersApi { final var current = rbacPartnerRepo.findByUuid(partnerUuid).orElseThrow(); final var previousPartnerPerson = current.getPartnerRel().getHolder(); - new HsOfficePartnerEntityPatcher(em, current).apply(body); + new HsOfficePartnerEntityPatcher(mapper, em, current).apply(body); final var saved = rbacPartnerRepo.save(current); optionallyCreateExPartnerRelation(saved, previousPartnerPerson); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcher.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcher.java index 16d313ac..5d36b602 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcher.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcher.java @@ -3,15 +3,21 @@ package net.hostsharing.hsadminng.hs.office.partner; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntityPatcher; import net.hostsharing.hsadminng.mapper.EntityPatcher; +import net.hostsharing.hsadminng.mapper.StrictMapper; import jakarta.persistence.EntityManager; class HsOfficePartnerEntityPatcher implements EntityPatcher { + + private final StrictMapper mapper; private final EntityManager em; private final HsOfficePartnerRbacEntity entity; + HsOfficePartnerEntityPatcher( + final StrictMapper mapper, final EntityManager em, final HsOfficePartnerRbacEntity entity) { + this.mapper = mapper; this.em = em; this.entity = entity; } @@ -20,7 +26,7 @@ class HsOfficePartnerEntityPatcher implements EntityPatcher { + private final StrictMapper mapper; private final EntityManager em; private final HsOfficeRelation entity; - public HsOfficeRelationEntityPatcher(final EntityManager em, final HsOfficeRelation entity) { + public HsOfficeRelationEntityPatcher(final StrictMapper mapper, final EntityManager em, final HsOfficeRelation entity) { + this.mapper = mapper; this.em = em; this.entity = entity; } @Override public void apply(final HsOfficeRelationPatchResource resource) { - OptionalFromJson.of(resource.getAnchorUuid()).ifPresent(newValue -> { - verifyNotNull(newValue, "contact"); - entity.setAnchor(em.getReference(HsOfficePersonRealEntity.class, newValue)); - }); - OptionalFromJson.of(resource.getHolderUuid()).ifPresent(newValue -> { - verifyNotNull(newValue, "contact"); - entity.setHolder(em.getReference(HsOfficePersonRealEntity.class, newValue)); - }); - OptionalFromJson.of(resource.getContactUuid()).ifPresent(newValue -> { - verifyNotNull(newValue, "contact"); - entity.setContact(em.getReference(HsOfficeContactRealEntity.class, newValue)); - }); - } + if (resource.getHolder() != null && resource.getHolderUuid() != null) { + throw new ValidationException("either \"holder\" or \"holder.uuid\" can be given, not both"); + } else { + if (resource.getHolder() != null) { + final var newHolder = mapper.map(resource.getHolder(), HsOfficePersonRealEntity.class); + em.persist(newHolder); + entity.setHolder(newHolder); + } else if (resource.getHolderUuid() != null) { + entity.setHolder(em.getReference(HsOfficePersonRealEntity.class, resource.getHolderUuid().get())); + } + } - private void verifyNotNull(final UUID newValue, final String propertyName) { - if (newValue == null) { - throw new IllegalArgumentException("property '" + propertyName + "' must not be null"); + if (resource.getContact() != null && resource.getContactUuid() != null) { + throw new ValidationException("either \"contact\" or \"contact.uuid\" can be given, not both"); + } else { + if (resource.getContact() != null) { + final var newContact = mapper.map(resource.getContact(), HsOfficeContactRealEntity.class); + em.persist(newContact); + entity.setContact(newContact); + } else if (resource.getContactUuid() != null) { + entity.setContact(em.getReference(HsOfficeContactRealEntity.class, resource.getContactUuid().get())); + } } } } diff --git a/src/main/resources/api-definition/hs-office/hs-office-partner-schemas.yaml b/src/main/resources/api-definition/hs-office/hs-office-partner-schemas.yaml index dd0def9a..88b6fd06 100644 --- a/src/main/resources/api-definition/hs-office/hs-office-partner-schemas.yaml +++ b/src/main/resources/api-definition/hs-office/hs-office-partner-schemas.yaml @@ -52,6 +52,7 @@ components: $ref: 'hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelationPatch' details: $ref: '#/components/schemas/HsOfficePartnerDetailsPatch' + additionalProperties: false HsOfficePartnerDetailsPatch: type: object diff --git a/src/main/resources/api-definition/hs-office/hs-office-relation-schemas.yaml b/src/main/resources/api-definition/hs-office/hs-office-relation-schemas.yaml index d74b5da0..96865955 100644 --- a/src/main/resources/api-definition/hs-office/hs-office-relation-schemas.yaml +++ b/src/main/resources/api-definition/hs-office/hs-office-relation-schemas.yaml @@ -53,10 +53,15 @@ components: type: string format: uuid nullable: true + holder: + $ref: 'hs-office-person-schemas.yaml#/components/schemas/HsOfficePersonInsert' contact.uuid: type: string format: uuid nullable: true + contact: + $ref: 'hs-office-contact-schemas.yaml#/components/schemas/HsOfficeContactInsert' + additionalProperties: false # arbitrary relation with explicit type HsOfficeRelationInsert: diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerRestTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerRestTest.java index 1ed5389b..9a688367 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerRestTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerRestTest.java @@ -108,8 +108,6 @@ class HsOfficePartnerControllerRestTest { "holder.uuid": "%s", "contact.uuid": "%s" }, - "person.uuid": "%s", - "contact.uuid": "%s", "details": { "registrationOffice": "Temp Registergericht Aurich", "registrationNumber": "111111" @@ -118,8 +116,6 @@ class HsOfficePartnerControllerRestTest { """.formatted( GIVEN_MANDANTE_UUID, GIVEN_INVALID_UUID, - GIVEN_CONTACT_UUID, - GIVEN_INVALID_UUID, GIVEN_CONTACT_UUID)) .accept(MediaType.APPLICATION_JSON)) @@ -145,8 +141,6 @@ class HsOfficePartnerControllerRestTest { "holder.uuid": "%s", "contact.uuid": "%s" }, - "person.uuid": "%s", - "contact.uuid": "%s", "details": { "registrationOffice": "Temp Registergericht Aurich", "registrationNumber": "111111" @@ -155,8 +149,6 @@ class HsOfficePartnerControllerRestTest { """.formatted( GIVEN_MANDANTE_UUID, GIVEN_PERSON_UUID, - GIVEN_INVALID_UUID, - GIVEN_PERSON_UUID, GIVEN_INVALID_UUID)) .accept(MediaType.APPLICATION_JSON)) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcherUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcherUnitTest.java index 48758e12..e7f09b03 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcherUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcherUnitTest.java @@ -6,6 +6,8 @@ import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartne import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeRelationPatchResource; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity; +import net.hostsharing.hsadminng.mapper.StrictMapper; +import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; @@ -14,7 +16,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.openapitools.jackson.nullable.JsonNullable; -import jakarta.persistence.EntityManager; import java.time.LocalDate; import java.util.UUID; @@ -26,7 +27,7 @@ import static org.mockito.Mockito.lenient; @TestInstance(PER_CLASS) @ExtendWith(MockitoExtension.class) -// This test class does not rerive from PatchUnitTestBase because it has no directly patchable properties. +// This test class does not subclass PatchUnitTestBase because it has no directly patchable properties. // But the factory-structure is kept, so PatchUnitTestBase could easily be plugged back in if needed. class HsOfficePartnerEntityPatcherUnitTest { @@ -47,13 +48,15 @@ class HsOfficePartnerEntityPatcherUnitTest { .build(); @Mock - private EntityManager em; + private EntityManagerWrapper emw; + + private StrictMapper mapper = new StrictMapper(emw); @BeforeEach void initMocks() { - lenient().when(em.getReference(eq(HsOfficePersonRealEntity.class), any())).thenAnswer(invocation -> + lenient().when(emw.getReference(eq(HsOfficePersonRealEntity.class), any())).thenAnswer(invocation -> HsOfficePersonRealEntity.builder().uuid(invocation.getArgument(1)).build()); - lenient().when(em.getReference(eq(HsOfficeContactRealEntity.class), any())).thenAnswer(invocation -> + lenient().when(emw.getReference(eq(HsOfficeContactRealEntity.class), any())).thenAnswer(invocation -> HsOfficeContactRealEntity.builder().uuid(invocation.getArgument(1)).build()); } @@ -123,6 +126,6 @@ class HsOfficePartnerEntityPatcherUnitTest { } protected HsOfficePartnerEntityPatcher createPatcher(final HsOfficePartnerRbacEntity partner) { - return new HsOfficePartnerEntityPatcher(em, partner); + return new HsOfficePartnerEntityPatcher(mapper, emw, partner); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationEntityPatcherUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationEntityPatcherUnitTest.java new file mode 100644 index 00000000..f4acb10b --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationEntityPatcherUnitTest.java @@ -0,0 +1,227 @@ +package net.hostsharing.hsadminng.hs.office.relation; + +import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; +import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeContactInsertResource; +import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePersonInsertResource; +import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePersonTypeResource; +import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeRelationPatchResource; +import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity; +import net.hostsharing.hsadminng.mapper.StrictMapper; +import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; +import net.hostsharing.hsadminng.rbac.test.PatchUnitTestBase; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.openapitools.jackson.nullable.JsonNullable; + +import jakarta.validation.ValidationException; +import java.util.UUID; +import java.util.stream.Stream; + +import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.LEGAL_PERSON; +import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.NATURAL_PERSON; +import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.PARTNER; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.assertj.core.api.Assumptions.assumeThat; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@TestInstance(PER_CLASS) +@ExtendWith(MockitoExtension.class) +class HsOfficeRelationEntityPatcherUnitTest extends PatchUnitTestBase< + HsOfficeRelationPatchResource, + HsOfficeRelation + > { + + private static final UUID INITIAL_RELATION_UUID = UUID.randomUUID(); + private static final UUID INITIAL_ANCHOR_UUID = UUID.randomUUID(); + private static final UUID INITIAL_HOLDER_UUID = UUID.randomUUID(); + private static final UUID INITIAL_CONTACT_UUID = UUID.randomUUID(); + + private static final UUID PATCHED_HOLDER_UUID = UUID.randomUUID(); + private static HsOfficePersonInsertResource HOLDER_PATCH_RESOURCE = new HsOfficePersonInsertResource() { + + { + setPersonType(HsOfficePersonTypeResource.NATURAL_PERSON); + setFamilyName("Patched-Holder-Family-Name"); + setGivenName("Patched-Holder-Given-Name"); + } + }; + private static HsOfficePersonRealEntity PATCHED_HOLDER = HsOfficePersonRealEntity.builder() + .uuid(PATCHED_HOLDER_UUID) + .personType(NATURAL_PERSON) + .familyName("Patched-Holder-Family-Name") + .givenName("Patched-Holder-Given-Name") + .build(); + + private static final UUID PATCHED_CONTACT_UUID = UUID.randomUUID(); + private static HsOfficeContactInsertResource CONTACT_PATCH_RESOURCE = new HsOfficeContactInsertResource() { + + { + setCaption("Patched-Contact-Caption"); + } + }; + private static HsOfficeContactRealEntity PATCHED_CONTACT = HsOfficeContactRealEntity.builder() + .uuid(PATCHED_CONTACT_UUID) + .caption("Patched-Contact-Caption") + .build(); + + @Mock + private EntityManagerWrapper emw; + + private StrictMapper mapper = new StrictMapper(emw); + + @BeforeEach + void initMocks() { + lenient().when(emw.getReference(HsOfficePersonRealEntity.class, PATCHED_HOLDER_UUID)).thenAnswer( + p -> PATCHED_HOLDER); + lenient().when(emw.getReference(HsOfficeContactRealEntity.class, PATCHED_CONTACT_UUID)).thenAnswer( + p -> PATCHED_CONTACT); + } + + @Override + protected HsOfficeRelation newInitialEntity() { + final var entity = new HsOfficeRelationRealEntity(); + entity.setUuid(INITIAL_RELATION_UUID); + entity.setType(PARTNER); + entity.setAnchor(HsOfficePersonRealEntity.builder() + .uuid(INITIAL_ANCHOR_UUID) + .personType(LEGAL_PERSON) + .tradeName("Initial-Anchor-Tradename") + .build()); + entity.setHolder(HsOfficePersonRealEntity.builder() + .uuid(INITIAL_HOLDER_UUID) + .personType(NATURAL_PERSON) + .familyName("Initial-Holder-Family-Name") + .givenName("Initial-Holder-Given-Name") + .build()); + entity.setContact(HsOfficeContactRealEntity.builder() + .uuid(INITIAL_CONTACT_UUID) + .caption("Initial-Contact-Caption") + .build()); + return entity; + } + + @Override + protected HsOfficeRelationPatchResource newPatchResource() { + return new HsOfficeRelationPatchResource(); + } + + @Override + protected HsOfficeRelationEntityPatcher createPatcher(final HsOfficeRelation relation) { + return new HsOfficeRelationEntityPatcher(mapper, emw, relation); + } + + @Override + protected Stream propertyTestDescriptors() { + return Stream.of( + new JsonNullableProperty<>( + "holderUuid", + HsOfficeRelationPatchResource::setHolderUuid, + PATCHED_HOLDER_UUID, + HsOfficeRelation::setHolder, + PATCHED_HOLDER), + new SimpleProperty<>( + "holder", + HsOfficeRelationPatchResource::setHolder, + HOLDER_PATCH_RESOURCE, + HsOfficeRelation::setHolder, + withoutUuid(PATCHED_HOLDER)) + .notNullable(), + + new JsonNullableProperty<>( + "contactUuid", + HsOfficeRelationPatchResource::setContactUuid, + PATCHED_CONTACT_UUID, + HsOfficeRelation::setContact, + PATCHED_CONTACT), + new SimpleProperty<>( + "contact", + HsOfficeRelationPatchResource::setContact, + CONTACT_PATCH_RESOURCE, + HsOfficeRelation::setContact, + withoutUuid(PATCHED_CONTACT)) + .notNullable() + ); + } + + @Override + protected void willPatchAllProperties() { + // this generic test does not work because either holder or holder.uuid can be set + assumeThat(true).isFalse(); + } + + @Test + void willThrowExceptionIfHolderAndHolderUuidAreGiven() { + // given + final var givenEntity = newInitialEntity(); + final var patchResource = newPatchResource(); + patchResource.setHolderUuid(JsonNullable.of(PATCHED_HOLDER_UUID)); + patchResource.setHolder(HOLDER_PATCH_RESOURCE); + + // when + final var exception = catchThrowable(() -> createPatcher(givenEntity).apply(patchResource)); + + // then + assertThat(exception).isInstanceOf(ValidationException.class) + .hasMessage("either \"holder\" or \"holder.uuid\" can be given, not both"); + } + + @Test + void willThrowExceptionIfContactAndContactUuidAreGiven() { + // given + final var givenEntity = newInitialEntity(); + final var patchResource = newPatchResource(); + patchResource.setContactUuid(JsonNullable.of(PATCHED_CONTACT_UUID)); + patchResource.setContact(CONTACT_PATCH_RESOURCE); + + // when + final var exception = catchThrowable(() -> createPatcher(givenEntity).apply(patchResource)); + + // then + assertThat(exception).isInstanceOf(ValidationException.class) + .hasMessage("either \"contact\" or \"contact.uuid\" can be given, not both"); + } + + @Test + void willPersistNewHolder() { + // given + final var givenEntity = newInitialEntity(); + final var patchResource = newPatchResource(); + patchResource.setHolder(HOLDER_PATCH_RESOURCE); + + // when + createPatcher(givenEntity).apply(patchResource); + + // then + verify(emw, times(1)).persist(givenEntity.getHolder()); + } + + @Test + void willPersistNewContact() { + // given + final var givenEntity = newInitialEntity(); + final var patchResource = newPatchResource(); + patchResource.setContact(CONTACT_PATCH_RESOURCE); + + // when + createPatcher(givenEntity).apply(patchResource); + + // then + verify(emw, times(1)).persist(givenEntity.getContact()); + } + + private HsOfficePersonRealEntity withoutUuid(final HsOfficePersonRealEntity givenWithUuid) { + return givenWithUuid.toBuilder().uuid(null).build(); + } + + private HsOfficeContactRealEntity withoutUuid(final HsOfficeContactRealEntity givenWithUuid) { + return givenWithUuid.toBuilder().uuid(null).build(); + } +} diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationPatcherUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationPatcherUnitTest.java index 343fcd90..72871086 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationPatcherUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationPatcherUnitTest.java @@ -3,6 +3,8 @@ package net.hostsharing.hsadminng.hs.office.relation; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeRelationPatchResource; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity; +import net.hostsharing.hsadminng.mapper.StrictMapper; +import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; import net.hostsharing.hsadminng.rbac.test.PatchUnitTestBase; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestInstance; @@ -10,7 +12,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import jakarta.persistence.EntityManager; import java.util.UUID; import java.util.stream.Stream; @@ -30,11 +31,13 @@ class HsOfficeRelationPatcherUnitTest extends PatchUnitTestBase< static final UUID PATCHED_CONTACT_UUID = UUID.randomUUID(); @Mock - EntityManager em; + EntityManagerWrapper emw; + + StrictMapper mapper = new StrictMapper(emw); @BeforeEach void initMocks() { - lenient().when(em.getReference(eq(HsOfficeContactRealEntity.class), any())).thenAnswer(invocation -> + lenient().when(emw.getReference(eq(HsOfficeContactRealEntity.class), any())).thenAnswer(invocation -> HsOfficeContactRealEntity.builder().uuid(invocation.getArgument(1)).build()); } @@ -66,7 +69,7 @@ class HsOfficeRelationPatcherUnitTest extends PatchUnitTestBase< @Override protected HsOfficeRelationEntityPatcher createPatcher(final HsOfficeRelation relation) { - return new HsOfficeRelationEntityPatcher(em, relation); + return new HsOfficeRelationEntityPatcher(mapper, emw, relation); } @Override diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/partner/ReplaceDeceasedPartnerWithCommunityOfHeirs.java b/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/partner/ReplaceDeceasedPartnerWithCommunityOfHeirs.java index c706e8e6..c114809b 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/partner/ReplaceDeceasedPartnerWithCommunityOfHeirs.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/scenarios/partner/ReplaceDeceasedPartnerWithCommunityOfHeirs.java @@ -12,101 +12,81 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase - httpGet("/api/hs/office/persons?name=Hostsharing+eG") - .expecting(OK).expecting(JSON), - response -> response.expectArrayElements(1).getFromBody("[0].uuid"), - "Even in production data we expect this query to return just a single result." // TODO.impl: add constraint? - ); - - obtain("Partner: %{partnerNumber}", () -> - httpGet("/api/hs/office/partners/%{partnerNumber}") - .reportWithResponse().expecting(OK).expecting(JSON), + obtain("Partner: %{partnerNumber}", + () -> httpGet("/api/hs/office/partners/%{partnerNumber}") + .reportWithResponse().expecting(OK).expecting(JSON), response -> response.getFromBody("uuid"), - "Even in production data we expect this query to return just a single result." // TODO.impl: add constraint? + "Even in production data we expect this query to return just a single result." + // TODO.impl: add constraint? ) .extractValue("partnerRel.holder.familyName", "familyNameOfDeceasedPerson") .extractValue("partnerRel.holder.givenName", "givenNameOfDeceasedPerson") - .extractUuidAlias("partnerRel.holder.uuid", "Person: %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}"); + .extractUuidAlias( + "partnerRel.holder.uuid", + "Person: %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}"); - obtain("Partner-Relation: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", () -> - httpPost("/api/hs/office/relations", usingJsonBody(""" - { - "type": "PARTNER", - "anchor.uuid": ${Person: Hostsharing eG}, - "holder": { - "personType": "UNINCORPORATED_FIRM", - "tradeName": "Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", - }, - "contact": { - "caption": "Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", - "postalAddress": { - "name": "Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", - "co": "%{representativeGivenName} %{representativeFamilyName}", - %{communityOfHeirsPostalAddress} - }, - "phoneNumbers": { - "office": ${communityOfHeirsOfficePhoneNumber} - }, - "emailAddresses": { - "main": ${communityOfHeirsEmailAddress} - } - } - } - """)) - .reportWithResponse().expecting(CREATED).expecting(JSON) - ) - .extractUuidAlias("contact.uuid", "Contact: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}") - .extractUuidAlias("holder.uuid", "Person: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}"); - - obtain("Representative-Relation: %{representativeGivenName} %{representativeFamilyName} for Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", () -> - httpPost("/api/hs/office/relations", usingJsonBody(""" - { - "type": "REPRESENTATIVE", - "anchor.uuid": ${Person: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}}, - "holder": { - "personType": "NATURAL_PERSON", - "givenName": ${representativeGivenName}, - "familyName": ${representativeFamilyName} - }, - "contact.uuid": ${Contact: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}} - } - """)) - .reportWithResponse().expecting(CREATED).expecting(JSON) - ).extractUuidAlias("holder.uuid", "Person: %{representativeGivenName} %{representativeFamilyName}"); - - obtain("Partner: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", () -> - httpPatch("/api/hs/office/partners/%{Partner: %{partnerNumber}}", usingJsonBody(""" - { - "partnerRel.uuid": ${Partner-Relation: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}} - } - """)) - .expecting(HttpStatus.OK) + withTitle("New Partner-Person+Contact: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", + () -> httpPatch("/api/hs/office/partners/%{Partner: %{partnerNumber}}", + usingJsonBody(""" + { + "wrong1": false, + "partnerRel": { + "wrong2": false, + "holder": { + "personType": "UNINCORPORATED_FIRM", + "tradeName": "Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", + }, + "contact": { + "wrong3": false, + "caption": "Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", + "postalAddress": { + "wrong4": false, + "name": "Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", + "co": "%{representativeGivenName} %{representativeFamilyName}", + %{communityOfHeirsPostalAddress} + }, + "phoneNumbers": { + "office": ${communityOfHeirsOfficePhoneNumber} + }, + "emailAddresses": { + "main": ${communityOfHeirsEmailAddress} + } + } + } + } + """)) + .reportWithResponse().expecting(HttpStatus.OK).expecting(JSON) + .extractUuidAlias( + "partnerRel.holder.uuid", + "Person: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}") + .extractUuidAlias( + "partnerRel.contact.uuid", + "Contact: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}") ); - // TODO.test: missing steps Debitor, Membership, Coop-Shares+Assets - - // Debitors - - // die Erbengemeinschaft wird als Anchor-Person (Partner) in die Debitor-Relations eingetragen - // der neue Rechnungsempfänger (z.B. auch ggf. Rechtsanwalt) wird als Holder-Person (Debitor-Person) in die Debitor-Relations eingetragen -- oder neu? - - // Membership - - // intro: die Mitgliedschaft geht juristisch gesehen auf die Erbengemeinschaft über - - // die bisherige Mitgliedschaft als DECEASED mit Ende-Datum=Todesdatum markieren - - // eine neue Mitgliedschaft (-00) mit dem Start-Datum=Todesdatum+1 anlegen - - // die Geschäftsanteile per share-tx: TRANSFER→ADOPT an die Erbengemeinschaft übertragen - // die Geschäftsguthaben per asset-tx: TRANSFER→ADOPT an die Erbengemeinschaft übertragen + obtain( + "Representative-Relation: %{representativeGivenName} %{representativeFamilyName} for Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}", + () -> httpPost("/api/hs/office/relations", + usingJsonBody(""" + { + "type": "REPRESENTATIVE", + "anchor.uuid": ${Person: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}}, + "holder": { + "personType": "NATURAL_PERSON", + "givenName": ${representativeGivenName}, + "familyName": ${representativeFamilyName} + }, + "contact.uuid": ${Contact: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}} + } + """)) + .reportWithResponse().expecting(CREATED).expecting(JSON) + ) + .extractUuidAlias("holder.uuid", "Person: %{representativeGivenName} %{representativeFamilyName}"); // outro: die Erbengemeinschaft hat eine Frist von 6 Monaten, um die Mitgliedschaft einer Person zu übertragen // →nächster "Drecksfall" @@ -120,7 +100,8 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase httpGet("/api/hs/office/partners/%{partnerNumber}") .expecting(OK).expecting(JSON).expectObject(), - path("partnerRel.holder.tradeName").contains("Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}") + path("partnerRel.holder.tradeName").contains( + "Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}") ); // TODO.test: Verify the EX_PARTNER-Relation, once we fixed the anchor problem, see HsOfficePartnerController @@ -128,9 +109,11 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase httpGet("/api/hs/office/relations?relationType=REPRESENTATIVE&personUuid=%{Person: %{representativeGivenName} %{representativeFamilyName}}") + () -> httpGet( + "/api/hs/office/relations?relationType=REPRESENTATIVE&personUuid=%{Person: %{representativeGivenName} %{representativeFamilyName}}") .expecting(OK).expecting(JSON).expectArrayElements(1), - path("[0].anchor.tradeName").contains("Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}"), + path("[0].anchor.tradeName").contains( + "Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}"), path("[0].holder.familyName").contains("%{representativeFamilyName}") ); diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/test/PatchUnitTestBase.java b/src/test/java/net/hostsharing/hsadminng/rbac/test/PatchUnitTestBase.java index f2b7e8bb..82d133e4 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/test/PatchUnitTestBase.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/test/PatchUnitTestBase.java @@ -19,7 +19,7 @@ import static org.assertj.core.api.Assumptions.assumeThat; public abstract class PatchUnitTestBase { @Test - void willPatchNoProperty() { + protected void willPatchNoProperty() { // given final var givenEntity = newInitialEntity(); final var patchResource = newPatchResource(); @@ -73,7 +73,7 @@ public abstract class PatchUnitTestBase { @ParameterizedTest @MethodSource("propertyTestCases") - void willThrowExceptionIfNotNullableValueIsNull(final Property testCase) { + protected void willThrowExceptionIfNotNullableValueIsNull(final Property testCase) { assumeThat(testCase instanceof JsonNullableProperty).isTrue(); assumeThat(testCase.nullable).isFalse(); @@ -94,7 +94,7 @@ public abstract class PatchUnitTestBase { @ParameterizedTest @MethodSource("propertyTestCases") - void willPatchOnlyGivenPropertyToNull(final Property testCase) { + protected void willPatchOnlyGivenPropertyToNull(final Property testCase) { assumeThat(testCase.nullable).isTrue(); // given @@ -113,7 +113,7 @@ public abstract class PatchUnitTestBase { @ParameterizedTest @MethodSource("propertyTestCases") - void willNotPatchIfGivenPropertyNotGiven(final Property testCase) { + protected void willNotPatchIfGivenPropertyNotGiven(final Property testCase) { // given final var givenEntity = newInitialEntity();