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()
|
||||
.that().resideInAPackage("..hs.office.membership..")
|
||||
.should().onlyBeAccessed().byClassesThat()
|
||||
.resideInAnyPackage("..hs.office.membership..");
|
||||
.resideInAnyPackage("..hs.office.membership..", "..hs.office.coopshares..");
|
||||
|
||||
@ArchTest
|
||||
@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