From 51f406c84ebdf667726c8a977877847b5fabdbae Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Wed, 24 Jan 2024 12:45:52 +0100 Subject: [PATCH] combined memberNumber (partnerNumber+memberNumberSuffix) --- .aliases | 1 + .../HsOfficeCoopAssetsTransactionEntity.java | 1 - .../office/debitor/HsOfficeDebitorEntity.java | 19 +- .../HsOfficeMembershipController.java | 4 +- .../membership/HsOfficeMembershipEntity.java | 23 +- .../HsOfficeMembershipRepository.java | 6 +- .../partner/HsOfficePartnerRepository.java | 1 + .../hs-office-membership-schemas.yaml | 15 +- .../hs-office/hs-office-memberships.yaml | 9 +- ...tsTransactionControllerAcceptanceTest.java | 12 +- ...sTransactionRepositoryIntegrationTest.java | 10 +- ...esTransactionControllerAcceptanceTest.java | 8 +- ...sTransactionRepositoryIntegrationTest.java | 46 ++- .../HsOfficeDebitorEntityUnitTest.java | 60 +++- ...fficeDebitorRepositoryIntegrationTest.java | 14 +- ...iceMembershipControllerAcceptanceTest.java | 108 +++++-- .../HsOfficeMembershipControllerRestTest.java | 273 +++++++++++------- .../HsOfficeMembershipEntityUnitTest.java | 39 ++- ...ceMembershipRepositoryIntegrationTest.java | 16 +- ...fficePartnerRepositoryIntegrationTest.java | 19 ++ .../HsOfficeRelationshipEntityUnitTest.java | 32 ++ ...ceSepaMandateControllerAcceptanceTest.java | 4 +- 22 files changed, 482 insertions(+), 238 deletions(-) create mode 100644 src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntityUnitTest.java diff --git a/.aliases b/.aliases index c0b4e22d..f6673bcd 100644 --- a/.aliases +++ b/.aliases @@ -80,3 +80,4 @@ alias fp='grep -r '@Accepts' src | sed -e 's/^.*@/@/g' | sort -u | wc -l' alias gw-spotless='./gradlew spotlessApply -x pitest -x test -x :processResources' alias gw-test='. .aliases; ./gradlew test' +alias gw-check='. .aliases; gw check -x pitest -x :dependencyCheckAnalyze' diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java index 02c72e17..f0b91c07 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java @@ -11,7 +11,6 @@ import org.hibernate.annotations.GenericGenerator; import jakarta.persistence.*; import java.math.BigDecimal; -import java.text.DecimalFormat; import java.time.LocalDate; import java.util.UUID; diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntity.java index 74787b0d..279f1d63 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntity.java @@ -26,12 +26,14 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify; @DisplayName("Debitor") public class HsOfficeDebitorEntity implements HasUuid, Stringifyable { + public static final String DEBITOR_NUMBER_TAG = "D-"; + // TODO: I would rather like to generate something matching this example: // debitor(1234500: Test AG, tes) // maybe remove withSepararator (always use ', ') and add withBusinessIdProp (with ': ' afterwards)? private static Stringify stringify = stringify(HsOfficeDebitorEntity.class, "debitor") - .withProp(HsOfficeDebitorEntity::getDebitorNumber) + .withProp(e -> DEBITOR_NUMBER_TAG + e.getDebitorNumber()) .withProp(HsOfficeDebitorEntity::getPartner) .withProp(HsOfficeDebitorEntity::getDefaultPrefix) .withSeparator(": ") @@ -75,16 +77,9 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable { @Column(name = "defaultprefix", columnDefinition = "char(3) not null") private String defaultPrefix; - public String getDebitorNumberString() { - // TODO: refactor - if (partner.getPartnerNumber() == null ) { - if (debitorNumberSuffix == null) { - return null; - } - return String.format("%02d", debitorNumberSuffix); - } - if (debitorNumberSuffix == null) { - return partner.getPartnerNumber() + "??"; + private String getDebitorNumberString() { + if (partner == null || partner.getPartnerNumber() == null || debitorNumberSuffix == null ) { + return null; } return partner.getPartnerNumber() + String.format("%02d", debitorNumberSuffix); } @@ -100,6 +95,6 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable { @Override public String toShortString() { - return getDebitorNumberString(); + return DEBITOR_NUMBER_TAG + getDebitorNumberString(); } } 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 a375ffa4..e18fc183 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 @@ -44,7 +44,9 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi { Integer memberNumber) { context.define(currentUser, assumedRoles); - final var entities = membershipRepo.findMembershipsByOptionalPartnerUuid(partnerUuid); + final var entities = ( memberNumber != null) + ? List.of(membershipRepo.findMembershipByMemberNumber(memberNumber)) + : membershipRepo.findMembershipsByOptionalPartnerUuid(partnerUuid); final var resources = mapper.mapList(entities, HsOfficeMembershipResource.class, SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java index 703adc57..25bb412a 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java @@ -34,7 +34,7 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable { public static final String MEMBER_NUMBER_TAG = "M-"; private static Stringify stringify = stringify(HsOfficeMembershipEntity.class) - .withProp(HsOfficeMembershipEntity::getMemberNumberString) + .withProp(e -> MEMBER_NUMBER_TAG + e.getMemberNumber()) .withProp(e -> e.getPartner().toShortString()) .withProp(e -> e.getMainDebitor().toShortString()) .withProp(e -> e.getValidity().asString()) @@ -91,25 +91,12 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable { } return validity; } - - public String getMemberNumberString() { - return MEMBER_NUMBER_TAG + getMemberNumber(); - } - public Integer getMemberNumber() { - // TODO: refactor - String combinedMemberNumber; - if (partner.getPartnerNumber() == null ) { - if (memberNumberSuffix == null) { - combinedMemberNumber = null; - } else {combinedMemberNumber = MEMBER_NUMBER_TAG + memberNumberSuffix;} - } else if (memberNumberSuffix == null) { - combinedMemberNumber = partner.getPartnerNumber() + "??"; - } else { - combinedMemberNumber = partner.getPartnerNumber() + memberNumberSuffix; + if (partner == null || partner.getPartnerNumber() == null || memberNumberSuffix == null ) { + return null; } - return Optional.ofNullable(combinedMemberNumber).map(Integer::parseInt).orElse(null); + return getPartner().getPartnerNumber() * 100 + Integer.parseInt(memberNumberSuffix, 10); } @Override @@ -119,7 +106,7 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable { @Override public String toShortString() { - return "M-" + partner.getPartnerNumber() + String.valueOf(memberNumberSuffix); + return "M-" + getMemberNumber(); } @PrePersist diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepository.java index 6de92ee8..c61a863e 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepository.java @@ -28,13 +28,13 @@ public interface HsOfficeMembershipRepository extends Repository findMembershipsByPartnerNumberAndSuffix( + HsOfficeMembershipEntity findMembershipByPartnerNumberAndSuffix( @NotNull Integer partnerNumber, @NotNull String suffix); - default List findMembershipsByMemberNumber(Integer memberNumber) { + default HsOfficeMembershipEntity findMembershipByMemberNumber(Integer memberNumber) { final var partnerNumber = memberNumber / 100; final var suffix = memberNumber % 100; - return findMembershipsByPartnerNumberAndSuffix(partnerNumber, String.format("%02d", suffix)); + return findMembershipByPartnerNumberAndSuffix(partnerNumber, String.format("%02d", suffix)); } long count(); 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 6c7a158c..dfbd1667 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 @@ -23,6 +23,7 @@ public interface HsOfficePartnerRepository extends Repository findPartnerByOptionalNameLike(String name); + HsOfficePartnerEntity findPartnerByPartnerNumber(Integer partnerNumber); HsOfficePartnerEntity save(final HsOfficePartnerEntity entity); diff --git a/src/main/resources/api-definition/hs-office/hs-office-membership-schemas.yaml b/src/main/resources/api-definition/hs-office/hs-office-membership-schemas.yaml index 855988b0..163f6f34 100644 --- a/src/main/resources/api-definition/hs-office/hs-office-membership-schemas.yaml +++ b/src/main/resources/api-definition/hs-office/hs-office-membership-schemas.yaml @@ -23,8 +23,15 @@ components: $ref: './hs-office-partner-schemas.yaml#/components/schemas/HsOfficePartner' mainDebitor: $ref: './hs-office-debitor-schemas.yaml#/components/schemas/HsOfficeDebitor' - memberNumberSuffix: + memberNumber: type: integer + minimum: 1000000 + maximum: 9999999 + memberNumberSuffix: + type: string + minLength: 2 + maxLength: 2 + pattern: '[0-9]+' validFrom: type: string format: date @@ -67,7 +74,10 @@ components: format: uuid nullable: false memberNumberSuffix: - type: integer + type: string + minLength: 2 + maxLength: 2 + pattern: '[0-9]+' nullable: false validFrom: type: string @@ -84,6 +94,7 @@ components: type: boolean required: - partnerUuid + - memberNumberSuffix - mainDebitorUuid - validFrom - membershipFeeBillable diff --git a/src/main/resources/api-definition/hs-office/hs-office-memberships.yaml b/src/main/resources/api-definition/hs-office/hs-office-memberships.yaml index c18ba861..3833752b 100644 --- a/src/main/resources/api-definition/hs-office/hs-office-memberships.yaml +++ b/src/main/resources/api-definition/hs-office/hs-office-memberships.yaml @@ -1,6 +1,7 @@ get: summary: Returns a list of (optionally filtered) memberships. - description: Returns the list of (optionally filtered) memberships which are visible to the current user or any of it's assumed roles. + description: Returns the list of memberships which are visible to the current user or any of it's assumed roles. + The list can optionally be filtered by either the `partnerUuid` or the `memberNumber` - not both at the same time. tags: - hs-office-memberships operationId: listMemberships @@ -13,13 +14,13 @@ get: schema: type: string format: uuid - description: UUID of the business partner. - - name: memberNumberSuffix + description: UUID of the business partner, exclusive to `memberNumber`. + - name: memberNumber in: query required: false schema: type: integer - description: Member number. + description: Member number, exclusive to `partnerUuid`. responses: "200": description: OK diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionControllerAcceptanceTest.java index a7052a2e..4c17f8e1 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionControllerAcceptanceTest.java @@ -75,8 +75,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest { void globalAdmin_canFindCoopAssetsTransactionsByMemberNumberSuffix() { context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000202) - .get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202); RestAssured // @formatter:off .given() @@ -118,8 +117,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest { void globalAdmin_canFindCoopAssetsTransactionsByMemberNumberSuffixAndDateRange() { context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000202) - .get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202); RestAssured // @formatter:off .given() @@ -153,8 +151,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest { void globalAdmin_canAddCoopAssetsTransaction() { context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000101) - .get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101); final var location = RestAssured // @formatter:off .given() @@ -199,8 +196,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest { void globalAdmin_canNotCancelMoreAssetsThanCurrentlySubscribed() { context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000101) - .get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101); final var location = RestAssured // @formatter:off .given() diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepositoryIntegrationTest.java index dfba6b7a..89f48402 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepositoryIntegrationTest.java @@ -62,8 +62,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase // given context("superuser-alex@hostsharing.net"); final var count = coopAssetsTransactionRepo.count(); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000101) - .get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101); // when final var result = attempt(em, () -> { @@ -96,7 +95,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase // when attempt(em, () -> { - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000101).get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101); final var newCoopAssetsTransaction = HsOfficeCoopAssetsTransactionEntity.builder() .membership(givenMembership) .transactionType(HsOfficeCoopAssetsTransactionType.DEPOSIT) @@ -159,7 +158,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase public void globalAdmin_canViewCoopAssetsTransactions_filteredByMembershipUuid() { // given context("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(null).get(1000202); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202); // when final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange( @@ -179,8 +178,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase public void globalAdmin_canViewCoopAssetsTransactions_filteredByMembershipUuidAndValueDateRange() { // given context("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000202) - .get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202); // when final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange( 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 ebb7ca59..58469681 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 @@ -75,7 +75,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest { void globalAdmin_canFindCoopSharesTransactionsByMemberNumberSuffix() { context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000202).get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202); RestAssured // @formatter:off .given().header("current-user", "superuser-alex@hostsharing.net").port(port).when().get("http://localhost/api/hs/office/coopsharestransactions?membershipUuid=" + givenMembership.getUuid()).then().log().all().assertThat().statusCode(200).contentType("application/json").body("", lenientlyEquals(""" @@ -109,7 +109,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest { void globalAdmin_canFindCoopSharesTransactionsByMemberNumberSuffixAndDateRange() { context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000202).get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202); RestAssured // @formatter:off .given().header("current-user", "superuser-alex@hostsharing.net").port(port).when().get("http://localhost/api/hs/office/coopsharestransactions?membershipUuid=" + givenMembership.getUuid() + "&fromValueDate=2020-01-01&toValueDate=2021-12-31").then().log().all().assertThat().statusCode(200).contentType("application/json").body("", lenientlyEquals(""" @@ -134,7 +134,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest { void globalAdmin_canAddCoopSharesTransaction() { context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000101).get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101); final var location = RestAssured // @formatter:off .given().header("current-user", "superuser-alex@hostsharing.net").contentType(ContentType.JSON).body(""" @@ -165,7 +165,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest { void globalAdmin_canNotCancelMoreSharesThanCurrentlySubscribed() { context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000101).get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101); final var location = RestAssured // @formatter:off .given().header("current-user", "superuser-alex@hostsharing.net").contentType(ContentType.JSON).body(""" diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionRepositoryIntegrationTest.java index 9ef64522..78d0ac7d 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionRepositoryIntegrationTest.java @@ -61,8 +61,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase // given context("superuser-alex@hostsharing.net"); final var count = coopSharesTransactionRepo.count(); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000101) - .get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101); // when final var result = attempt(em, () -> { @@ -95,8 +94,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase // when attempt(em, () -> { - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000101) - .get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101); final var newCoopSharesTransaction = HsOfficeCoopSharesTransactionEntity.builder() .membership(givenMembership) .transactionType(HsOfficeCoopSharesTransactionType.SUBSCRIPTION) @@ -115,7 +113,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase .map(s -> s.replace("hs_office_", "")) .containsExactlyInAnyOrder(Array.fromFormatted( initialGrantNames, - "{ grant perm view on coopsharestransaction#temprefB to role membership#10001:....tenant by system and assume }", + "{ grant perm view on coopsharestransaction#temprefB to role membership#1000101:....tenant by system and assume }", null)); } @@ -142,25 +140,24 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase // then allTheseCoopSharesTransactionsAreReturned( result, - "CoopShareTransaction(10001, 2010-03-15, SUBSCRIPTION, 4, ref 10001-1, initial subscription)", - "CoopShareTransaction(10001, 2021-09-01, CANCELLATION, -2, ref 10001-2, cancelling some)", - "CoopShareTransaction(10001, 2022-10-20, ADJUSTMENT, 2, ref 10001-3, some adjustment)", + "CoopShareTransaction(1000101, 2010-03-15, SUBSCRIPTION, 4, ref 1000101-1, initial subscription)", + "CoopShareTransaction(1000101, 2021-09-01, CANCELLATION, -2, ref 1000101-2, cancelling some)", + "CoopShareTransaction(1000101, 2022-10-20, ADJUSTMENT, 2, ref 1000101-3, some adjustment)", - "CoopShareTransaction(10002, 2010-03-15, SUBSCRIPTION, 4, ref 10002-1, initial subscription)", - "CoopShareTransaction(10002, 2021-09-01, CANCELLATION, -2, ref 10002-2, cancelling some)", - "CoopShareTransaction(10002, 2022-10-20, ADJUSTMENT, 2, ref 10002-3, some adjustment)", + "CoopShareTransaction(1000202, 2010-03-15, SUBSCRIPTION, 4, ref 1000202-1, initial subscription)", + "CoopShareTransaction(1000202, 2021-09-01, CANCELLATION, -2, ref 1000202-2, cancelling some)", + "CoopShareTransaction(1000202, 2022-10-20, ADJUSTMENT, 2, ref 1000202-3, some adjustment)", - "CoopShareTransaction(10003, 2010-03-15, SUBSCRIPTION, 4, ref 10003-1, initial subscription)", - "CoopShareTransaction(10003, 2021-09-01, CANCELLATION, -2, ref 10003-2, cancelling some)", - "CoopShareTransaction(10003, 2022-10-20, ADJUSTMENT, 2, ref 10003-3, some adjustment)"); + "CoopShareTransaction(1000303, 2010-03-15, SUBSCRIPTION, 4, ref 1000303-1, initial subscription)", + "CoopShareTransaction(1000303, 2021-09-01, CANCELLATION, -2, ref 1000303-2, cancelling some)", + "CoopShareTransaction(1000303, 2022-10-20, ADJUSTMENT, 2, ref 1000303-3, some adjustment)"); } @Test public void globalAdmin_canViewCoopSharesTransactions_filteredByMembershipUuid() { // given context("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000202) - .get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202); // when final var result = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange( @@ -171,17 +168,16 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase // then allTheseCoopSharesTransactionsAreReturned( result, - "CoopShareTransaction(10002, 2010-03-15, SUBSCRIPTION, 4, ref 10002-1, initial subscription)", - "CoopShareTransaction(10002, 2021-09-01, CANCELLATION, -2, ref 10002-2, cancelling some)", - "CoopShareTransaction(10002, 2022-10-20, ADJUSTMENT, 2, ref 10002-3, some adjustment)"); + "CoopShareTransaction(1000202, 2010-03-15, SUBSCRIPTION, 4, ref 1000202-1, initial subscription)", + "CoopShareTransaction(1000202, 2021-09-01, CANCELLATION, -2, ref 1000202-2, cancelling some)", + "CoopShareTransaction(1000202, 2022-10-20, ADJUSTMENT, 2, ref 1000202-3, some adjustment)"); } @Test public void globalAdmin_canViewCoopSharesTransactions_filteredByMembershipUuidAndValueDateRange() { // given context("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByMemberNumber(1000202) - .get(0); + final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202); // when final var result = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange( @@ -192,7 +188,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase // then allTheseCoopSharesTransactionsAreReturned( result, - "CoopShareTransaction(10002, 2021-09-01, CANCELLATION, -2, ref 10002-2, cancelling some)"); + "CoopShareTransaction(1000202, 2021-09-01, CANCELLATION, -2, ref 1000202-2, cancelling some)"); } @Test @@ -209,9 +205,9 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase // then: exactlyTheseCoopSharesTransactionsAreReturned( result, - "CoopShareTransaction(10001, 2010-03-15, SUBSCRIPTION, 4, ref 10001-1, initial subscription)", - "CoopShareTransaction(10001, 2021-09-01, CANCELLATION, -2, ref 10001-2, cancelling some)", - "CoopShareTransaction(10001, 2022-10-20, ADJUSTMENT, 2, ref 10001-3, some adjustment)"); + "CoopShareTransaction(1000101, 2010-03-15, SUBSCRIPTION, 4, ref 1000101-1, initial subscription)", + "CoopShareTransaction(1000101, 2021-09-01, CANCELLATION, -2, ref 1000101-2, cancelling some)", + "CoopShareTransaction(1000101, 2022-10-20, ADJUSTMENT, 2, ref 1000101-3, some adjustment)"); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityUnitTest.java index c1cb6c18..6e3e8db1 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityUnitTest.java @@ -29,7 +29,7 @@ class HsOfficeDebitorEntityUnitTest { final var result = given.toString(); - assertThat(result).isEqualTo("debitor(1234567: LEGAL some trade name: som)"); + assertThat(result).isEqualTo("debitor(D-1234567: LEGAL some trade name: som)"); } @Test @@ -46,7 +46,7 @@ class HsOfficeDebitorEntityUnitTest { final var result = given.toString(); - assertThat(result).isEqualTo("debitor(1234567: )"); + assertThat(result).isEqualTo("debitor(D-1234567: )"); } @Test @@ -60,6 +60,60 @@ class HsOfficeDebitorEntityUnitTest { final var result = given.toShortString(); - assertThat(result).isEqualTo("1234567"); + assertThat(result).isEqualTo("D-1234567"); + } + + @Test + void getDebitorNumberWithPartnerNumberAndDebitorNumberSuffix() { + final var given = HsOfficeDebitorEntity.builder() + .partner(HsOfficePartnerEntity.builder() + .partnerNumber(12345) + .build()) + .debitorNumberSuffix((byte)67) + .build(); + + final var result = given.getDebitorNumber(); + + assertThat(result).isEqualTo(1234567); + } + + @Test + void getDebitorNumberWithoutPartnerReturnsNull() { + final var given = HsOfficeDebitorEntity.builder() + .partner(null) + .debitorNumberSuffix((byte)67) + .build(); + + final var result = given.getDebitorNumber(); + + assertThat(result).isNull(); + } + + @Test + void getDebitorNumberWithoutPartnerNumberReturnsNull() { + final var given = HsOfficeDebitorEntity.builder() + .partner(HsOfficePartnerEntity.builder() + .partnerNumber(null) + .build()) + .debitorNumberSuffix((byte)67) + .build(); + + final var result = given.getDebitorNumber(); + + assertThat(result).isNull(); + } + + @Test + void getDebitorNumberWithoutDebitorNumberSuffixReturnsNull() { + final var given = HsOfficeDebitorEntity.builder() + .partner(HsOfficePartnerEntity.builder() + .partnerNumber(12345) + .build()) + .debitorNumberSuffix(null) + .build(); + + final var result = given.getDebitorNumber(); + + assertThat(result).isNull(); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java index 97eb49b1..3e62168f 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java @@ -211,9 +211,9 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { // then allTheseDebitorsAreReturned( result, - "debitor(1000111: LEGAL First GmbH: fir)", - "debitor(1000212: LEGAL Second e.K.: sec)", - "debitor(1000313: SOLE_REPRESENTATION Third OHG: thi)"); + "debitor(D-1000111: LEGAL First GmbH: fir)", + "debitor(D-1000212: LEGAL Second e.K.: sec)", + "debitor(D-1000313: SOLE_REPRESENTATION Third OHG: thi)"); } @ParameterizedTest @@ -231,8 +231,8 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { // then: exactlyTheseDebitorsAreReturned(result, - "debitor(1000111: LEGAL First GmbH: fir)", - "debitor(1000120: LEGAL First GmbH: fif)"); + "debitor(D-1000111: LEGAL First GmbH: fir)", + "debitor(D-1000120: LEGAL First GmbH: fif)"); } @Test @@ -260,7 +260,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { final var result = debitorRepo.findDebitorByDebitorNumber(1000313); // then - exactlyTheseDebitorsAreReturned(result, "debitor(1000313: SOLE_REPRESENTATION Third OHG: thi)"); + exactlyTheseDebitorsAreReturned(result, "debitor(D-1000313: SOLE_REPRESENTATION Third OHG: thi)"); } } @@ -276,7 +276,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { final var result = debitorRepo.findDebitorByOptionalNameLike("third contact"); // then - exactlyTheseDebitorsAreReturned(result, "debitor(1000313: SOLE_REPRESENTATION Third OHG: thi)"); + exactlyTheseDebitorsAreReturned(result, "debitor(D-1000313: SOLE_REPRESENTATION Third OHG: thi)"); } } 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 8fe2028a..0a96b732 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 @@ -61,7 +61,7 @@ class HsOfficeMembershipControllerAcceptanceTest { @PersistenceContext EntityManager em; - private static int tempMemberNumberSuffix = 10; + private static int tempMemberNumberSuffix = 90; // TODO: check if we even need multiple distinct values @Nested @Accepts({ "Membership:F(Find)" }) @@ -84,7 +84,8 @@ class HsOfficeMembershipControllerAcceptanceTest { { "partner": { "person": { "tradeName": "First GmbH" } }, "mainDebitor": { "debitorNumber": 1000111 }, - "memberNumberSuffix": 10001, + "memberNumber": 1000101, + "memberNumberSuffix": "01", "validFrom": "2022-10-01", "validTo": null, "reasonForTermination": "NONE" @@ -92,7 +93,8 @@ class HsOfficeMembershipControllerAcceptanceTest { { "partner": { "person": { "tradeName": "Second e.K." } }, "mainDebitor": { "debitorNumber": 1000212 }, - "memberNumberSuffix": 10002, + "memberNumber": 1000202, + "memberNumberSuffix": "02", "validFrom": "2022-10-01", "validTo": null, "reasonForTermination": "NONE" @@ -100,7 +102,8 @@ class HsOfficeMembershipControllerAcceptanceTest { { "partner": { "person": { "tradeName": "Third OHG" } }, "mainDebitor": { "debitorNumber": 1000313 }, - "memberNumberSuffix": 10003, + "memberNumber": 1000303, + "memberNumberSuffix": "03", "validFrom": "2022-10-01", "validTo": null, "reasonForTermination": "NONE" @@ -109,6 +112,67 @@ class HsOfficeMembershipControllerAcceptanceTest { """)); // @formatter:on } + + @Test + void globalAdmin_canViewMembershipsByPartnerUuid() throws JSONException { + + context.define("superuser-alex@hostsharing.net"); + final var partner = partnerRepo.findPartnerByPartnerNumber(10001); + + RestAssured // @formatter:off + .given() + .header("current-user", "superuser-alex@hostsharing.net") + .port(port) + .when() + .queryParam("partnerUuid", partner.getUuid() ) + .get("http://localhost/api/hs/office/memberships") + .then().log().all().assertThat() + .statusCode(200) + .contentType("application/json") + .body("", lenientlyEquals(""" + [ + { + "partner": { "person": { "tradeName": "First GmbH" } }, + "mainDebitor": { "debitorNumber": 1000111 }, + "memberNumber": 1000101, + "memberNumberSuffix": "01", + "validFrom": "2022-10-01", + "validTo": null, + "reasonForTermination": "NONE" + } + ] + """)); + // @formatter:on + } + + @Test + void globalAdmin_canViewMembershipsByMemberNumber() throws JSONException { + + RestAssured // @formatter:off + .given() + .header("current-user", "superuser-alex@hostsharing.net") + .port(port) + .when() + .queryParam("memberNumber", 1000202 ) + .get("http://localhost/api/hs/office/memberships") + .then().log().all().assertThat() + .statusCode(200) + .contentType("application/json") + .body("", lenientlyEquals(""" + [ + { + "partner": { "person": { "tradeName": "Second e.K." } }, + "mainDebitor": { "debitorNumber": 1000212 }, + "memberNumber": 1000202, + "memberNumberSuffix": "02", + "validFrom": "2022-10-01", + "validTo": null, + "reasonForTermination": "NONE" + } + ] + """)); + // @formatter:on + } } @Nested @@ -121,6 +185,9 @@ class HsOfficeMembershipControllerAcceptanceTest { context.define("superuser-alex@hostsharing.net"); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Third").get(0); final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("Third").get(0); + final var givenMemberSuffixNumber = ++tempMemberNumberSuffix; + final var givenMemberSuffix = toPaddedSuffix(givenMemberSuffixNumber); + final var expectedMemberNumber = givenPartner.getPartnerNumber()*100+givenMemberSuffixNumber; final var location = RestAssured // @formatter:off .given() @@ -130,11 +197,11 @@ class HsOfficeMembershipControllerAcceptanceTest { { "partnerUuid": "%s", "mainDebitorUuid": "%s", - "memberNumberSuffix": 20001, + "memberNumberSuffix": "%s", "validFrom": "2022-10-13", "membershipFeeBillable": "true" } - """.formatted(givenPartner.getUuid(), givenDebitor.getUuid())) + """.formatted(givenPartner.getUuid(), givenDebitor.getUuid(), givenMemberSuffix)) .port(port) .when() .post("http://localhost/api/hs/office/memberships") @@ -145,7 +212,8 @@ class HsOfficeMembershipControllerAcceptanceTest { .body("mainDebitor.debitorNumber", is(givenDebitor.getDebitorNumber())) .body("mainDebitor.debitorNumberSuffix", is((int) givenDebitor.getDebitorNumberSuffix())) .body("partner.person.tradeName", is("Third OHG")) - .body("memberNumberSuffix", is(20001)) + .body("memberNumber", is(expectedMemberNumber)) + .body("memberNumberSuffix", is(givenMemberSuffix)) .body("validFrom", is("2022-10-13")) .body("validTo", equalTo(null)) .header("Location", startsWith("http://localhost")) @@ -166,9 +234,7 @@ class HsOfficeMembershipControllerAcceptanceTest { @Test void globalAdmin_canGetArbitraryMembership() { context.define("superuser-alex@hostsharing.net"); - final var givenMembershipUuid = membershipRepo.findMembershipsByMemberNumber(1000101) - .get(0) - .getUuid(); + final var givenMembershipUuid = membershipRepo.findMembershipByMemberNumber(1000101).getUuid(); RestAssured // @formatter:off .given() @@ -183,7 +249,8 @@ class HsOfficeMembershipControllerAcceptanceTest { { "partner": { "person": { "tradeName": "First GmbH" } }, "mainDebitor": { "debitorNumber": 1000111 }, - "memberNumberSuffix": 10001, + "memberNumber": 1000101, + "memberNumberSuffix": "01", "validFrom": "2022-10-01", "validTo": null, "reasonForTermination": "NONE" @@ -195,9 +262,7 @@ class HsOfficeMembershipControllerAcceptanceTest { @Accepts({ "Membership:X(Access Control)" }) void normalUser_canNotGetUnrelatedMembership() { context.define("superuser-alex@hostsharing.net"); - final var givenMembershipUuid = membershipRepo.findMembershipsByMemberNumber(1000101) - .get(0) - .getUuid(); + final var givenMembershipUuid = membershipRepo.findMembershipByMemberNumber(1000101).getUuid(); RestAssured // @formatter:off .given() @@ -213,9 +278,7 @@ class HsOfficeMembershipControllerAcceptanceTest { @Accepts({ "Membership:X(Access Control)" }) void debitorAgentUser_canGetRelatedMembership() { context.define("superuser-alex@hostsharing.net"); - final var givenMembershipUuid = membershipRepo.findMembershipsByMemberNumber(1000303) - .get(0) - .getUuid(); + final var givenMembershipUuid = membershipRepo.findMembershipByMemberNumber(1000303).getUuid(); RestAssured // @formatter:off .given() @@ -234,7 +297,8 @@ class HsOfficeMembershipControllerAcceptanceTest { "debitorNumber": 1000313, "billingContact": { "label": "third contact" } }, - "memberNumberSuffix": 10003, + "memberNumber": 1000303, + "memberNumberSuffix": "03", "validFrom": "2022-10-01", "validTo": null, "reasonForTermination": "NONE" @@ -458,8 +522,10 @@ class HsOfficeMembershipControllerAcceptanceTest { void cleanup() { jpaAttempt.transacted(() -> { context.define("superuser-alex@hostsharing.net", null); - final var query = em.createQuery("DELETE FROM HsOfficeMembershipEntity m WHERE m.memberNumberSuffix >= '20'"); - query.executeUpdate(); - }); + final var query = em.createQuery("DELETE FROM HsOfficeMembershipEntity m WHERE m.memberNumberSuffix >= '90'"); + if ( query.executeUpdate() > 0 ) { + query.toString(); + } + }).assertSuccessful(); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerRestTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerRestTest.java index 30617a36..63ea7306 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerRestTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerRestTest.java @@ -6,7 +6,10 @@ import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; import net.hostsharing.hsadminng.mapper.Mapper; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; @@ -22,6 +25,7 @@ import jakarta.persistence.SynchronizationType; import java.util.Map; import java.util.UUID; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -59,119 +63,166 @@ public class HsOfficeMembershipControllerRestTest { when(emf.createEntityManager(any(SynchronizationType.class), any(Map.class))).thenReturn(em); } - @Test - void respondBadRequest_ifPartnerUuidIsMissing() throws Exception { + @Nested + class AddMembership { + @Test + void respondBadRequest_ifPartnerUuidIsMissing() throws Exception { - // when - mockMvc.perform(MockMvcRequestBuilders - .post("/api/hs/office/memberships") - .header("current-user", "superuser-alex@hostsharing.net") - .contentType(MediaType.APPLICATION_JSON) - .content(""" - { - "partnerUuid": null, - "mainDebitorUuid": "%s", - "memberNumberSuffix": 20001, - "validFrom": "2022-10-13", - "membershipFeeBillable": "true" - } - """.formatted(UUID.randomUUID())) - .accept(MediaType.APPLICATION_JSON)) + // when + mockMvc.perform(MockMvcRequestBuilders + .post("/api/hs/office/memberships") + .header("current-user", "superuser-alex@hostsharing.net") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "partnerUuid": null, + "mainDebitorUuid": "%s", + "memberNumberSuffix": "01", + "validFrom": "2022-10-13", + "membershipFeeBillable": "true" + } + """.formatted(UUID.randomUUID())) + .accept(MediaType.APPLICATION_JSON)) - // then - .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("statusCode", is(400))) - .andExpect(jsonPath("statusPhrase", is("Bad Request"))) - .andExpect(jsonPath("message", is("[partnerUuid must not be null but is \"null\"]"))); + // then + .andExpect(status().is4xxClientError()) + .andExpect(jsonPath("statusCode", is(400))) + .andExpect(jsonPath("statusPhrase", is("Bad Request"))) + .andExpect(jsonPath("message", is("[partnerUuid must not be null but is \"null\"]"))); + } + + @Test + void respondBadRequest_ifDebitorUuidIsMissing() throws Exception { + + // when + mockMvc.perform(MockMvcRequestBuilders + .post("/api/hs/office/memberships") + .header("current-user", "superuser-alex@hostsharing.net") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "partnerUuid": "%s", + "mainDebitorUuid": null, + "memberNumberSuffix": "01", + "validFrom": "2022-10-13", + "membershipFeeBillable": "true" + } + """.formatted(UUID.randomUUID())) + .accept(MediaType.APPLICATION_JSON)) + + // then + .andExpect(status().is4xxClientError()) + .andExpect(jsonPath("statusCode", is(400))) + .andExpect(jsonPath("statusPhrase", is("Bad Request"))) + .andExpect(jsonPath("message", is("[mainDebitorUuid must not be null but is \"null\"]"))); + } + + @Test + void respondBadRequest_ifAnyGivenPartnerUuidCannotBeFound() throws Exception { + + // given + final var givenPartnerUuid = UUID.randomUUID(); + final var givenMainDebitorUuid = UUID.randomUUID(); + when(em.find(HsOfficePartnerEntity.class, givenPartnerUuid)).thenReturn(null); + when(em.find(HsOfficeDebitorEntity.class, givenMainDebitorUuid)).thenReturn(mock(HsOfficeDebitorEntity.class)); + + // when + mockMvc.perform(MockMvcRequestBuilders + .post("/api/hs/office/memberships") + .header("current-user", "superuser-alex@hostsharing.net") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "partnerUuid": "%s", + "mainDebitorUuid": "%s", + "memberNumberSuffix": "01", + "validFrom": "2022-10-13", + "membershipFeeBillable": "true" + } + """.formatted(givenPartnerUuid, givenMainDebitorUuid)) + .accept(MediaType.APPLICATION_JSON)) + + // then + .andExpect(status().is4xxClientError()) + .andExpect(jsonPath("statusCode", is(400))) + .andExpect(jsonPath("statusPhrase", is("Bad Request"))) + .andExpect(jsonPath("message", is("Unable to find Partner with uuid " + givenPartnerUuid))); + } + + @Test + void respondBadRequest_ifAnyGivenDebitorUuidCannotBeFound() throws Exception { + + // given + final var givenPartnerUuid = UUID.randomUUID(); + final var givenMainDebitorUuid = UUID.randomUUID(); + when(em.find(HsOfficePartnerEntity.class, givenPartnerUuid)).thenReturn(mock(HsOfficePartnerEntity.class)); + when(em.find(HsOfficeDebitorEntity.class, givenMainDebitorUuid)).thenReturn(null); + + // when + mockMvc.perform(MockMvcRequestBuilders + .post("/api/hs/office/memberships") + .header("current-user", "superuser-alex@hostsharing.net") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "partnerUuid": "%s", + "mainDebitorUuid": "%s", + "memberNumberSuffix": "01", + "validFrom": "2022-10-13", + "membershipFeeBillable": "true" + } + """.formatted(givenPartnerUuid, givenMainDebitorUuid)) + .accept(MediaType.APPLICATION_JSON)) + + // then + .andExpect(status().is4xxClientError()) + .andExpect(jsonPath("statusCode", is(400))) + .andExpect(jsonPath("statusPhrase", is("Bad Request"))) + .andExpect(jsonPath("message", is("Unable to find Debitor with uuid " + givenMainDebitorUuid))); + } + + @ParameterizedTest + @EnumSource(InvalidMemberSuffixVariants.class) + void respondBadRequest_ifMemberNumberSuffixIsInvalid(final InvalidMemberSuffixVariants testCase) throws Exception { + + // when + mockMvc.perform(MockMvcRequestBuilders + .post("/api/hs/office/memberships") + .header("current-user", "superuser-alex@hostsharing.net") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "partnerUuid": "%s", + "mainDebitorUuid": "%s", + %s + "validFrom": "2022-10-13", + "membershipFeeBillable": "true" + } + """.formatted(UUID.randomUUID(), UUID.randomUUID(), testCase.memberNumberSuffixEntry)) + .accept(MediaType.APPLICATION_JSON)) + + // then + .andExpect(status().is4xxClientError()) + .andExpect(jsonPath("statusCode", is(400))) + .andExpect(jsonPath("statusPhrase", is("Bad Request"))) + .andExpect(jsonPath("message", containsString(testCase.expectedErrorMessage))); + } + + public enum InvalidMemberSuffixVariants { + MISSING("", "[memberNumberSuffix must not be null but is \"null\"]"), + TOO_SMALL("\"memberNumberSuffix\": \"9\",", "memberNumberSuffix size must be between 2 and 2 but is \"9\""), + TOO_LARGE("\"memberNumberSuffix\": \"100\",", "memberNumberSuffix size must be between 2 and 2 but is \"100\""), + NOT_NUMERIC("\"memberNumberSuffix\": \"AA\",", "memberNumberSuffix must match \"[0-9]+\" but is \"AA\""), + EMPTY("\"memberNumberSuffix\": \"\",", "memberNumberSuffix size must be between 2 and 2 but is \"\""); + + private final String memberNumberSuffixEntry; + private final String expectedErrorMessage; + + InvalidMemberSuffixVariants(final String memberNumberSuffixEntry, final String expectedErrorMessage) { + this.memberNumberSuffixEntry = memberNumberSuffixEntry; + this.expectedErrorMessage = expectedErrorMessage; + } + } } - @Test - void respondBadRequest_ifDebitorUuidIsMissing() throws Exception { - - // when - mockMvc.perform(MockMvcRequestBuilders - .post("/api/hs/office/memberships") - .header("current-user", "superuser-alex@hostsharing.net") - .contentType(MediaType.APPLICATION_JSON) - .content(""" - { - "partnerUuid": "%s", - "mainDebitorUuid": null, - "memberNumberSuffix": 20001, - "validFrom": "2022-10-13", - "membershipFeeBillable": "true" - } - """.formatted(UUID.randomUUID())) - .accept(MediaType.APPLICATION_JSON)) - - // then - .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("statusCode", is(400))) - .andExpect(jsonPath("statusPhrase", is("Bad Request"))) - .andExpect(jsonPath("message", is("[mainDebitorUuid must not be null but is \"null\"]"))); - } - - @Test - void respondBadRequest_ifAnyGivenPartnerUuidCannotBeFound() throws Exception { - - // given - final var givenPartnerUuid = UUID.randomUUID(); - final var givenMainDebitorUuid = UUID.randomUUID(); - when(em.find(HsOfficePartnerEntity.class, givenPartnerUuid)).thenReturn(null); - when(em.find(HsOfficeDebitorEntity.class, givenMainDebitorUuid)).thenReturn(mock(HsOfficeDebitorEntity.class)); - - // when - mockMvc.perform(MockMvcRequestBuilders - .post("/api/hs/office/memberships") - .header("current-user", "superuser-alex@hostsharing.net") - .contentType(MediaType.APPLICATION_JSON) - .content(""" - { - "partnerUuid": "%s", - "mainDebitorUuid": "%s", - "memberNumberSuffix": 20001, - "validFrom": "2022-10-13", - "membershipFeeBillable": "true" - } - """.formatted(givenPartnerUuid, givenMainDebitorUuid)) - .accept(MediaType.APPLICATION_JSON)) - - // then - .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("statusCode", is(400))) - .andExpect(jsonPath("statusPhrase", is("Bad Request"))) - .andExpect(jsonPath("message", is("Unable to find Partner with uuid " + givenPartnerUuid))); - } - - @Test - void respondBadRequest_ifAnyGivenDebitorUuidCannotBeFound() throws Exception { - - // given - final var givenPartnerUuid = UUID.randomUUID(); - final var givenMainDebitorUuid = UUID.randomUUID(); - when(em.find(HsOfficePartnerEntity.class, givenPartnerUuid)).thenReturn(mock(HsOfficePartnerEntity.class)); - when(em.find(HsOfficeDebitorEntity.class, givenMainDebitorUuid)).thenReturn(null); - - // when - mockMvc.perform(MockMvcRequestBuilders - .post("/api/hs/office/memberships") - .header("current-user", "superuser-alex@hostsharing.net") - .contentType(MediaType.APPLICATION_JSON) - .content(""" - { - "partnerUuid": "%s", - "mainDebitorUuid": "%s", - "memberNumberSuffix": 20001, - "validFrom": "2022-10-13", - "membershipFeeBillable": "true" - } - """.formatted(givenPartnerUuid, givenMainDebitorUuid)) - .accept(MediaType.APPLICATION_JSON)) - - // then - .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("statusCode", is(400))) - .andExpect(jsonPath("statusPhrase", is("Bad Request"))) - .andExpect(jsonPath("message", is("Unable to find Debitor with uuid " + givenMainDebitorUuid))); - } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityUnitTest.java index 9563d6ad..4132c1bd 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityUnitTest.java @@ -1,6 +1,7 @@ package net.hostsharing.hsadminng.hs.office.membership; import com.vladmihalcea.hibernate.type.range.Range; +import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; import org.junit.jupiter.api.Test; import jakarta.persistence.PrePersist; @@ -26,17 +27,49 @@ class HsOfficeMembershipEntityUnitTest { @Test void toStringContainsAllProps() { final var result = givenMembership.toString(); - - assertThat(result).isEqualTo("Membership(M-1000101, LEGAL Test Ltd., 1000100, [2020-01-01,))"); + assertThat(result).isEqualTo("Membership(M-1000101, LEGAL Test Ltd., D-1000100, [2020-01-01,))"); } @Test void toShortStringContainsMemberNumberSuffixOnly() { final var result = givenMembership.toShortString(); - assertThat(result).isEqualTo("M-1000101"); } + @Test + void getMemberNumberWithPartnerAndSuffix() { + final var result = givenMembership.getMemberNumber(); + assertThat(result).isEqualTo(1000101); + } + + @Test + void getMemberNumberWithPartnerButWithoutSuffix() { + givenMembership.setMemberNumberSuffix(null); + final var result = givenMembership.getMemberNumber(); + assertThat(result).isEqualTo(null); + } + + @Test + void getMemberNumberWithoutPartnerButWithSuffix() { + givenMembership.setPartner(null); + final var result = givenMembership.getMemberNumber(); + assertThat(result).isEqualTo(null); + } + + @Test + void getMemberNumberWithoutPartnerNumberButWithSuffix() { + givenMembership.setPartner(HsOfficePartnerEntity.builder().build()); + final var result = givenMembership.getMemberNumber(); + assertThat(result).isEqualTo(null); + } + + @Test + void getValidtyIfNull() { + givenMembership.setValidity(null); + final var result = givenMembership.getValidity(); + assertThat(result).isEqualTo(Range.infinite(LocalDate.class)); + } + @Test void initializesReasonForTerminationInPrePersistIfNull() throws Exception { final var givenUninitializedMembership = new HsOfficeMembershipEntity(); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java index e6ec5bb2..7570d31e 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java @@ -184,9 +184,9 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest { // then exactlyTheseMembershipsAreReturned( result, - "Membership(M-1000101, LEGAL First GmbH, 1000111, [2022-10-01,), NONE)", - "Membership(M-1000202, LEGAL Second e.K., 1000212, [2022-10-01,), NONE)", - "Membership(M-1000303, SOLE_REPRESENTATION Third OHG, 1000313, [2022-10-01,), NONE)"); + "Membership(M-1000101, LEGAL First GmbH, D-1000111, [2022-10-01,), NONE)", + "Membership(M-1000202, LEGAL Second e.K., D-1000212, [2022-10-01,), NONE)", + "Membership(M-1000303, SOLE_REPRESENTATION Third OHG, D-1000313, [2022-10-01,), NONE)"); } @Test @@ -200,7 +200,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest { // then exactlyTheseMembershipsAreReturned(result, - "Membership(M-1000101, LEGAL First GmbH, 1000111, [2022-10-01,), NONE)"); + "Membership(M-1000101, LEGAL First GmbH, D-1000111, [2022-10-01,), NONE)"); } @Test @@ -209,11 +209,13 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest { context("superuser-alex@hostsharing.net"); // when - final var result = membershipRepo.findMembershipsByMemberNumber(1000202); + final var result = membershipRepo.findMembershipByMemberNumber(1000202); // then - exactlyTheseMembershipsAreReturned(result, - "Membership(M-1000202, LEGAL Second e.K., 1000212, [2022-10-01,), NONE)"); + assertThat(result) + .isNotNull() + .extracting(Object::toString) + .isEqualTo("Membership(M-1000202, LEGAL Second e.K., D-1000212, [2022-10-01,), NONE)"); } } 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 18eb063d..3aba5640 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 @@ -211,6 +211,25 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { } } + @Nested + class FindByPartnerNumber { + + @Test + public void globalAdmin_withoutAssumedRole_canViewAllPartners() { + // given + context("superuser-alex@hostsharing.net"); + + // when + final var result = partnerRepo.findPartnerByPartnerNumber(10001); + + // then + assertThat(result) + .isNotNull() + .extracting(Object::toString) + .isEqualTo("partner(LEGAL First GmbH: first contact)"); + } + } + @Nested class UpdatePartner { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntityUnitTest.java new file mode 100644 index 00000000..f1246561 --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntityUnitTest.java @@ -0,0 +1,32 @@ +package net.hostsharing.hsadminng.hs.office.relationship; + +import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; +import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class HsOfficeRelationshipEntityUnitTest { + + private HsOfficePersonEntity anchor = HsOfficePersonEntity.builder() + .personType(HsOfficePersonType.LEGAL) + .tradeName("some trade name") + .build(); + private HsOfficePersonEntity holder = HsOfficePersonEntity.builder() + .personType(HsOfficePersonType.NATURAL) + .familyName("Meier") + .givenName("Mellie") + .build(); + + @Test + void toShortString() { + final var given = HsOfficeRelationshipEntity.builder() + .relType(HsOfficeRelationshipType.REPRESENTATIVE) + .relAnchor(anchor) + .relHolder(holder) + .build(); + + assertThat(given.toShortString()).isEqualTo("rel(relAnchor='LEGAL some trade name', relType='REPRESENTATIVE', relHolder='NATURAL Meier, Mellie')"); + } +} 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 70cf53da..f38a3f8f 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 @@ -376,7 +376,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest { context.define("superuser-alex@hostsharing.net"); assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent().get() .matches(mandate -> { - assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(1000111: LEGAL First GmbH: fir)"); + assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(D-1000111: LEGAL First GmbH: fir)"); assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH"); assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z - patched"); assertThat(mandate.getValidFrom()).isEqualTo("2020-06-05"); @@ -417,7 +417,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest { // finally, the sepaMandate is actually updated assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent().get() .matches(mandate -> { - assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(1000111: LEGAL First GmbH: fir)"); + assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(D-1000111: LEGAL First GmbH: fir)"); assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH"); assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z"); assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2023-01-01)");