From eba39ff27ad25636a2bcd193fd312904c052410d Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Sun, 12 Jan 2025 13:40:32 +0100 Subject: [PATCH] upgrade to Spring Boot 3.4.1 and fixed most issues, except one particular strange RBAC problem --- .tc-environment | 2 +- .unset-environment | 2 +- build.gradle | 10 +- etc/allowed-licenses.json | 22 ++-- .../RestResponseEntityExceptionHandler.java | 3 +- .../HsUnixUserHostingAssetValidator.java | 2 + ...OfficeCoopSharesTransactionController.java | 5 +- .../debitor/HsOfficeDebitorController.java | 30 +++-- .../HsOfficeMembershipController.java | 18 ++- .../HsOfficeMembershipEntityPatcher.java | 6 +- .../partner/HsOfficePartnerRepository.java | 39 ++++-- .../person/HsOfficePersonRealEntity.java | 2 - .../HsOfficeSepaMandateController.java | 26 +++- .../hs-office/hs-office-debitor-schemas.yaml | 1 + ...OfficeContactControllerAcceptanceTest.java | 1 - ...esTransactionControllerAcceptanceTest.java | 118 ++++++++++-------- ...opSharesTransactionControllerRestTest.java | 4 +- ...iceMembershipControllerAcceptanceTest.java | 1 - ...OfficeMembershipEntityPatcherUnitTest.java | 4 +- ...fficePartnerRepositoryIntegrationTest.java | 60 ++++----- ...sOfficePersonControllerAcceptanceTest.java | 1 - ...ceSepaMandateControllerAcceptanceTest.java | 10 +- src/test/resources/application.yml | 2 +- 23 files changed, 221 insertions(+), 148 deletions(-) diff --git a/.tc-environment b/.tc-environment index ecc6dc9a..595d0096 100644 --- a/.tc-environment +++ b/.tc-environment @@ -4,5 +4,5 @@ export HSADMINNG_POSTGRES_ADMIN_PASSWORD= export HSADMINNG_POSTGRES_RESTRICTED_USERNAME=restricted export HSADMINNG_SUPERUSER=superuser-alex@hostsharing.net export HSADMINNG_MIGRATION_DATA_PATH=migration -export LIQUIBASE_CONTEXT= +export LIQUIBASE_COMMAND_CONTEXT_FILTER= export LANG=en_US.UTF-8 diff --git a/.unset-environment b/.unset-environment index a9e4ee81..fbc180cc 100644 --- a/.unset-environment +++ b/.unset-environment @@ -4,5 +4,5 @@ unset HSADMINNG_POSTGRES_ADMIN_PASSWORD unset HSADMINNG_POSTGRES_RESTRICTED_USERNAME unset HSADMINNG_SUPERUSER unset HSADMINNG_MIGRATION_DATA_PATH -unset LIQUIBASE_CONTEXT +unset LIQUIBASE_COMMAND_CONTEXT_FILTER diff --git a/build.gradle b/build.gradle index 7646a33b..2ef4a819 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,11 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.3.7' + id 'org.springframework.boot' version '3.4.1' id 'io.spring.dependency-management' version '1.1.7' id 'io.openapiprocessor.openapi-processor' version '2023.2' id 'com.github.jk1.dependency-license-report' version '2.9' id "org.owasp.dependencycheck" version "11.1.1" - id "com.diffplug.spotless" version "7.0.0" + id "com.diffplug.spotless" version "7.0.1" id 'jacoco' id 'info.solidsoft.pitest' version '1.15.0' id 'se.patrikerdes.use-latest-versions' version '0.2.18' @@ -20,6 +20,8 @@ wrapper { gradleVersion = '8.5' } +// FIXME: Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build what is described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.3 + configurations { compileOnly { extendsFrom annotationProcessor @@ -61,7 +63,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.10.0' - implementation 'org.springdoc:springdoc-openapi:2.6.0' + implementation 'org.springdoc:springdoc-openapi:2.8.1' implementation 'org.postgresql:postgresql:42.7.4' implementation 'org.liquibase:liquibase-core:4.30.0' implementation 'io.hypersistence:hypersistence-utils-hibernate-63:3.9.0' @@ -71,7 +73,7 @@ dependencies { implementation 'net.java.dev.jna:jna:5.16.0' implementation 'org.modelmapper:modelmapper:3.2.2' implementation 'org.iban4j:iban4j:3.2.10-RELEASE' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.1' implementation 'org.reflections:reflections:0.10.2' compileOnly 'org.projectlombok:lombok' diff --git a/etc/allowed-licenses.json b/etc/allowed-licenses.json index ff50a78f..447f5c62 100644 --- a/etc/allowed-licenses.json +++ b/etc/allowed-licenses.json @@ -5,9 +5,23 @@ { "moduleLicense": "Apache-2.0" }, { "moduleLicense": "Apache License 2.0" }, { "moduleLicense": "Apache License v2.0" }, + { "moduleLicense": "Apache License Version 2.0" }, { "moduleLicense": "Apache License, Version 2.0" }, + { "moduleLicense": "The Apache License, Version 2.0" }, { "moduleLicense": "The Apache Software License, Version 2.0" }, + { + "moduleLicense": null, + "#moduleLicense": "Apache License 2.0, see https://github.com/springdoc/springdoc-openapi/blob/main/LICENSE", + "moduleVersion": "2.4.0", + "moduleName": "org.springdoc:springdoc-openapi" + }, + { + "moduleLicense": null, + "moduleVersion": "1.0.0", + "moduleName": "org.jspecify:jspecify" + }, + { "moduleLicense": "BSD License" }, { "moduleLicense": "BSD-2-Clause" }, { "moduleLicense": "BSD-3-Clause" }, @@ -46,14 +60,8 @@ { "moduleLicense": "Public Domain, per Creative Commons CC0", "moduleVersion": "2.0.3" - }, - - { - "moduleLicense": null, - "#moduleLicense": "Apache License 2.0, see https://github.com/springdoc/springdoc-openapi/blob/main/LICENSE", - "moduleVersion": "2.4.0", - "moduleName": "org.springdoc:springdoc-openapi" } + ] } diff --git a/src/main/java/net/hostsharing/hsadminng/errors/RestResponseEntityExceptionHandler.java b/src/main/java/net/hostsharing/hsadminng/errors/RestResponseEntityExceptionHandler.java index c366d7bc..64b72ef8 100644 --- a/src/main/java/net/hostsharing/hsadminng/errors/RestResponseEntityExceptionHandler.java +++ b/src/main/java/net/hostsharing/hsadminng/errors/RestResponseEntityExceptionHandler.java @@ -97,6 +97,7 @@ public class RestResponseEntityExceptionHandler return errorResponse(request, HttpStatus.valueOf(statusCode.value()), Optional.ofNullable(response.getBody()).map(Object::toString).orElse(firstMessageLine(exc))); } + @Override @SuppressWarnings("unchecked,rawtypes") protected ResponseEntity handleHttpMessageNotReadable( @@ -131,7 +132,7 @@ public class RestResponseEntityExceptionHandler final HttpStatusCode status, final WebRequest request) { final var errorList = exc - .getAllValidationResults() + .getAllValidationResults() // FIXME: deprecated .stream() .map(ParameterValidationResult::getResolvableErrors) .flatMap(Collection::stream) diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java index 024866c2..9f2ac336 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java @@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType; import net.hostsharing.hsadminng.hs.validation.PropertiesProvider; import jakarta.persistence.EntityManager; +import jakarta.persistence.FlushModeType; import java.util.regex.Pattern; import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty; @@ -53,6 +54,7 @@ class HsUnixUserHostingAssetValidator extends HostingAssetEntityValidator { } private static Integer computeUserId(final EntityManager em, final PropertiesProvider propertiesProvider) { + em.setFlushMode(FlushModeType.COMMIT); // FIXME: check and remove or reset final Object result = em.createNativeQuery("SELECT nextval('hs_hosting.asset_unixuser_system_id_seq')", Integer.class) .getSingleResult(); return (Integer) result; diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java index b903dd85..9afef7da 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java @@ -8,7 +8,7 @@ import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopShar import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopSharesTransactionInsertResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopSharesTransactionResource; import net.hostsharing.hsadminng.errors.MultiValidationException; -import net.hostsharing.hsadminng.mapper.StandardMapper; +import net.hostsharing.hsadminng.mapper.StrictMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat.ISO; @@ -33,14 +33,13 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar private Context context; @Autowired - private StandardMapper mapper; + private StrictMapper mapper; @Autowired private HsOfficeCoopSharesTransactionRepository coopSharesTransactionRepo; @Override @Transactional(readOnly = true) - @Timed("app.office.coopShares.api.getListOfCoopShares") public ResponseEntity> getListOfCoopShares( final String currentSubject, diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorController.java index 1e82b848..089d85b2 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorController.java @@ -2,13 +2,14 @@ package net.hostsharing.hsadminng.hs.office.debitor; import io.micrometer.core.annotation.Timed; import net.hostsharing.hsadminng.context.Context; +import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeDebitorsApi; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorInsertResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorResource; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealRepository; -import net.hostsharing.hsadminng.mapper.StandardMapper; +import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.persistence.EntityExistsValidator; import org.apache.commons.lang3.Validate; import org.hibernate.Hibernate; @@ -36,13 +37,16 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi { private Context context; @Autowired - private StandardMapper mapper; + private StrictMapper mapper; @Autowired private HsOfficeDebitorRepository debitorRepo; @Autowired - private HsOfficeRelationRealRepository relrealRepo; + private HsOfficeRelationRealRepository realRelRepo; + + @Autowired + private HsOfficeBankAccountRepository bankAccountRepo; @Autowired private EntityExistsValidator entityValidator; @@ -88,18 +92,18 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi { Validate.isTrue(body.getDebitorRel() == null || body.getDebitorRel().getMark() == null, "ERROR: [400] debitorRel.mark must be null"); - final var entityToSave = mapper.map(body, HsOfficeDebitorEntity.class); - if (body.getDebitorRel() != null) { + final var entityToSave = mapper.map(body, HsOfficeDebitorEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER); + if (body.getDebitorRel() != null) { // FIXME: move this into RESOURCE_TO_ENTITY_POSTMAPPER final var debitorRel = mapper.map("debitorRel.", body.getDebitorRel(), HsOfficeRelationRealEntity.class); debitorRel.setType(DEBITOR); entityValidator.validateEntityExists("debitorRel.anchorUuid", debitorRel.getAnchor()); entityValidator.validateEntityExists("debitorRel.holderUuid", debitorRel.getHolder()); entityValidator.validateEntityExists("debitorRel.contactUuid", debitorRel.getContact()); - entityToSave.setDebitorRel(relrealRepo.save(debitorRel)); + entityToSave.setDebitorRel(realRelRepo.save(debitorRel)); } else { - final var debitorRelOptional = relrealRepo.findByUuid(body.getDebitorRelUuid()); + final var debitorRelOptional = realRelRepo.findByUuid(body.getDebitorRelUuid()); debitorRelOptional.ifPresentOrElse( - debitorRel -> {entityToSave.setDebitorRel(relrealRepo.save(debitorRel));}, + debitorRel -> {entityToSave.setDebitorRel(realRelRepo.save(debitorRel));}, () -> { throw new ValidationException( "Unable to find RealRelation by debitorRelUuid: " + body.getDebitorRelUuid()); @@ -107,7 +111,7 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi { } final var savedEntity = debitorRepo.save(entityToSave); - em.flush(); + em.flush(); // FIXME: necessary? em.refresh(savedEntity); final var uri = @@ -191,6 +195,14 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi { return ResponseEntity.ok(mapped); } + final BiConsumer RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> { + if (resource.getRefundBankAccountUuid() != null) { + final var bankAccountEntity = bankAccountRepo.findByUuid(resource.getRefundBankAccountUuid()) + .orElseThrow(() -> new ValidationException()); // FIXME + entity.setRefundBankAccount(bankAccountEntity); + } + }; + final BiConsumer ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource) -> { resource.setDebitorNumber(entity.getTaggedDebitorNumber()); }; diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipController.java index 43cc292d..778d12b9 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipController.java @@ -7,13 +7,15 @@ import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMember import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipResource; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; -import net.hostsharing.hsadminng.mapper.StandardMapper; +import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository; +import net.hostsharing.hsadminng.mapper.StrictMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; +import jakarta.persistence.EntityNotFoundException; import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; @@ -28,7 +30,10 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi { private Context context; @Autowired - private StandardMapper mapper; + private StrictMapper mapper; + + @Autowired + private HsOfficePartnerRepository partnerRepo; @Autowired private HsOfficeMembershipRepository membershipRepo; @@ -68,7 +73,7 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi { context.define(currentSubject, assumedRoles); - final var entityToSave = mapper.map(body, HsOfficeMembershipEntity.class); + final var entityToSave = mapper.map(body, HsOfficeMembershipEntity.class, SEPA_MANDATE_RESOURCE_TO_ENTITY_POSTMAPPER); final var saved = membershipRepo.save(entityToSave); @@ -164,5 +169,12 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi { if (entity.getValidity().hasUpperBound()) { resource.setValidTo(entity.getValidity().upper().minusDays(1)); } + resource.getPartner().setPartnerNumber(entity.getPartner().getTaggedPartnerNumber()); // FIXME: use partner mapper? + }; + + final BiConsumer SEPA_MANDATE_RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> { + entity.setPartner(partnerRepo.findByUuid(resource.getPartnerUuid()) + .orElseThrow(() -> new EntityNotFoundException( + "ERROR: [400] partnerUuid %s not found".formatted(resource.getPartnerUuid())))); }; } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityPatcher.java b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityPatcher.java index 33bf363b..79bfb340 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityPatcher.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityPatcher.java @@ -2,18 +2,18 @@ package net.hostsharing.hsadminng.hs.office.membership; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource; import net.hostsharing.hsadminng.mapper.EntityPatcher; -import net.hostsharing.hsadminng.mapper.StandardMapper; import net.hostsharing.hsadminng.mapper.OptionalFromJson; +import net.hostsharing.hsadminng.mapper.StrictMapper; import java.util.Optional; public class HsOfficeMembershipEntityPatcher implements EntityPatcher { - private final StandardMapper mapper; + private final StrictMapper mapper; private final HsOfficeMembershipEntity entity; public HsOfficeMembershipEntityPatcher( - final StandardMapper mapper, + final StrictMapper mapper, final HsOfficeMembershipEntity entity) { this.mapper = mapper; this.entity = entity; diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java index 3ae4a26a..7715d011 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java @@ -16,18 +16,33 @@ public interface HsOfficePartnerRepository extends Repository findAll(); // TODO.refa: move to a repo in test sources - @Query(""" - SELECT partner FROM HsOfficePartnerEntity partner - JOIN HsOfficeRelationRealEntity rel ON rel.uuid = partner.partnerRel.uuid - JOIN HsOfficeContactRealEntity contact ON contact.uuid = rel.contact.uuid - JOIN HsOfficePersonRealEntity person ON person.uuid = rel.holder.uuid - WHERE :name is null - OR partner.details.birthName like concat(cast(:name as text), '%') - OR contact.caption like concat(cast(:name as text), '%') - OR person.tradeName like concat(cast(:name as text), '%') - OR person.givenName like concat(cast(:name as text), '%') - OR person.familyName like concat(cast(:name as text), '%') - """) +// @Query(""" +// SELECT partner FROM HsOfficePartnerEntity partner +// JOIN HsOfficeRelationRealEntity rel ON rel.uuid = partner.partnerRel.uuid +// JOIN HsOfficeContactRealEntity contact ON contact.uuid = rel.contact.uuid +// JOIN HsOfficePersonRealEntity person ON person.uuid = rel.holder.uuid +// LEFT JOIN HsOfficePartnerDetailsEntity details ON partner.details.uuid = details.uuid +// WHERE :name is null +// OR (details IS NOT NULL AND details.birthName like concat(cast(:name as text), '%')) +// OR contact.caption like concat(cast(:name as text), '%') +// OR person.tradeName like concat(cast(:name as text), '%') +// OR person.givenName like concat(cast(:name as text), '%') +// OR person.familyName like concat(cast(:name as text), '%') +// """) + @Query(value = """ + select partner.uuid, partner.detailsuuid, partner.partnernumber, partner.partnerreluuid, partner.version + from hs_office.partner_rv partner + join hs_office.relation partnerRel on partnerRel.uuid = partner.partnerreluuid + join hs_office.contact contact on contact.uuid = partnerRel.contactuuid + join hs_office.person partnerPerson on partnerPerson.uuid = partnerRel.holderuuid + left join hs_office.partner_details_rv partnerDetails on partnerDetails.uuid = partner.detailsuuid + where :name is null + or (partnerDetails.uuid is not null and partnerDetails.birthname like (cast(:name as text) || '%') escape '') + or contact.caption like (cast(:name as text) || '%') escape '' + or partnerPerson.tradename like (cast(:name as text) || '%') escape '' + or partnerPerson.givenname like (cast(:name as text) || '%') escape '' + or partnerPerson.familyname like (cast(:name as text) || '%') escape '' + """, nativeQuery = true) @Timed("app.office.partners.repo.findPartnerByOptionalNameLike") List findPartnerByOptionalNameLike(String name); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRealEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRealEntity.java index 766785a0..0d320d07 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRealEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRealEntity.java @@ -3,7 +3,6 @@ package net.hostsharing.hsadminng.hs.office.person; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import lombok.experimental.FieldNameConstants; import lombok.experimental.SuperBuilder; import net.hostsharing.hsadminng.errors.DisplayAs; @@ -17,7 +16,6 @@ import jakarta.persistence.Table; @Setter @NoArgsConstructor @SuperBuilder(toBuilder = true) -@FieldNameConstants @DisplayAs("RealPerson") public class HsOfficePersonRealEntity extends HsOfficePerson { } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateController.java index 02a3beb4..61399d1e 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateController.java @@ -2,11 +2,14 @@ package net.hostsharing.hsadminng.hs.office.sepamandate; import io.micrometer.core.annotation.Timed; import net.hostsharing.hsadminng.context.Context; +import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository; +import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeSepaMandatesApi; +import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeSepaMandateInsertResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeSepaMandatePatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeSepaMandateResource; -import net.hostsharing.hsadminng.mapper.StandardMapper; +import net.hostsharing.hsadminng.mapper.StrictMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; @@ -15,6 +18,7 @@ import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBui import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; +import jakarta.validation.ValidationException; import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; @@ -29,7 +33,13 @@ public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi { private Context context; @Autowired - private StandardMapper mapper; + private StrictMapper mapper; + + @Autowired + private HsOfficeDebitorRepository debitorRepo; + + @Autowired + private HsOfficeBankAccountRepository bankAccountRepo; @Autowired private HsOfficeSepaMandateRepository sepaMandateRepo; @@ -137,10 +147,22 @@ public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi { if (entity.getValidity().hasUpperBound()) { resource.setValidTo(entity.getValidity().upper().minusDays(1)); } + resource.setDebitor(mapper.map(entity.getDebitor(), HsOfficeDebitorResource.class)); resource.getDebitor().setDebitorNumber(entity.getDebitor().getTaggedDebitorNumber()); + resource.getDebitor().getPartner().setPartnerNumber(entity.getDebitor().getPartner().getTaggedPartnerNumber()); }; final BiConsumer SEPA_MANDATE_RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> { entity.setValidity(toPostgresDateRange(resource.getValidFrom(), resource.getValidTo())); + entity.setDebitor(debitorRepo.findByUuid(resource.getDebitorUuid()).orElseThrow( () -> + new ValidationException( + "debitor.uuid='" + resource.getDebitorUuid() + "' not found or not accessible" + ) + )); + entity.setBankAccount(bankAccountRepo.findByUuid(resource.getBankAccountUuid()).orElseThrow( () -> + new ValidationException( + "bankAccount.uuid='" + resource.getBankAccountUuid() + "' not found or not accessible" + ) + )); }; } diff --git a/src/main/resources/api-definition/hs-office/hs-office-debitor-schemas.yaml b/src/main/resources/api-definition/hs-office/hs-office-debitor-schemas.yaml index c868a459..9b115889 100644 --- a/src/main/resources/api-definition/hs-office/hs-office-debitor-schemas.yaml +++ b/src/main/resources/api-definition/hs-office/hs-office-debitor-schemas.yaml @@ -90,6 +90,7 @@ components: type: boolean vatReverseCharge: type: boolean + # TODO.feat: alternatively the complete refundBankAccount refundBankAccount.uuid: type: string format: uuid diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactControllerAcceptanceTest.java index a4b19eef..48d12f44 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactControllerAcceptanceTest.java @@ -374,7 +374,6 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu return jpaAttempt.transacted(() -> { context.define(creatingUser); final var newContact = HsOfficeContactRbacEntity.builder() - .uuid(UUID.randomUUID()) .caption("Temp from " + Context.getCallerMethodNameFromStackFrame(1) ) .postalAddress(Map.ofEntries( entry("name", RandomStringUtils.randomAlphabetic(6) + " " + RandomStringUtils.randomAlphabetic(10)), diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerAcceptanceTest.java index 5568fa2f..55411a10 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerAcceptanceTest.java @@ -197,7 +197,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased @Test void globalAdmin_canAddCoopSharesReversalTransaction() { - context.define("superuser-alex@hostsharing.net"); + context.define("superuser-alex@hostsharing.net", "global#global:ADMIN"); final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101).orElseThrow(); final var givenTransaction = jpaAttempt.transacted(() -> { // TODO.impl: introduce something like transactedAsSuperuser / transactedAs("...", ...) @@ -214,46 +214,46 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased final var location = RestAssured // @formatter:off .given() - .header("current-subject", "superuser-alex@hostsharing.net") - .contentType(ContentType.JSON) - .body(""" - { - "membership.uuid": "%s", - "transactionType": "REVERSAL", - "shareCount": %s, - "valueDate": "2022-10-30", - "reference": "test reversal ref", - "comment": "some coop shares reversal transaction", - "revertedShareTx.uuid": "%s" - } - """.formatted( - givenMembership.getUuid(), - -givenTransaction.getShareCount(), - givenTransaction.getUuid())) - .port(port) + .header("current-subject", "superuser-alex@hostsharing.net") + .contentType(ContentType.JSON) + .body(""" + { + "membership.uuid": "%s", + "transactionType": "REVERSAL", + "shareCount": %s, + "valueDate": "2022-10-30", + "reference": "test reversal ref", + "comment": "some coop shares reversal transaction", + "revertedShareTx.uuid": "%s" + } + """.formatted( + givenMembership.getUuid(), + -givenTransaction.getShareCount(), + givenTransaction.getUuid())) + .port(port) .when() - .post("http://localhost/api/hs/office/coopsharestransactions") + .post("http://localhost/api/hs/office/coopsharestransactions") .then().log().all().assertThat() - .statusCode(201) - .contentType(ContentType.JSON) - .body("uuid", isUuidValid()) - .body("", lenientlyEquals(""" - { - "transactionType": "REVERSAL", - "shareCount": -13, - "valueDate": "2022-10-30", - "reference": "test reversal ref", - "comment": "some coop shares reversal transaction", - "revertedShareTx": { - "transactionType": "SUBSCRIPTION", - "shareCount": 13, - "valueDate": "2022-10-20", - "reference": "test ref" - } + .statusCode(201) + .contentType(ContentType.JSON) + .body("uuid", isUuidValid()) + .body("", lenientlyEquals(""" + { + "transactionType": "REVERSAL", + "shareCount": -13, + "valueDate": "2022-10-30", + "reference": "test reversal ref", + "comment": "some coop shares reversal transaction", + "revertedShareTx": { + "transactionType": "SUBSCRIPTION", + "shareCount": 13, + "valueDate": "2022-10-20", + "reference": "test ref" } - """)) - .header("Location", startsWith("http://localhost")) - .extract().header("Location"); // @formatter:on + } + """)) + .header("Location", startsWith("http://localhost")) + .extract().header("Location"); // @formatter:on // finally, the new coopAssetsTransaction can be accessed under the generated UUID final var newShareTxUuid = UUID.fromString( @@ -269,22 +269,34 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101).orElseThrow(); RestAssured // @formatter:off - .given().header("current-subject", "superuser-alex@hostsharing.net").contentType(ContentType.JSON).body(""" - { - "membership.uuid": "%s", - "transactionType": "CANCELLATION", - "shareCount": -80, - "valueDate": "2022-10-13", - "reference": "temp ref X", - "comment": "just some test coop shares transaction" - } - """.formatted(givenMembership.getUuid())).port(port).when().post("http://localhost/api/hs/office/coopsharestransactions").then().log().all().assertThat().statusCode(400).contentType(ContentType.JSON).body("", lenientlyEquals(""" + .given() + .header("current-subject", "superuser-alex@hostsharing.net") + .contentType(ContentType.JSON) + .body(""" { - "statusCode": 400, - "statusPhrase": "Bad Request", - "message": "ERROR: [400] coop shares transaction would result in a negative number of shares" - } - """)); // @formatter:on + "membership.uuid": "%s", + "transactionType": "CANCELLATION", + "shareCount": -80, + "valueDate": "2022-10-13", + "reference": "temp ref X", + "comment": "just some test coop shares transaction" + } + """.formatted(givenMembership.getUuid())) + .port(port) + .when() + .post("http://localhost/api/hs/office/coopsharestransactions") + .then() + .log().all() + .assertThat() + .statusCode(400) + .contentType(ContentType.JSON) + .body("", lenientlyEquals(""" + { + "statusCode": 400, + "statusPhrase": "Bad Request", + "message": "ERROR: [400] coop shares transaction would result in a negative number of shares" + } + """)); // @formatter:on } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerRestTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerRestTest.java index 5bc432de..f6ed87ed 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerRestTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerRestTest.java @@ -1,7 +1,7 @@ package net.hostsharing.hsadminng.hs.office.coopshares; import net.hostsharing.hsadminng.context.Context; -import net.hostsharing.hsadminng.mapper.StandardMapper; +import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.rbac.test.JsonBuilder; import net.hostsharing.hsadminng.config.DisableSecurityConfig; import org.junit.jupiter.params.ParameterizedTest; @@ -36,7 +36,7 @@ class HsOfficeCoopSharesTransactionControllerRestTest { @MockBean @SuppressWarnings("unused") // not used in test, but in controller class - StandardMapper mapper; + StrictMapper mapper; @MockBean HsOfficeCoopSharesTransactionRepository coopSharesTransactionRepo; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerAcceptanceTest.java index 88f29868..3c67b2cd 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerAcceptanceTest.java @@ -430,7 +430,6 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle context.define("superuser-alex@hostsharing.net"); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike(partnerName).get(0); final var newMembership = HsOfficeMembershipEntity.builder() - .uuid(UUID.randomUUID()) .partner(givenPartner) .memberNumberSuffix(TEMP_MEMBER_NUMBER_SUFFIX) .validity(Range.closedInfinite(LocalDate.parse("2022-11-01"))) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityPatcherUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityPatcherUnitTest.java index f6ab56fa..e5ffccfe 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityPatcherUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityPatcherUnitTest.java @@ -4,7 +4,7 @@ import io.hypersistence.utils.hibernate.type.range.Range; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipStatusResource; -import net.hostsharing.hsadminng.mapper.StandardMapper; +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; @@ -40,7 +40,7 @@ class HsOfficeMembershipEntityPatcherUnitTest extends PatchUnitTestBase< @Mock private EntityManagerWrapper em; - private StandardMapper mapper = new StandardMapper(em); + private StrictMapper mapper = new StrictMapper(em); @BeforeEach void initMocks() { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java index c8a709a1..1ce4df3d 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java @@ -16,7 +16,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.MockBean; // FIXME: use MockitoBean import org.springframework.context.annotation.Import; import org.springframework.orm.jpa.JpaSystemException; @@ -32,6 +32,7 @@ import static net.hostsharing.hsadminng.rbac.role.RawRbacObjectEntity.objectDisp import static net.hostsharing.hsadminng.rbac.role.RawRbacRoleEntity.distinctRoleNamesOf; import static net.hostsharing.hsadminng.mapper.Array.from; import static net.hostsharing.hsadminng.rbac.role.RbacRoleType.ADMIN; +import static net.hostsharing.hsadminng.rbac.role.RbacRoleType.AGENT; import static net.hostsharing.hsadminng.rbac.test.JpaAttempt.attempt; import static org.assertj.core.api.Assertions.assertThat; @@ -207,9 +208,23 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean } @Test - public void normalUser_canViewOnlyRelatedPartners() { + public void partnerAgent_canViewOnlyRelatedPartnersWithoutDetails() { // given: - context("person-FirstGmbH@example.com"); + context("person-FirstGmbH@example.com", + "hs_office.relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT"); + + // when: + final var result = partnerRepo.findPartnerByOptionalNameLike(null); + + // then: + exactlyThesePartnersAreReturned(result, "partner(P-10001: LP First GmbH, first contact)"); + } + + @Test + public void partnerTenant_canViewRelatedPartnersButWithoutDetails() { + // given: + context("person-FirstGmbH@example.com", + "hs_office.relation#HostsharingeG-with-PARTNER-FirstGmbH:TENANT"); // when: final var result = partnerRepo.findPartnerByOptionalNameLike(null); @@ -289,19 +304,19 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean } @Test - public void partnerRelationAgent_canUpdateRelatedPartner() { + public void partnerRelationAgent_canUpdateRelatedPartnerDetails() { // given context("superuser-alex@hostsharing.net"); final var givenPartner = givenSomeTemporaryHostsharingPartner(20037, "Erben Bessler", "ninth"); assertThatPartnerIsVisibleForUserWithRole( givenPartner, - "hs_office.person#ErbenBesslerMelBessler:ADMIN"); + givenPartner.getPartnerRel().roleId(AGENT)); assertThatPartnerActuallyInDatabase(givenPartner); // when final var result = jpaAttempt.transacted(() -> { context("superuser-alex@hostsharing.net", - "hs_office.person#ErbenBesslerMelBessler:ADMIN"); + givenPartner.getPartnerRel().roleId(AGENT)); givenPartner.getDetails().setBirthName("new birthname"); return partnerRepo.save(givenPartner); }); @@ -310,30 +325,6 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean result.assertSuccessful(); } - @Test - public void partnerRelationTenant_canNotUpdateRelatedPartner() { - // given - context("superuser-alex@hostsharing.net"); - final var givenPartner = givenSomeTemporaryHostsharingPartner(20037, "Erben Bessler", "ninth"); - assertThatPartnerIsVisibleForUserWithRole( - givenPartner, - "hs_office.person#ErbenBesslerMelBessler:ADMIN"); - assertThatPartnerActuallyInDatabase(givenPartner); - - // when - final var result = jpaAttempt.transacted(() -> { - context("superuser-alex@hostsharing.net", - "hs_office.relation#HostsharingeG-with-PARTNER-ErbenBesslerMelBessler:TENANT"); - givenPartner.getDetails().setBirthName("new birthname"); - return partnerRepo.save(givenPartner); - }); - - // then - result.assertExceptionWithRootCauseMessage(JpaSystemException.class, - "ERROR: [403] insert into hs_office.partner_details ", - " not allowed for current subjects {hs_office.relation#HostsharingeG-with-PARTNER-ErbenBesslerMelBessler:TENANT}"); - } - private void assertThatPartnerActuallyInDatabase(final HsOfficePartnerEntity saved) { final var found = partnerRepo.findByUuid(saved.getUuid()); assertThat(found).isNotEmpty().get().isNotSameAs(saved).extracting(HsOfficePartnerEntity::toString).isEqualTo(saved.toString()); @@ -463,7 +454,10 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean .details(HsOfficePartnerDetailsEntity.builder().build()) .build(); - return partnerRepo.save(newPartner); + final var savedPartner = partnerRepo.save(newPartner); + em.flush(); + final var partner = em.find(savedPartner.getClass(), savedPartner.getUuid()); + return savedPartner; }).assertSuccessful().returnedValue(); } @@ -484,13 +478,13 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean void exactlyThesePartnersAreReturned(final List actualResult, final String... partnerNames) { assertThat(actualResult) - .extracting(partnerEntity -> partnerEntity.toString()) + .extracting(HsOfficePartnerEntity::toString) .containsExactlyInAnyOrder(partnerNames); } void allThesePartnersAreReturned(final List actualResult, final String... partnerNames) { assertThat(actualResult) - .extracting(partnerEntity -> partnerEntity.toString()) + .extracting(HsOfficePartnerEntity::toString) .contains(partnerNames); } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonControllerAcceptanceTest.java index b0cae150..a2c21dac 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonControllerAcceptanceTest.java @@ -331,7 +331,6 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup return jpaAttempt.transacted(() -> { context.define(creatingUser); final var newPerson = HsOfficePersonRealEntity.builder() - .uuid(UUID.randomUUID()) .personType(HsOfficePersonType.LEGAL_PERSON) .tradeName("Temp " + Context.getCallerMethodNameFromStackFrame(2)) .familyName(RandomStringUtils.randomAlphabetic(10) + "@example.org") diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateControllerAcceptanceTest.java index eabde5a7..b8876423 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateControllerAcceptanceTest.java @@ -180,10 +180,9 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl void globalAdmin_canNotPostNewSepaMandateWhenDebitorUuidIsMissing() { context.define("superuser-alex@hostsharing.net"); - final var givenDebitor = debitorRepo.findDebitorsByOptionalNameLike("Third").get(0); final var givenBankAccount = bankAccountRepo.findByIbanOrderByIbanAsc("DE02200505501015871393").get(0); - final var location = RestAssured // @formatter:off + RestAssured // @formatter:off .given() .header("current-subject", "superuser-alex@hostsharing.net") .contentType(ContentType.JSON) @@ -227,12 +226,12 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl .post("http://localhost/api/hs/office/sepamandates") .then().log().all().assertThat() .statusCode(400) - .body("message", is("ERROR: [400] Unable to find BankAccount with uuid 00000000-0000-0000-0000-000000000000")); + .body("message", is("ERROR: [400] bankAccount.uuid='00000000-0000-0000-0000-000000000000' not found or not accessible")); // @formatter:on } @Test - void globalAdmin_canNotPostNewSepaMandate_ifPersonDoesNotExist() { + void globalAdmin_canNotPostNewSepaMandate_ifDebitorDoesNotExist() { context.define("superuser-alex@hostsharing.net"); final var givenDebitorUuid = UUID.fromString("00000000-0000-0000-0000-000000000000"); @@ -257,7 +256,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl .post("http://localhost/api/hs/office/sepamandates") .then().log().all().assertThat() .statusCode(400) - .body("message", is("ERROR: [400] Unable to find Debitor with uuid 00000000-0000-0000-0000-000000000000")); + .body("message", is("ERROR: [400] debitor.uuid='00000000-0000-0000-0000-000000000000' not found or not accessible")); // @formatter:on } } @@ -529,7 +528,6 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl .orElse(givenDebitor.getPartner().getPartnerRel().getHolder().getFamilyName()); final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike(bankAccountHolder).get(0); final var newSepaMandate = HsOfficeSepaMandateEntity.builder() - .uuid(UUID.randomUUID()) .debitor(givenDebitor) .bankAccount(givenBankAccount) .reference("temp ref CAT Z") diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 954bdd63..344828e7 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -6,7 +6,7 @@ management: endpoints: web: exposure: - include: info, health, metrics, metric-links + include: info, health, metrics, metric-links, mappings, openapi, swaggerui spring: sql: