1
0

http-get endpoints for partner, debitor and memberhip-number (#135)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/135
Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
Michael Hoennig
2024-12-11 11:35:51 +01:00
parent c7b17ee546
commit 19fac6b5e1
39 changed files with 672 additions and 171 deletions
@@ -0,0 +1,23 @@
package net.hostsharing.hsadminng.errors;
import lombok.AllArgsConstructor;
import jakarta.validation.ValidationException;
@AllArgsConstructor
public class Validate {
final String variableNames;
public static Validate validate(final String variableNames) {
return new Validate(variableNames);
}
public final void atMaxOneNonNull(final Object var1, final Object var2) {
if (var1 != null && var2 != null) {
throw new ValidationException(
"Exactly one of (" + variableNames + ") must be non-null, " +
"but are (" + var1 + ", " + var2 + ")");
}
}
}
@@ -290,11 +290,10 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse
if (adoptingMembershipMemberNumber != null) {
final var adoptingMemberNumber = Integer.valueOf(adoptingMembershipMemberNumber.substring("M-".length()));
final var adoptingMembership = membershipRepo.findMembershipByMemberNumber(adoptingMemberNumber);
if (adoptingMembership != null) {
return adoptingMembership;
}
throw new ValidationException("adoptingMembership.memberNumber='" + adoptingMembershipMemberNumber
+ "' not found or not accessible");
return adoptingMembership.orElseThrow( () ->
new ValidationException("adoptingMembership.memberNumber='" + adoptingMembershipMemberNumber
+ "' not found or not accessible")
);
}
throw new ValidationException(
@@ -57,12 +57,15 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
final String currentSubject,
final String assumedRoles,
final String name,
final String debitorNumber) {
final UUID partnerUuid,
final String partnerNumber) {
context.define(currentSubject, assumedRoles);
final var entities = debitorNumber != null
? debitorRepo.findDebitorByDebitorNumber(cropTag("D-", debitorNumber))
: debitorRepo.findDebitorByOptionalNameLike(name);
final var entities = partnerNumber != null
? debitorRepo.findDebitorsByPartnerNumber(cropTag("P-", partnerNumber))
: partnerUuid != null
? debitorRepo.findDebitorsByPartnerUuid(partnerUuid)
: debitorRepo.findDebitorsByOptionalNameLike(name);
final var resources = mapper.mapList(entities, HsOfficeDebitorResource.class, ENTITY_TO_RESOURCE_POSTMAPPER);
return ResponseEntity.ok(resources);
@@ -133,6 +136,23 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
return ResponseEntity.ok(mapper.map(result.get(), HsOfficeDebitorResource.class, ENTITY_TO_RESOURCE_POSTMAPPER));
}
@Override
@Transactional(readOnly = true)
@Timed("app.office.debitors.api.getSingleDebitorByDebitorNumber")
public ResponseEntity<HsOfficeDebitorResource> getSingleDebitorByDebitorNumber(
final String currentSubject,
final String assumedRoles,
final Integer debitorNumber) {
context.define(currentSubject, assumedRoles);
final var result = debitorRepo.findDebitorByDebitorNumber(debitorNumber);
if (result.isEmpty()) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(mapper.map(result.get(), HsOfficeDebitorResource.class, ENTITY_TO_RESOURCE_POSTMAPPER));
}
@Override
@Transactional
@Timed("app.office.debitors.api.deleteDebitorByUuid")
@@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.hs.office.debitor;
import io.micrometer.core.annotation.Timed;
import net.hostsharing.hsadminng.lambda.Reducer;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
@@ -13,21 +14,29 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt
@Timed("app.office.debitors.repo.findByUuid")
Optional<HsOfficeDebitorEntity> findByUuid(UUID id);
@Timed("app.office.debitors.repo.findDebitorByPartnerUuid")
List<HsOfficeDebitorEntity> findDebitorsByPartnerUuid(UUID partnerUuid);
@Query("""
SELECT debitor FROM HsOfficeDebitorEntity debitor
JOIN HsOfficePartnerEntity partner
ON partner.partnerRel.holder = debitor.debitorRel.anchor
AND partner.partnerRel.type = 'PARTNER' AND debitor.debitorRel.type = 'DEBITOR'
WHERE partner.partnerNumber = :partnerNumber
AND debitor.debitorNumberSuffix = :debitorNumberSuffix
AND (:debitorNumberSuffix IS NULL OR debitor.debitorNumberSuffix = :debitorNumberSuffix)
""")
@Timed("app.office.debitors.repo.findDebitorByPartnerNumberAndDebitorNumberSuffix")
List<HsOfficeDebitorEntity> findDebitorByPartnerNumberAndDebitorNumberSuffix(int partnerNumber, String debitorNumberSuffix);
List<HsOfficeDebitorEntity> findDebitorByPartnerNumberAndOptionalDebitorNumberSuffix(int partnerNumber, String debitorNumberSuffix);
default List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int debitorNumber) {
default Optional<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int debitorNumber) {
final var partnerNumber = debitorNumber / 100;
final String suffix = String.format("%02d", debitorNumber % 100);
final var result = findDebitorByPartnerNumberAndDebitorNumberSuffix(partnerNumber, suffix);
final var result = findDebitorByPartnerNumberAndOptionalDebitorNumberSuffix(partnerNumber, suffix);
return result.stream().reduce(Reducer::toSingleElement);
}
default List<HsOfficeDebitorEntity> findDebitorsByPartnerNumber(int partnerNumber) {
final var result = findDebitorByPartnerNumberAndOptionalDebitorNumberSuffix(partnerNumber, null);
return result;
}
@@ -50,7 +59,7 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt
OR contact.caption like concat(cast(:name as text), '%')
""")
@Timed("app.office.debitors.repo.findDebitorByOptionalNameLike")
List<HsOfficeDebitorEntity> findDebitorByOptionalNameLike(String name);
List<HsOfficeDebitorEntity> findDebitorsByOptionalNameLike(String name);
@Timed("app.office.debitors.repo.save")
HsOfficeDebitorEntity save(final HsOfficeDebitorEntity entity);
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeMembersh
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipInsertResource;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
@@ -17,7 +18,7 @@ import java.util.List;
import java.util.UUID;
import java.util.function.BiConsumer;
import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.errors.Validate.validate;
import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
@RestController
@@ -39,16 +40,20 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
final String currentSubject,
final String assumedRoles,
final UUID partnerUuid,
final String memberNumber) {
final String partnerNumber) {
context.define(currentSubject, assumedRoles);
final var entities = (memberNumber != null)
? ofNullable(membershipRepo.findMembershipByMemberNumber(
cropTag(HsOfficeMembershipEntity.MEMBER_NUMBER_TAG, memberNumber))).stream()
.toList()
: membershipRepo.findMembershipsByOptionalPartnerUuid(partnerUuid);
validate("partnerUuid, partnerNumber").atMaxOneNonNull(partnerUuid, partnerNumber);
final var resources = mapper.mapList(entities, HsOfficeMembershipResource.class,
final var entities = partnerNumber != null
? membershipRepo.findMembershipsByPartnerNumber(
cropTag(HsOfficePartnerEntity.PARTNER_NUMBER_TAG, partnerNumber))
: partnerUuid != null
? membershipRepo.findMembershipsByPartnerUuid(partnerUuid)
: membershipRepo.findAll();
final var resources = mapper.mapList(
entities, HsOfficeMembershipResource.class,
SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER);
return ResponseEntity.ok(resources);
}
@@ -72,7 +77,8 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
.path("/api/hs/office/memberships/{id}")
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficeMembershipResource.class,
final var mapped = mapper.map(
saved, HsOfficeMembershipResource.class,
SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER);
return ResponseEntity.created(uri).body(mapped);
}
@@ -91,7 +97,27 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
if (result.isEmpty()) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(mapper.map(result.get(), HsOfficeMembershipResource.class,
return ResponseEntity.ok(mapper.map(
result.get(), HsOfficeMembershipResource.class,
SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER));
}
@Override
@Transactional(readOnly = true)
@Timed("app.office.membership.api.getSingleMembershipByMembershipNumber")
public ResponseEntity<HsOfficeMembershipResource> getSingleMembershipByMembershipNumber(
final String currentSubject,
final String assumedRoles,
final Integer membershipNumber) {
context.define(currentSubject, assumedRoles);
final var result = membershipRepo.findMembershipByMemberNumber(membershipNumber);
if (result.isEmpty()) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(mapper.map(
result.get(), HsOfficeMembershipResource.class,
SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER));
}
@@ -22,12 +22,19 @@ public interface HsOfficeMembershipRepository extends Repository<HsOfficeMembers
@Query("""
SELECT membership FROM HsOfficeMembershipEntity membership
WHERE ( CAST(:partnerUuid as org.hibernate.type.UUIDCharType) IS NULL
OR membership.partner.uuid = :partnerUuid )
WHERE membership.partner.uuid = :partnerUuid
ORDER BY membership.partner.partnerNumber, membership.memberNumberSuffix
""")
@Timed("app.office.membership.repo.findMembershipsByOptionalPartnerUuid")
List<HsOfficeMembershipEntity> findMembershipsByOptionalPartnerUuid(UUID partnerUuid);
List<HsOfficeMembershipEntity> findMembershipsByPartnerUuid(UUID partnerUuid);
@Query("""
SELECT membership FROM HsOfficeMembershipEntity membership
WHERE membership.partner.partnerNumber = :partnerNumber
ORDER BY membership.partner.partnerNumber, membership.memberNumberSuffix
""")
@Timed("app.office.membership.repo.findMembershipsByPartnerNumber")
List<HsOfficeMembershipEntity> findMembershipsByPartnerNumber(Integer partnerNumber);
@Query("""
SELECT membership FROM HsOfficeMembershipEntity membership
@@ -35,12 +42,12 @@ public interface HsOfficeMembershipRepository extends Repository<HsOfficeMembers
AND (membership.memberNumberSuffix = :suffix)
ORDER BY membership.memberNumberSuffix
""")
@Timed("app.office.membership.repo.findMembershipByPartnerNumberAndSuffix")
HsOfficeMembershipEntity findMembershipByPartnerNumberAndSuffix(
@Timed("app.office.membership.repo.findMembershipByMemberNumber")
Optional<HsOfficeMembershipEntity> findMembershipByPartnerNumberAndSuffix(
@NotNull Integer partnerNumber,
@NotNull String suffix);
default HsOfficeMembershipEntity findMembershipByMemberNumber(Integer memberNumber) {
default Optional<HsOfficeMembershipEntity> findMembershipByMemberNumber(final Integer memberNumber) {
final var partnerNumber = memberNumber / 100;
final String suffix = String.format("%02d", memberNumber % 100);
final var result = findMembershipByPartnerNumberAndSuffix(partnerNumber, suffix);
@@ -104,6 +104,23 @@ public class HsOfficePartnerController implements HsOfficePartnersApi {
return ResponseEntity.ok(mapper.map(result.get(), HsOfficePartnerResource.class));
}
@Override
@Transactional(readOnly = true)
@Timed("app.office.partners.api.getSinglePartnerByPartnerNumber")
public ResponseEntity<HsOfficePartnerResource> getSinglePartnerByPartnerNumber(
final String currentSubject,
final String assumedRoles,
final Integer partnerNumber) {
context.define(currentSubject, assumedRoles);
final var result = partnerRepo.findPartnerByPartnerNumber(partnerNumber);
if (result.isEmpty()) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(mapper.map(result.get(), HsOfficePartnerResource.class));
}
@Override
@Transactional
@Timed("app.office.partners.api.deletePartnerByUuid")
@@ -32,7 +32,7 @@ public interface HsOfficePartnerRepository extends Repository<HsOfficePartnerEnt
List<HsOfficePartnerEntity> findPartnerByOptionalNameLike(String name);
@Timed("app.office.partners.repo.findPartnerByPartnerNumber")
HsOfficePartnerEntity findPartnerByPartnerNumber(Integer partnerNumber);
Optional<HsOfficePartnerEntity> findPartnerByPartnerNumber(Integer partnerNumber);
@Timed("app.office.partners.repo.save")
HsOfficePartnerEntity save(final HsOfficePartnerEntity entity);