Merge pull request 'Add constraint to relation to check if anchor of debitor relation is a PARTNER' (#175) from TP-20250326_relation_contraint_check_debitor_anchor_is_partner into master
Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/175 Reviewed-by: Michael Hoennig <michael.hoennig@hostsharing.net>
This commit is contained in:
		| @@ -32,6 +32,7 @@ create table if not exists hs_office.relation | |||||||
|  |  | ||||||
| -- ============================================================================ | -- ============================================================================ | ||||||
| --changeset michael.hoennig:hs-office-relation-unique-constraints endDelimiter:--// | --changeset michael.hoennig:hs-office-relation-unique-constraints endDelimiter:--// | ||||||
|  | --validCheckSum: 9:79e93a47a62e44c661cd8d414626e49d | ||||||
| -- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
| CREATE UNIQUE INDEX unique_relation_with_mark | CREATE UNIQUE INDEX unique_relation_with_mark | ||||||
| @@ -49,6 +50,36 @@ CREATE UNIQUE INDEX unique_partner_relation | |||||||
| --// | --// | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ===================================================================================== | ||||||
|  | --changeset timotheus.pokorra:hs-office-relation-debitor-anchor-CONSTRAINT endDelimiter:--// | ||||||
|  | -- ------------------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | -- | ||||||
|  | -- Name: relation_check_debitor_anchor_partner(RelationType, uuid); Type: FUNCTION; Schema: hs_office; Owner: test | ||||||
|  | -- | ||||||
|  |  | ||||||
|  | CREATE FUNCTION hs_office.relation_check_debitor_anchor_partner(mytype hs_office.RelationType, debitoranchoruuid uuid) RETURNS boolean | ||||||
|  |     LANGUAGE plpgsql | ||||||
|  |     AS ' | ||||||
|  | declare | ||||||
|  |     countPartner integer; | ||||||
|  | begin | ||||||
|  |     if mytype = ''DEBITOR'' then | ||||||
|  |         SELECT COUNT(*) FROM hs_office.relation r | ||||||
|  |             WHERE r.type = ''PARTNER'' AND r.holderuuid = debitoranchoruuid | ||||||
|  |             INTO countPartner; | ||||||
|  |         if countPartner < 1 then | ||||||
|  |             raise exception ''[400] invalid debitor relation: anchor person must have a PARTNER relation''; | ||||||
|  |         end if; | ||||||
|  |     end if; | ||||||
|  |     return true; | ||||||
|  | end; '; | ||||||
|  |  | ||||||
|  | ALTER TABLE hs_office.relation ADD CONSTRAINT check_debitor_anchor_person CHECK (hs_office.relation_check_debitor_anchor_partner(type, anchorUuid)); | ||||||
|  |  | ||||||
|  | --// | ||||||
|  |  | ||||||
|  |  | ||||||
| -- ============================================================================ | -- ============================================================================ | ||||||
| --changeset michael.hoennig:hs-office-relation-MAIN-TABLE-JOURNAL endDelimiter:--// | --changeset michael.hoennig:hs-office-relation-MAIN-TABLE-JOURNAL endDelimiter:--// | ||||||
| -- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||||||
|   | |||||||
| @@ -1,7 +1,9 @@ | |||||||
| package net.hostsharing.hsadminng.hs.office.relation; | package net.hostsharing.hsadminng.hs.office.relation; | ||||||
|  |  | ||||||
| import net.hostsharing.hsadminng.context.Context; | import net.hostsharing.hsadminng.context.Context; | ||||||
| import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRbacRepository; | import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository; | ||||||
|  | import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity; | ||||||
|  | import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository; | ||||||
| import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType; | import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType; | ||||||
| import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; | import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; | ||||||
| import net.hostsharing.hsadminng.rbac.test.JpaAttempt; | import net.hostsharing.hsadminng.rbac.test.JpaAttempt; | ||||||
| @@ -21,6 +23,8 @@ import java.util.UUID; | |||||||
|  |  | ||||||
| import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.NATURAL_PERSON; | import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.NATURAL_PERSON; | ||||||
| import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.REPRESENTATIVE; | import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.REPRESENTATIVE; | ||||||
|  | import static net.hostsharing.hsadminng.rbac.test.EntityList.one; | ||||||
|  | import static net.hostsharing.hsadminng.rbac.test.JpaAttempt.attempt; | ||||||
| import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||||
|  |  | ||||||
| @DataJpaTest | @DataJpaTest | ||||||
| @@ -29,10 +33,13 @@ import static org.assertj.core.api.Assertions.assertThat; | |||||||
| class HsOfficeRealRelationRepositoryIntegrationTest extends ContextBasedTestWithCleanup { | class HsOfficeRealRelationRepositoryIntegrationTest extends ContextBasedTestWithCleanup { | ||||||
|  |  | ||||||
|     @Autowired |     @Autowired | ||||||
|     HsOfficeRelationRealRepository relationRealRepo; |     HsOfficeRelationRealRepository realRelationRepo; | ||||||
|  |  | ||||||
|     @Autowired |     @Autowired | ||||||
|     HsOfficePersonRbacRepository personRepo; |     HsOfficePersonRealRepository realPersonRepo; | ||||||
|  |  | ||||||
|  |     @Autowired | ||||||
|  |     HsOfficeContactRealRepository realContactRepo; | ||||||
|  |  | ||||||
|     @PersistenceContext |     @PersistenceContext | ||||||
|     EntityManager em; |     EntityManager em; | ||||||
| @@ -49,7 +56,7 @@ class HsOfficeRealRelationRepositoryIntegrationTest extends ContextBasedTestWith | |||||||
|             final var personUuid = determinePersonUuid(NATURAL_PERSON, "Smith"); |             final var personUuid = determinePersonUuid(NATURAL_PERSON, "Smith"); | ||||||
|  |  | ||||||
|             // when |             // when | ||||||
|             final var result = relationRealRepo.findRelationRelatedToPersonUuid(personUuid); |             final var result = realRelationRepo.findRelationRelatedToPersonUuid(personUuid); | ||||||
|  |  | ||||||
|             // then |             // then | ||||||
|             context("superuser-alex@hostsharing.net"); // just to be able to access RBAc-entities persons+contact |             context("superuser-alex@hostsharing.net"); // just to be able to access RBAc-entities persons+contact | ||||||
| @@ -68,7 +75,7 @@ class HsOfficeRealRelationRepositoryIntegrationTest extends ContextBasedTestWith | |||||||
|             final var personUuid = determinePersonUuid(NATURAL_PERSON, "Smith"); |             final var personUuid = determinePersonUuid(NATURAL_PERSON, "Smith"); | ||||||
|  |  | ||||||
|             // when: |             // when: | ||||||
|             final var result = relationRealRepo.findRelationRelatedToPersonUuidRelationTypeMarkPersonAndContactData(personUuid, REPRESENTATIVE, null, null, null); |             final var result = realRelationRepo.findRelationRelatedToPersonUuidRelationTypeMarkPersonAndContactData(personUuid, REPRESENTATIVE, null, null, null); | ||||||
|  |  | ||||||
|             // then: |             // then: | ||||||
|             context("superuser-alex@hostsharing.net"); // just to be able to access RBAc-entities persons+contact |             context("superuser-alex@hostsharing.net"); // just to be able to access RBAc-entities persons+contact | ||||||
| @@ -79,6 +86,34 @@ class HsOfficeRealRelationRepositoryIntegrationTest extends ContextBasedTestWith | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Nested | ||||||
|  |     class CreateRelation { | ||||||
|  |  | ||||||
|  |         @Test | ||||||
|  |         public void canNotAddDebitorRelationWithAnchorThatIsNotAPartner() { | ||||||
|  |             // given | ||||||
|  |             context("superuser-alex@hostsharing.net"); | ||||||
|  |  | ||||||
|  |             final var givenPartnerPerson = hsOfficePersonRealEntity("Non-Partner Person"); | ||||||
|  |             final var givenContact = one(realContactRepo.findContactByOptionalCaptionLike("eleventh contact")); | ||||||
|  |  | ||||||
|  |             // when | ||||||
|  |             final var result = attempt(em, () -> { | ||||||
|  |                 final var newRelation = HsOfficeRelationRealEntity.builder() | ||||||
|  |                     .type(HsOfficeRelationType.DEBITOR) | ||||||
|  |                     .anchor(givenPartnerPerson) | ||||||
|  |                     .holder(givenPartnerPerson) | ||||||
|  |                     .contact(givenContact) | ||||||
|  |                     .build(); | ||||||
|  |                 final var entity = realRelationRepo.save(newRelation); | ||||||
|  |                 return toCleanup(entity.load()); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             // then | ||||||
|  |             result.assertExceptionWithRootCauseMessage(org.postgresql.util.PSQLException.class, "ERROR: [400] invalid debitor relation: anchor person must have a PARTNER relation"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private UUID determinePersonUuid(final HsOfficePersonType type, final String familyName) { |     private UUID determinePersonUuid(final HsOfficePersonType type, final String familyName) { | ||||||
|         return (UUID) em.createNativeQuery(""" |         return (UUID) em.createNativeQuery(""" | ||||||
|                     SELECT uuid FROM hs_office.person p |                     SELECT uuid FROM hs_office.person p | ||||||
| @@ -97,4 +132,12 @@ class HsOfficeRealRelationRepositoryIntegrationTest extends ContextBasedTestWith | |||||||
|                 .extracting(HsOfficeRelation::toString) |                 .extracting(HsOfficeRelation::toString) | ||||||
|                 .containsExactlyInAnyOrder(relationNames); |                 .containsExactlyInAnyOrder(relationNames); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public HsOfficePersonRealEntity hsOfficePersonRealEntity(final String tradeName) { | ||||||
|  |         return realPersonRepo.save(HsOfficePersonRealEntity.builder() | ||||||
|  |             .personType(HsOfficePersonType.NATURAL_PERSON) | ||||||
|  |             .tradeName(tradeName) | ||||||
|  |             .build()); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user