add hs-office-coopshares entity+repository
This commit is contained in:
parent
7376301ed4
commit
c2dd3d8de9
@ -0,0 +1,73 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopshares;
|
||||||
|
|
||||||
|
import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType;
|
||||||
|
import lombok.*;
|
||||||
|
import net.hostsharing.hsadminng.Stringify;
|
||||||
|
import net.hostsharing.hsadminng.Stringifyable;
|
||||||
|
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
|
||||||
|
import org.hibernate.annotations.Type;
|
||||||
|
import org.hibernate.annotations.TypeDef;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.Stringify.stringify;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "hs_office_coopsharestransaction_rv")
|
||||||
|
@TypeDef(
|
||||||
|
name = "pgsql_enum",
|
||||||
|
typeClass = PostgreSQLEnumType.class
|
||||||
|
)
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@DisplayName("CoopShareTransaction")
|
||||||
|
public class HsOfficeCoopSharesTransactionEntity implements Stringifyable {
|
||||||
|
|
||||||
|
private static Stringify<HsOfficeCoopSharesTransactionEntity> stringify = stringify(HsOfficeCoopSharesTransactionEntity.class)
|
||||||
|
.withProp(e -> e.getMembership().getMemberNumber())
|
||||||
|
.withProp(HsOfficeCoopSharesTransactionEntity::getValueDate)
|
||||||
|
.withProp(HsOfficeCoopSharesTransactionEntity::getTransactionType)
|
||||||
|
.withProp(HsOfficeCoopSharesTransactionEntity::getShareCount)
|
||||||
|
.withProp(HsOfficeCoopSharesTransactionEntity::getReference)
|
||||||
|
.withSeparator(", ")
|
||||||
|
.quotedValues(false);
|
||||||
|
|
||||||
|
private @Id UUID uuid;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "membershipuuid")
|
||||||
|
private HsOfficeMembershipEntity membership;
|
||||||
|
|
||||||
|
@Column(name = "transactiontype")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@Type( type = "pgsql_enum" )
|
||||||
|
private HsOfficeCoopSharesTransactionType transactionType;
|
||||||
|
|
||||||
|
@Column(name = "valuedate")
|
||||||
|
private LocalDate valueDate;
|
||||||
|
|
||||||
|
@Column(name = "sharecount")
|
||||||
|
private int shareCount;
|
||||||
|
|
||||||
|
@Column(name = "reference")
|
||||||
|
private String reference;
|
||||||
|
|
||||||
|
@Column(name = "comment")
|
||||||
|
private String comment;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return stringify.apply(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toShortString() {
|
||||||
|
return "%s%+d".formatted(membership.getMemberNumber(), shareCount);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopshares;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.Repository;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface HsOfficeCoopSharesTransactionRepository extends Repository<HsOfficeCoopSharesTransactionEntity, UUID> {
|
||||||
|
|
||||||
|
Optional<HsOfficeCoopSharesTransactionEntity> findByUuid(UUID id);
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
SELECT st FROM HsOfficeCoopSharesTransactionEntity st
|
||||||
|
WHERE (:memberNumber IS NULL OR st.membership.memberNumber = :memberNumber)
|
||||||
|
AND (:fromValueDate IS NULL OR (st.valueDate >= :fromValueDate))
|
||||||
|
AND (:toValueDate IS NULL OR (st.valueDate <= :toValueDate))
|
||||||
|
ORDER BY st.membership.memberNumber, st.valueDate
|
||||||
|
""")
|
||||||
|
List<HsOfficeCoopSharesTransactionEntity> findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
|
Integer memberNumber, LocalDate fromValueDate, LocalDate toValueDate);
|
||||||
|
|
||||||
|
HsOfficeCoopSharesTransactionEntity save(final HsOfficeCoopSharesTransactionEntity entity);
|
||||||
|
|
||||||
|
long count();
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopshares;
|
||||||
|
|
||||||
|
public enum HsOfficeCoopSharesTransactionType {
|
||||||
|
ADJUSTMENT, SUBSCRIPTION, CANCELLATION;
|
||||||
|
}
|
@ -91,7 +91,7 @@ public class ArchitectureTest {
|
|||||||
public static final ArchRule HsOfficeMembershipPackageRule = classes()
|
public static final ArchRule HsOfficeMembershipPackageRule = classes()
|
||||||
.that().resideInAPackage("..hs.office.membership..")
|
.that().resideInAPackage("..hs.office.membership..")
|
||||||
.should().onlyBeAccessed().byClassesThat()
|
.should().onlyBeAccessed().byClassesThat()
|
||||||
.resideInAnyPackage("..hs.office.membership..");
|
.resideInAnyPackage("..hs.office.membership..", "..hs.office.coopshares..");
|
||||||
|
|
||||||
@ArchTest
|
@ArchTest
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopshares;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.office.membership.TestHsMembership.testMembership;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class HsOfficeCoopSharesTransactionEntityTest {
|
||||||
|
|
||||||
|
final HsOfficeCoopSharesTransactionEntity givenSepaMandate = HsOfficeCoopSharesTransactionEntity.builder()
|
||||||
|
.membership(testMembership)
|
||||||
|
.reference("some-ref")
|
||||||
|
.valueDate(LocalDate.parse("2020-01-01"))
|
||||||
|
.transactionType(HsOfficeCoopSharesTransactionType.SUBSCRIPTION)
|
||||||
|
.shareCount(4)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toStringContainsAlmostAllPropertiesAccount() {
|
||||||
|
final var result = givenSepaMandate.toString();
|
||||||
|
|
||||||
|
assertThat(result).isEqualTo("CoopShareTransaction(300001, 2020-01-01, SUBSCRIPTION, 4, some-ref)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toShortStringContainsOnlyMemberNumberAndSharesCountOnly() {
|
||||||
|
final var result = givenSepaMandate.toShortString();
|
||||||
|
|
||||||
|
assertThat(result).isEqualTo("300001+4");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,227 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.coopshares;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import net.hostsharing.hsadminng.context.ContextBasedTest;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository;
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository;
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository;
|
||||||
|
import net.hostsharing.test.Array;
|
||||||
|
import net.hostsharing.test.JpaAttempt;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
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.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantDisplaysOf;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf;
|
||||||
|
import static net.hostsharing.test.JpaAttempt.attempt;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@DataJpaTest
|
||||||
|
@ComponentScan(basePackageClasses = { HsOfficeCoopSharesTransactionRepository.class, Context.class, JpaAttempt.class })
|
||||||
|
@DirtiesContext
|
||||||
|
class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBasedTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HsOfficeCoopSharesTransactionRepository coopSharesTransactionRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HsOfficeMembershipRepository membershipRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
RawRbacRoleRepository rawRoleRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
RawRbacGrantRepository rawGrantRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
EntityManager em;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
JpaAttempt jpaAttempt;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
HttpServletRequest request;
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class CreateCoopSharesTransaction {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void globalAdmin_canCreateNewCoopShareTransaction() {
|
||||||
|
// given
|
||||||
|
context("superuser-alex@hostsharing.net");
|
||||||
|
final var count = coopSharesTransactionRepo.count();
|
||||||
|
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001)
|
||||||
|
.get(0);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var result = attempt(em, () -> {
|
||||||
|
final var newCoopSharesTransaction = HsOfficeCoopSharesTransactionEntity.builder()
|
||||||
|
.uuid(UUID.randomUUID())
|
||||||
|
.membership(givenMembership)
|
||||||
|
.transactionType(HsOfficeCoopSharesTransactionType.SUBSCRIPTION)
|
||||||
|
.shareCount(4)
|
||||||
|
.valueDate(LocalDate.parse("2022-10-18"))
|
||||||
|
.reference("temp ref A")
|
||||||
|
.build();
|
||||||
|
return coopSharesTransactionRepo.save(newCoopSharesTransaction);
|
||||||
|
});
|
||||||
|
|
||||||
|
// then
|
||||||
|
result.assertSuccessful();
|
||||||
|
assertThat(result.returnedValue()).isNotNull().extracting(HsOfficeCoopSharesTransactionEntity::getUuid).isNotNull();
|
||||||
|
assertThatCoopSharesTransactionIsPersisted(result.returnedValue());
|
||||||
|
assertThat(coopSharesTransactionRepo.count()).isEqualTo(count + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createsAndGrantsRoles() {
|
||||||
|
// given
|
||||||
|
context("superuser-alex@hostsharing.net");
|
||||||
|
final var initialRoleNames = roleNamesOf(rawRoleRepo.findAll());
|
||||||
|
final var initialGrantNames = grantDisplaysOf(rawGrantRepo.findAll()).stream()
|
||||||
|
.map(s -> s.replace("FirstGmbH-firstcontact", "..."))
|
||||||
|
.map(s -> s.replace("hs_office_", ""))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// when
|
||||||
|
attempt(em, () -> {
|
||||||
|
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(
|
||||||
|
null,
|
||||||
|
10001).get(0);
|
||||||
|
final var newCoopSharesTransaction = HsOfficeCoopSharesTransactionEntity.builder()
|
||||||
|
.uuid(UUID.randomUUID())
|
||||||
|
.membership(givenMembership)
|
||||||
|
.transactionType(HsOfficeCoopSharesTransactionType.SUBSCRIPTION)
|
||||||
|
.shareCount(4)
|
||||||
|
.valueDate(LocalDate.parse("2022-10-18"))
|
||||||
|
.reference("temp ref B")
|
||||||
|
.build();
|
||||||
|
return coopSharesTransactionRepo.save(newCoopSharesTransaction);
|
||||||
|
});
|
||||||
|
|
||||||
|
// then
|
||||||
|
final var all = rawRoleRepo.findAll();
|
||||||
|
assertThat(roleNamesOf(all)).containsExactlyInAnyOrder(Array.from(initialRoleNames)); // no new roles created
|
||||||
|
assertThat(grantDisplaysOf(rawGrantRepo.findAll()))
|
||||||
|
.map(s -> s.replace("FirstGmbH-firstcontact", "..."))
|
||||||
|
.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 }",
|
||||||
|
null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertThatCoopSharesTransactionIsPersisted(final HsOfficeCoopSharesTransactionEntity saved) {
|
||||||
|
final var found = coopSharesTransactionRepo.findByUuid(saved.getUuid());
|
||||||
|
assertThat(found).isNotEmpty().get().usingRecursiveComparison().isEqualTo(saved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class FindAllCoopSharesTransactions {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void globalAdmin_withoutAssumedRole_canViewAllCoopSharesTransactions() {
|
||||||
|
// given
|
||||||
|
context("superuser-alex@hostsharing.net");
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var result = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
// then
|
||||||
|
allTheseCoopSharesTransactionsAreReturned(
|
||||||
|
result,
|
||||||
|
"CoopShareTransaction(10001, 2010-03-15, SUBSCRIPTION, 2, ref 10001-1)",
|
||||||
|
"CoopShareTransaction(10001, 2021-09-01, SUBSCRIPTION, 24, ref 10001-2)",
|
||||||
|
"CoopShareTransaction(10001, 2022-10-20, CANCELLATION, 12, ref 10001-3)",
|
||||||
|
|
||||||
|
"CoopShareTransaction(10002, 2010-03-15, SUBSCRIPTION, 2, ref 10002-1)",
|
||||||
|
"CoopShareTransaction(10002, 2021-09-01, SUBSCRIPTION, 24, ref 10002-2)",
|
||||||
|
"CoopShareTransaction(10002, 2022-10-20, CANCELLATION, 12, ref 10002-3)",
|
||||||
|
|
||||||
|
"CoopShareTransaction(10003, 2010-03-15, SUBSCRIPTION, 2, ref 10003-1)",
|
||||||
|
"CoopShareTransaction(10003, 2021-09-01, SUBSCRIPTION, 24, ref 10003-2)",
|
||||||
|
"CoopShareTransaction(10003, 2022-10-20, CANCELLATION, 12, ref 10003-3)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void normalUser_canViewOnlyRelatedCoopSharesTransactions() {
|
||||||
|
// given:
|
||||||
|
context("superuser-alex@hostsharing.net", "hs_office_partner#FirstGmbH-firstcontact.admin");
|
||||||
|
// "hs_office_person#FirstGmbH.admin",
|
||||||
|
|
||||||
|
// when:
|
||||||
|
final var result = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
// then:
|
||||||
|
exactlyTheseCoopSharesTransactionsAreReturned(
|
||||||
|
result,
|
||||||
|
"CoopShareTransaction(10001, 2010-03-15, SUBSCRIPTION, 2, ref 10001-1)",
|
||||||
|
"CoopShareTransaction(10001, 2021-09-01, SUBSCRIPTION, 24, ref 10001-2)",
|
||||||
|
"CoopShareTransaction(10001, 2022-10-20, CANCELLATION, 12, ref 10001-3)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void auditJournalLogIsAvailable() {
|
||||||
|
// given
|
||||||
|
final var query = em.createNativeQuery("""
|
||||||
|
select c.currenttask, j.targettable, j.targetop
|
||||||
|
from tx_journal j
|
||||||
|
join tx_context c on j.contextId = c.contextId
|
||||||
|
where targettable = 'hs_office_coopsharestransaction';
|
||||||
|
""");
|
||||||
|
|
||||||
|
// when
|
||||||
|
@SuppressWarnings("unchecked") final List<Object[]> customerLogEntries = query.getResultList();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(customerLogEntries).map(Arrays::toString).contains(
|
||||||
|
"[creating coopSharesTransaction test-data 10001, hs_office_coopsharestransaction, INSERT]",
|
||||||
|
"[creating coopSharesTransaction test-data 10002, hs_office_coopsharestransaction, INSERT]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
@AfterEach
|
||||||
|
void cleanup() {
|
||||||
|
jpaAttempt.transacted(() -> {
|
||||||
|
context("superuser-alex@hostsharing.net", null);
|
||||||
|
em.createQuery("DELETE FROM HsOfficeCoopSharesTransactionEntity WHERE reference like 'temp ref%'");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void exactlyTheseCoopSharesTransactionsAreReturned(
|
||||||
|
final List<HsOfficeCoopSharesTransactionEntity> actualResult,
|
||||||
|
final String... coopSharesTransactionNames) {
|
||||||
|
assertThat(actualResult)
|
||||||
|
.extracting(coopSharesTransactionEntity -> coopSharesTransactionEntity.toString())
|
||||||
|
.containsExactlyInAnyOrder(coopSharesTransactionNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
void allTheseCoopSharesTransactionsAreReturned(
|
||||||
|
final List<HsOfficeCoopSharesTransactionEntity> actualResult,
|
||||||
|
final String... coopSharesTransactionNames) {
|
||||||
|
assertThat(actualResult)
|
||||||
|
.extracting(coopSharesTransactionEntity -> coopSharesTransactionEntity.toString())
|
||||||
|
.contains(coopSharesTransactionNames);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user