update dependend relations when updating partner person (#162)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/162 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
@@ -20,6 +20,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
@@ -420,7 +421,7 @@ public class ArchitectureTest {
|
||||
if (isGeneratedSpringRepositoryMethod(item, method)) {
|
||||
continue;
|
||||
}
|
||||
if (item.isAnnotatedWith(RestController.class) && !method.getModifiers().contains(PUBLIC)) {
|
||||
if (!method.getModifiers().contains(PUBLIC) || method.isAnnotatedWith(PostConstruct.class)) {
|
||||
continue;
|
||||
}
|
||||
final var message = String.format(
|
||||
|
||||
@@ -316,7 +316,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
||||
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenPartner = givenSomeTemporaryPartnerBessler(20011);
|
||||
final var givenPartnerRel = givenSomeTemporaryPartnerRel("Winkler", "third contact");
|
||||
final var newPartnerPerson = personRealRepo.findPersonByOptionalNameLike("Winkler").getFirst();
|
||||
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
@@ -325,7 +325,9 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
||||
.body("""
|
||||
{
|
||||
"partnerNumber": "P-20011",
|
||||
"partnerRel.uuid": "%s",
|
||||
"partnerRel": {
|
||||
"holder.uuid": "%s"
|
||||
},
|
||||
"details": {
|
||||
"registrationOffice": "Temp Registergericht Aurich",
|
||||
"registrationNumber": "222222",
|
||||
@@ -334,7 +336,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
||||
"dateOfDeath": "2022-01-12"
|
||||
}
|
||||
}
|
||||
""".formatted(givenPartnerRel.getUuid()))
|
||||
""".formatted(newPartnerPerson.getUuid()))
|
||||
.port(port)
|
||||
.when()
|
||||
.patch("http://localhost/api/hs/office/partners/" + givenPartner.getUuid())
|
||||
@@ -348,7 +350,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
||||
"anchor": { "tradeName": "Hostsharing eG" },
|
||||
"holder": { "familyName": "Winkler" },
|
||||
"type": "PARTNER",
|
||||
"contact": { "caption": "third contact" }
|
||||
"contact": { "caption": "fourth contact" }
|
||||
},
|
||||
"details": {
|
||||
"registrationOffice": "Temp Registergericht Aurich",
|
||||
@@ -368,7 +370,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
||||
.matches(partner -> {
|
||||
assertThat(partner.getPartnerNumber()).isEqualTo(givenPartner.getPartnerNumber());
|
||||
assertThat(partner.getPartnerRel().getHolder().getFamilyName()).isEqualTo("Winkler");
|
||||
assertThat(partner.getPartnerRel().getContact().getCaption()).isEqualTo("third contact");
|
||||
assertThat(partner.getPartnerRel().getContact().getCaption()).isEqualTo("fourth contact");
|
||||
assertThat(partner.getDetails().getRegistrationOffice()).isEqualTo("Temp Registergericht Aurich");
|
||||
assertThat(partner.getDetails().getRegistrationNumber()).isEqualTo("222222");
|
||||
assertThat(partner.getDetails().getBirthName()).isEqualTo("Maja Schmidt");
|
||||
@@ -379,11 +381,11 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
||||
}
|
||||
|
||||
@Test
|
||||
void patchingThePartnerRelCreatesExPartnerRel() {
|
||||
void patchingThePartnerPersonCreatesExPartnerRel() {
|
||||
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenPartner = givenSomeTemporaryPartnerBessler(20011);
|
||||
final var givenPartnerRel = givenSomeTemporaryPartnerRel("Winkler", "third contact");
|
||||
final var newPartnerPerson = personRealRepo.findPersonByOptionalNameLike("Winkler").getFirst();
|
||||
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
@@ -391,9 +393,11 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
||||
.contentType(ContentType.JSON)
|
||||
.body("""
|
||||
{
|
||||
"partnerRel.uuid": "%s"
|
||||
"partnerRel": {
|
||||
"holder.uuid": "%s"
|
||||
}
|
||||
}
|
||||
""".formatted(givenPartnerRel.getUuid()))
|
||||
""".formatted(newPartnerPerson.getUuid()))
|
||||
.port(port)
|
||||
.when()
|
||||
.patch("http://localhost/api/hs/office/partners/" + givenPartner.getUuid())
|
||||
@@ -405,16 +409,16 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
assertThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent().get()
|
||||
.matches(partner -> {
|
||||
assertThat(partner.getPartnerRel().getHolder().getFamilyName()).isEqualTo("Winkler");
|
||||
assertThat(partner.getPartnerRel().getContact().getCaption()).isEqualTo("third contact");
|
||||
assertThat(partner.getPartnerRel().getHolder().getFamilyName()).isEqualTo("Winkler"); // updated
|
||||
assertThat(partner.getPartnerRel().getContact().getCaption()).isEqualTo("fourth contact"); // unchanged
|
||||
return true;
|
||||
});
|
||||
|
||||
// and an ex-partner-relation got created
|
||||
final var anchorpartnerPersonUUid = givenPartner.getPartnerRel().getAnchor().getUuid();
|
||||
assertThat(relationRepo.findRelationRelatedToPersonUuidRelationTypeMarkPersonAndContactData(anchorpartnerPersonUUid, EX_PARTNER, null, null, null))
|
||||
final var newPartnerPersonUuid = givenPartner.getPartnerRel().getHolder().getUuid();
|
||||
assertThat(relationRepo.findRelationRelatedToPersonUuidRelationTypeMarkPersonAndContactData(newPartnerPersonUuid, EX_PARTNER, null, null, null))
|
||||
.map(HsOfficeRelation::toShortString)
|
||||
.contains("rel(anchor='LP Hostsharing eG', type='EX_PARTNER', holder='UF Erben Bessler')");
|
||||
.contains("rel(anchor='NP Winkler, Paul', type='EX_PARTNER', holder='UF Erben Bessler')");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.hostsharing.hsadminng.hs.office.partner;
|
||||
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactFromResourceConverter;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRbacEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity;
|
||||
@@ -38,7 +39,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@WebMvcTest(HsOfficePartnerController.class)
|
||||
@Import({StrictMapper.class, DisableSecurityConfig.class})
|
||||
@Import({ StrictMapper.class, HsOfficeContactFromResourceConverter.class, DisableSecurityConfig.class})
|
||||
@ActiveProfiles("test")
|
||||
class HsOfficePartnerControllerRestTest {
|
||||
|
||||
@@ -108,8 +109,6 @@ class HsOfficePartnerControllerRestTest {
|
||||
"holder.uuid": "%s",
|
||||
"contact.uuid": "%s"
|
||||
},
|
||||
"person.uuid": "%s",
|
||||
"contact.uuid": "%s",
|
||||
"details": {
|
||||
"registrationOffice": "Temp Registergericht Aurich",
|
||||
"registrationNumber": "111111"
|
||||
@@ -118,8 +117,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 +142,6 @@ class HsOfficePartnerControllerRestTest {
|
||||
"holder.uuid": "%s",
|
||||
"contact.uuid": "%s"
|
||||
},
|
||||
"person.uuid": "%s",
|
||||
"contact.uuid": "%s",
|
||||
"details": {
|
||||
"registrationOffice": "Temp Registergericht Aurich",
|
||||
"registrationNumber": "111111"
|
||||
@@ -155,8 +150,6 @@ class HsOfficePartnerControllerRestTest {
|
||||
""".formatted(
|
||||
GIVEN_MANDANTE_UUID,
|
||||
GIVEN_PERSON_UUID,
|
||||
GIVEN_INVALID_UUID,
|
||||
GIVEN_PERSON_UUID,
|
||||
GIVEN_INVALID_UUID))
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
package net.hostsharing.hsadminng.hs.office.partner;
|
||||
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerDetailsPatchResource;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource;
|
||||
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.rbac.test.PatchUnitTestBase;
|
||||
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;
|
||||
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.persistence.EntityManager;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -22,19 +27,17 @@ import static org.mockito.Mockito.lenient;
|
||||
|
||||
@TestInstance(PER_CLASS)
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
HsOfficePartnerPatchResource,
|
||||
HsOfficePartnerRbacEntity
|
||||
> {
|
||||
// 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 {
|
||||
|
||||
private static final UUID INITIAL_PARTNER_UUID = UUID.randomUUID();
|
||||
private static final UUID INITIAL_CONTACT_UUID = UUID.randomUUID();
|
||||
private static final UUID INITIAL_PERSON_UUID = UUID.randomUUID();
|
||||
private static final UUID INITIAL_PARTNER_PERSON_UUID = UUID.randomUUID();
|
||||
private static final UUID INITIAL_DETAILS_UUID = UUID.randomUUID();
|
||||
private static final UUID PATCHED_PARTNER_ROLE_UUID = UUID.randomUUID();
|
||||
|
||||
private final HsOfficePersonRealEntity givenInitialPerson = HsOfficePersonRealEntity.builder()
|
||||
.uuid(INITIAL_PERSON_UUID)
|
||||
private final HsOfficePersonRealEntity givenInitialPartnerPerson = HsOfficePersonRealEntity.builder()
|
||||
.uuid(INITIAL_PARTNER_PERSON_UUID)
|
||||
.build();
|
||||
private final HsOfficeContactRealEntity givenInitialContact = HsOfficeContactRealEntity.builder()
|
||||
.uuid(INITIAL_CONTACT_UUID)
|
||||
@@ -43,22 +46,74 @@ class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
private final HsOfficePartnerDetailsEntity givenInitialDetails = HsOfficePartnerDetailsEntity.builder()
|
||||
.uuid(INITIAL_DETAILS_UUID)
|
||||
.build();
|
||||
|
||||
@Mock
|
||||
private EntityManager em;
|
||||
private EntityManagerWrapper emw;
|
||||
|
||||
private StrictMapper mapper = new StrictMapper(emw);
|
||||
|
||||
@BeforeEach
|
||||
void initMocks() {
|
||||
lenient().when(em.getReference(eq(HsOfficeRelationRealEntity.class), any())).thenAnswer(invocation ->
|
||||
HsOfficeRelationRealEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||
lenient().when(emw.getReference(eq(HsOfficePersonRealEntity.class), any())).thenAnswer(invocation ->
|
||||
HsOfficePersonRealEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||
lenient().when(emw.getReference(eq(HsOfficeContactRealEntity.class), any())).thenAnswer(invocation ->
|
||||
HsOfficeContactRealEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void patchPartnerPerson() {
|
||||
// given
|
||||
final var patchResource = newPatchResource();
|
||||
final var newHolderUuid = UUID.randomUUID();
|
||||
patchResource.setPartnerRel(new HsOfficeRelationPatchResource());
|
||||
patchResource.getPartnerRel().setHolderUuid(JsonNullable.of(newHolderUuid));
|
||||
final var entity = newInitialEntity();
|
||||
|
||||
// when
|
||||
createPatcher(entity).apply(patchResource);
|
||||
|
||||
// then
|
||||
assertThat(entity.getPartnerRel().getHolder().getUuid()).isEqualTo(newHolderUuid);
|
||||
}
|
||||
|
||||
@Test
|
||||
void patchPartnerContact() {
|
||||
// given
|
||||
final var patchResource = newPatchResource();
|
||||
final var newContactUuid = UUID.randomUUID();
|
||||
patchResource.setPartnerRel(new HsOfficeRelationPatchResource());
|
||||
patchResource.getPartnerRel().setContactUuid(JsonNullable.of(newContactUuid));
|
||||
final var entity = newInitialEntity();
|
||||
|
||||
// when
|
||||
createPatcher(entity).apply(patchResource);
|
||||
|
||||
// then
|
||||
assertThat(entity.getPartnerRel().getContact().getUuid()).isEqualTo(newContactUuid);
|
||||
}
|
||||
|
||||
@Test
|
||||
void patchPartnerDetails() {
|
||||
// given
|
||||
final var patchResource = newPatchResource();
|
||||
final var newDateOfBirth = LocalDate.now();
|
||||
patchResource.setDetails(new HsOfficePartnerDetailsPatchResource());
|
||||
patchResource.getDetails().setDateOfDeath(JsonNullable.of(newDateOfBirth));
|
||||
final var entity = newInitialEntity();
|
||||
|
||||
// when
|
||||
createPatcher(entity).apply(patchResource);
|
||||
|
||||
// then
|
||||
assertThat(entity.getDetails().getDateOfDeath()).isEqualTo(newDateOfBirth);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HsOfficePartnerRbacEntity newInitialEntity() {
|
||||
final var entity = HsOfficePartnerRbacEntity.builder()
|
||||
.uuid(INITIAL_PARTNER_UUID)
|
||||
.partnerNumber(12345)
|
||||
.partnerRel(HsOfficeRelationRealEntity.builder()
|
||||
.holder(givenInitialPerson)
|
||||
.holder(givenInitialPartnerPerson)
|
||||
.contact(givenInitialContact)
|
||||
.build())
|
||||
.details(givenInitialDetails)
|
||||
@@ -66,32 +121,11 @@ class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HsOfficePartnerPatchResource newPatchResource() {
|
||||
return new HsOfficePartnerPatchResource();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HsOfficePartnerEntityPatcher createPatcher(final HsOfficePartnerRbacEntity partner) {
|
||||
return new HsOfficePartnerEntityPatcher(em, partner);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<Property> propertyTestDescriptors() {
|
||||
return Stream.of(
|
||||
new JsonNullableProperty<>(
|
||||
"partnerRel",
|
||||
HsOfficePartnerPatchResource::setPartnerRelUuid,
|
||||
PATCHED_PARTNER_ROLE_UUID,
|
||||
HsOfficePartnerRbacEntity::setPartnerRel,
|
||||
newPartnerRel(PATCHED_PARTNER_ROLE_UUID))
|
||||
.notNullable()
|
||||
);
|
||||
}
|
||||
|
||||
private static HsOfficeRelationRealEntity newPartnerRel(final UUID uuid) {
|
||||
return HsOfficeRelationRealEntity.builder()
|
||||
.uuid(uuid)
|
||||
.build();
|
||||
return new HsOfficePartnerEntityPatcher(mapper, emw, partner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,38 @@
|
||||
package net.hostsharing.hsadminng.hs.office.relation;
|
||||
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactFromResourceConverter;
|
||||
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.persistence.EntityManager;
|
||||
import jakarta.validation.ValidationException;
|
||||
import java.util.Map;
|
||||
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.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@TestInstance(PER_CLASS)
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@@ -26,36 +41,84 @@ class HsOfficeRelationPatcherUnitTest extends PatchUnitTestBase<
|
||||
HsOfficeRelation
|
||||
> {
|
||||
|
||||
static final UUID INITIAL_RELATION_UUID = UUID.randomUUID();
|
||||
static final UUID PATCHED_CONTACT_UUID = UUID.randomUUID();
|
||||
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();
|
||||
{
|
||||
{
|
||||
HOLDER_PATCH_RESOURCE.setPersonType(HsOfficePersonTypeResource.NATURAL_PERSON);
|
||||
HOLDER_PATCH_RESOURCE.setFamilyName("Patched-Holder-Family-Name");
|
||||
HOLDER_PATCH_RESOURCE.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();
|
||||
{
|
||||
{
|
||||
CONTACT_PATCH_RESOURCE.setCaption("Patched-Contact-Caption");
|
||||
CONTACT_PATCH_RESOURCE.setEmailAddresses(Map.ofEntries(
|
||||
Map.entry("main", "patched@example.org")
|
||||
));
|
||||
}
|
||||
};
|
||||
private static HsOfficeContactRealEntity PATCHED_CONTACT = HsOfficeContactRealEntity.builder()
|
||||
.uuid(PATCHED_CONTACT_UUID)
|
||||
.caption("Patched-Contact-Caption")
|
||||
.emailAddresses(Map.ofEntries(
|
||||
Map.entry("main", "patched@example.org")
|
||||
))
|
||||
.build();
|
||||
|
||||
@Mock
|
||||
EntityManager em;
|
||||
private EntityManagerWrapper emw;
|
||||
|
||||
private StrictMapper mapper;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void initMocks() {
|
||||
lenient().when(em.getReference(eq(HsOfficeContactRealEntity.class), any())).thenAnswer(invocation ->
|
||||
HsOfficeContactRealEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||
}
|
||||
void init() {
|
||||
mapper = new StrictMapper(emw); // emw is injected after the constructor got called
|
||||
mapper.addConverter(
|
||||
new HsOfficeContactFromResourceConverter<>(),
|
||||
HsOfficeContactInsertResource.class, HsOfficeContactRealEntity.class);
|
||||
|
||||
final HsOfficePersonRealEntity givenInitialAnchorPerson = HsOfficePersonRealEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.build();
|
||||
final HsOfficePersonRealEntity givenInitialHolderPerson = HsOfficePersonRealEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.build();
|
||||
final HsOfficeContactRealEntity givenInitialContact = HsOfficeContactRealEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.build();
|
||||
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 HsOfficeRelationRbacEntity();
|
||||
final var entity = new HsOfficeRelationRealEntity();
|
||||
entity.setUuid(INITIAL_RELATION_UUID);
|
||||
entity.setType(HsOfficeRelationType.REPRESENTATIVE);
|
||||
entity.setAnchor(givenInitialAnchorPerson);
|
||||
entity.setHolder(givenInitialHolderPerson);
|
||||
entity.setContact(givenInitialContact);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -65,24 +128,114 @@ class HsOfficeRelationPatcherUnitTest extends PatchUnitTestBase<
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HsOfficeRelationEntityPatcher createPatcher(final HsOfficeRelation relation) {
|
||||
return new HsOfficeRelationEntityPatcher(em, relation);
|
||||
protected HsOfficeRelationPatcher createPatcher(final HsOfficeRelation relation) {
|
||||
return new HsOfficeRelationPatcher(mapper, emw, relation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<Property> propertyTestDescriptors() {
|
||||
return Stream.of(
|
||||
new JsonNullableProperty<>(
|
||||
"contact",
|
||||
"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,
|
||||
newContact(PATCHED_CONTACT_UUID))
|
||||
PATCHED_CONTACT),
|
||||
new SimpleProperty<>(
|
||||
"contact",
|
||||
HsOfficeRelationPatchResource::setContact,
|
||||
CONTACT_PATCH_RESOURCE,
|
||||
HsOfficeRelation::setContact,
|
||||
withoutUuid(PATCHED_CONTACT))
|
||||
.notNullable()
|
||||
);
|
||||
}
|
||||
|
||||
static HsOfficeContactRealEntity newContact(final UUID uuid) {
|
||||
return HsOfficeContactRealEntity.builder().uuid(uuid).build();
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.NATU
|
||||
import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.UNINCORPORATED_FIRM;
|
||||
import static net.hostsharing.hsadminng.rbac.grant.RawRbacGrantEntity.distinctGrantDisplaysOf;
|
||||
import static net.hostsharing.hsadminng.rbac.role.RawRbacRoleEntity.distinctRoleNamesOf;
|
||||
import static net.hostsharing.hsadminng.rbac.role.RbacRoleType.ADMIN;
|
||||
import static net.hostsharing.hsadminng.rbac.test.JpaAttempt.attempt;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -282,7 +283,40 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
|
||||
assertThatRelationIsNotVisibleForUserWithRole(
|
||||
result.returnedValue(),
|
||||
"hs_office.contact#fifthcontact:ADMIN");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostsharingAdmin_withoutAssumedRole_canUpdateHolderOfArbitraryRelation() {
|
||||
// given
|
||||
context("superuser-alex@hostsharing.net");
|
||||
final var givenRelation = givenSomeTemporaryRelationBessler(
|
||||
"Bert", "fifth contact");
|
||||
final var oldHolderPerson = givenRelation.getHolder();
|
||||
final var newHolderPerson = personRepo.findPersonByOptionalNameLike("Paul").getFirst();
|
||||
assertThatRelationActuallyInDatabase(givenRelation);
|
||||
assertThatRelationIsVisibleForUserWithRole(
|
||||
givenRelation,
|
||||
givenRelation.getHolder().roleId(ADMIN));
|
||||
|
||||
// when
|
||||
final var result = jpaAttempt.transacted(() -> {
|
||||
context("superuser-alex@hostsharing.net");
|
||||
givenRelation.setHolder(newHolderPerson);
|
||||
return toCleanup(relationRbacRepo.save(givenRelation).load());
|
||||
});
|
||||
|
||||
// then
|
||||
result.assertSuccessful();
|
||||
assertThat(result.returnedValue().getHolder().getGivenName()).isEqualTo("Paul");
|
||||
assertThatRelationIsVisibleForUserWithRole(
|
||||
result.returnedValue(),
|
||||
"rbac.global#global:ADMIN");
|
||||
assertThatRelationIsVisibleForUserWithRole(
|
||||
result.returnedValue(),
|
||||
newHolderPerson.roleId(ADMIN));
|
||||
assertThatRelationIsNotVisibleForUserWithRole(
|
||||
result.returnedValue(),
|
||||
oldHolderPerson.roleId(ADMIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.hostsharing.hsadminng.hs.office.scenarios.contact.RemovePhoneNumberFr
|
||||
import net.hostsharing.hsadminng.hs.office.scenarios.contact.ReplaceContactData;
|
||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateExternalDebitorForPartner;
|
||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSelfDebitorForPartner;
|
||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSelfDebitorForPartnerWithIdenticalContactData;
|
||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSepaMandateForDebitor;
|
||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.DeleteDebitor;
|
||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.DontDeleteDefaultDebitor;
|
||||
@@ -265,11 +266,27 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
class DebitorScenarios {
|
||||
|
||||
@Test
|
||||
@Order(2000)
|
||||
@Requires("Partner: P-31011 - Michelle Matthieu")
|
||||
@Produces("Debitor: D-3101100 - Michelle Matthieu")
|
||||
void shouldCreateSelfDebitorForPartnerWithIdenticalContactData() {
|
||||
new CreateSelfDebitorForPartnerWithIdenticalContactData(scenarioTest)
|
||||
.given("partnerNumber", "P-31011")
|
||||
.given("debitorNumberSuffix", "00") // TODO.impl: could be assigned automatically, but is not yet
|
||||
.given("billable", true)
|
||||
.given("vatBusiness", false)
|
||||
.given("vatReverseCharge", false)
|
||||
.given("defaultPrefix", "mim")
|
||||
.doRun()
|
||||
.keep();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2010)
|
||||
@Requires("Partner: P-31010 - Test AG")
|
||||
@Produces("Debitor: D-3101000 - Test AG - main debitor")
|
||||
void shouldCreateSelfDebitorForPartner() {
|
||||
void shouldCreateSelfDebitorForPartnerWithDistinctContactData() {
|
||||
new CreateSelfDebitorForPartner(scenarioTest)
|
||||
.given("partnerPersonTradeName", "Test AG")
|
||||
.given("billingContactCaption", "Test AG - billing department")
|
||||
@@ -654,7 +671,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
||||
|
||||
@Test
|
||||
@Order(6010)
|
||||
@Requires("Partner: P-31011 - Michelle Matthieu")
|
||||
@Requires("Debitor: D-3101100 - Michelle Matthieu") // which should also get updated
|
||||
void shouldReplaceDeceasedPartnerByCommunityOfHeirs() {
|
||||
new ReplaceDeceasedPartnerWithCommunityOfHeirs(scenarioTest)
|
||||
.given("partnerNumber", "P-31011")
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package net.hostsharing.hsadminng.hs.office.scenarios.debitor;
|
||||
|
||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
|
||||
public class CreateSelfDebitorForPartnerWithIdenticalContactData
|
||||
extends UseCase<CreateSelfDebitorForPartnerWithIdenticalContactData> {
|
||||
|
||||
public CreateSelfDebitorForPartnerWithIdenticalContactData(final ScenarioTest testSuite) {
|
||||
super(testSuite);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpResponse run() {
|
||||
withTitle("Determine Partner-Person UUID", () ->
|
||||
httpGet("/api/hs/office/partners/" + uriEncoded("%{partnerNumber}"))
|
||||
.reportWithResponse().expecting(HttpStatus.OK).expecting(JSON)
|
||||
.extractUuidAlias("partnerRel.holder.uuid", "partnerPersonUuid")
|
||||
.extractUuidAlias("partnerRel.contact.uuid", "partnerContactUuid")
|
||||
);
|
||||
|
||||
return httpPost("/api/hs/office/debitors", usingJsonBody("""
|
||||
{
|
||||
"debitorRel": {
|
||||
"anchor.uuid": ${partnerPersonUuid},
|
||||
"holder.uuid": ${partnerPersonUuid},
|
||||
"contact.uuid": ${partnerContactUuid}
|
||||
},
|
||||
"debitorNumberSuffix": ${debitorNumberSuffix},
|
||||
"billable": ${billable},
|
||||
"vatId": ${vatId???},
|
||||
"vatCountryCode": ${vatCountryCode???},
|
||||
"vatBusiness": ${vatBusiness},
|
||||
"vatReverseCharge": ${vatReverseCharge},
|
||||
"defaultPrefix": ${defaultPrefix}
|
||||
}
|
||||
"""))
|
||||
.expecting(CREATED).expecting(JSON);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,101 +12,81 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase<ReplaceD
|
||||
|
||||
public ReplaceDeceasedPartnerWithCommunityOfHeirs(final ScenarioTest testSuite) {
|
||||
super(testSuite);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpResponse run() {
|
||||
|
||||
obtain("Person: Hostsharing eG", () ->
|
||||
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,20 +100,44 @@ public class ReplaceDeceasedPartnerWithCommunityOfHeirs extends UseCase<ReplaceD
|
||||
"Verify the Updated Partner",
|
||||
() -> 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}"),
|
||||
path("partnerRel.contact.postalAddress").lenientlyContainsJson("§{communityOfHeirsPostalAddress}"),
|
||||
path("partnerRel.contact.phoneNumbers.office").contains("%{communityOfHeirsOfficePhoneNumber}"),
|
||||
path("partnerRel.contact.emailAddresses.main").contains("%{communityOfHeirsEmailAddress}")
|
||||
);
|
||||
|
||||
// TODO.test: Verify the EX_PARTNER-Relation, once we fixed the anchor problem, see HsOfficePartnerController
|
||||
// (net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerController.optionallyCreateExPartnerRelation)
|
||||
verify(
|
||||
"Verify the Ex-Partner-Relation",
|
||||
() -> httpGet(
|
||||
"/api/hs/office/relations?relationType=EX_PARTNER&personUuid=%{Person: %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}}")
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].anchor.tradeName").contains(
|
||||
"Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}")
|
||||
);
|
||||
|
||||
verify(
|
||||
"Verify the Representative-Relation",
|
||||
() -> httpGet("/api/hs/office/relations?relationType=REPRESENTATIVE&personUuid=%{Person: %{representativeGivenName} %{representativeFamilyName}}")
|
||||
() -> httpGet(
|
||||
"/api/hs/office/relations?relationType=REPRESENTATIVE&personUuid=%{Person: Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}}")
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].anchor.tradeName").contains("Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}"),
|
||||
path("[0].holder.familyName").contains("%{representativeFamilyName}")
|
||||
path("[0].anchor.tradeName").contains(
|
||||
"Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}"),
|
||||
path("[0].holder.familyName").contains("%{representativeFamilyName}"),
|
||||
path("[0].contact.postalAddress").lenientlyContainsJson("§{communityOfHeirsPostalAddress}"),
|
||||
path("[0].contact.phoneNumbers.office").contains("%{communityOfHeirsOfficePhoneNumber}"),
|
||||
path("[0].contact.emailAddresses.main").contains("%{communityOfHeirsEmailAddress}")
|
||||
);
|
||||
|
||||
// TODO.test: Verify Debitor, Membership, Coop-Shares and Coop-Assets once implemented
|
||||
verify(
|
||||
"Verify the Debitor-Relation",
|
||||
() -> httpGet(
|
||||
"/api/hs/office/debitors?partnerNumber=%{partnerNumber}")
|
||||
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||
path("[0].debitorRel.anchor.tradeName").contains(
|
||||
"Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}"),
|
||||
path("[0].debitorRel.holder.tradeName").contains(
|
||||
"Erbengemeinschaft %{givenNameOfDeceasedPerson} %{familyNameOfDeceasedPerson}")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase.HttpResponse;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.scenarios.TemplateResolver.Resolver.DROP_COMMENTS;
|
||||
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class PathAssertion {
|
||||
@@ -27,6 +28,18 @@ public class PathAssertion {
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Consumer<UseCase.HttpResponse> lenientlyContainsJson(final String resolvableValue) {
|
||||
return response -> {
|
||||
try {
|
||||
lenientlyEquals(ScenarioTest.resolve(resolvableValue, DROP_COMMENTS)).matches(response.getFromBody(path)) ;
|
||||
} catch (final AssertionError e) {
|
||||
// without this, the error message is often lacking important context
|
||||
fail(e.getMessage() + " in `path(\"" + path + "\").contains(\"" + resolvableValue + "\")`" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Consumer<HttpResponse> doesNotExist() {
|
||||
return response -> {
|
||||
try {
|
||||
|
||||
@@ -32,6 +32,12 @@ public class TemplateResolver {
|
||||
return jsonQuoted(value);
|
||||
}
|
||||
},
|
||||
JSON_OBJECT('§'){
|
||||
@Override
|
||||
String convert(final Object value, final Resolver resolver) {
|
||||
return jsonObject(value);
|
||||
}
|
||||
},
|
||||
URI_ENCODED('&'){
|
||||
@Override
|
||||
String convert(final Object value, final Resolver resolver) {
|
||||
@@ -213,4 +219,12 @@ public class TemplateResolver {
|
||||
default -> "\"" + value + "\"";
|
||||
};
|
||||
}
|
||||
|
||||
private static String jsonObject(final Object value) {
|
||||
return switch (value) {
|
||||
case null -> null;
|
||||
case String string -> "{" + string.replace("\n", " ") + "}";
|
||||
default -> throw new IllegalArgumentException("can not format " + value.getClass() + " (" + value + ") as JSON object");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import static org.assertj.core.api.Assumptions.assumeThat;
|
||||
public abstract class PatchUnitTestBase<R, E> {
|
||||
|
||||
@Test
|
||||
void willPatchNoProperty() {
|
||||
protected void willPatchNoProperty() {
|
||||
// given
|
||||
final var givenEntity = newInitialEntity();
|
||||
final var patchResource = newPatchResource();
|
||||
@@ -73,7 +73,7 @@ public abstract class PatchUnitTestBase<R, E> {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("propertyTestCases")
|
||||
void willThrowExceptionIfNotNullableValueIsNull(final Property<R, Object, E, Object> testCase) {
|
||||
protected void willThrowExceptionIfNotNullableValueIsNull(final Property<R, Object, E, Object> testCase) {
|
||||
assumeThat(testCase instanceof JsonNullableProperty).isTrue();
|
||||
assumeThat(testCase.nullable).isFalse();
|
||||
|
||||
@@ -94,7 +94,7 @@ public abstract class PatchUnitTestBase<R, E> {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("propertyTestCases")
|
||||
void willPatchOnlyGivenPropertyToNull(final Property<R, Object, E, Object> testCase) {
|
||||
protected void willPatchOnlyGivenPropertyToNull(final Property<R, Object, E, Object> testCase) {
|
||||
assumeThat(testCase.nullable).isTrue();
|
||||
|
||||
// given
|
||||
@@ -113,7 +113,7 @@ public abstract class PatchUnitTestBase<R, E> {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("propertyTestCases")
|
||||
void willNotPatchIfGivenPropertyNotGiven(final Property<R, Object, E, Object> testCase) {
|
||||
protected void willNotPatchIfGivenPropertyNotGiven(final Property<R, Object, E, Object> testCase) {
|
||||
|
||||
// given
|
||||
final var givenEntity = newInitialEntity();
|
||||
|
||||
Reference in New Issue
Block a user