memberNumber as partnerNumber+memberNumberSuffix #13

Merged
hsh-michaelhoennig merged 78 commits from memberNumberSuffix-and-partnerNumber into master 2024-01-24 15:57:16 +01:00
47 changed files with 789 additions and 423 deletions

View File

@ -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-spotless='./gradlew spotlessApply -x pitest -x test -x :processResources'
alias gw-test='. .aliases; ./gradlew test' alias gw-test='. .aliases; ./gradlew test'
alias gw-check='. .aliases; gw check -x pitest -x :dependencyCheckAnalyze'

View File

@ -53,12 +53,25 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, HasUu
@Column(name = "valuedate") @Column(name = "valuedate")
private LocalDate valueDate; private LocalDate valueDate;
/**
* The signed value which directly affects the booking balance.
*
* <p>This means, that a DEPOSIT is always positive, a DISBURSAL is always negative,
* but an ADJUSTMENT can bei either positive or negative.
* See {@link HsOfficeCoopAssetsTransactionType} for</p> more information.
*/
@Column(name = "assetvalue") @Column(name = "assetvalue")
private BigDecimal assetValue; private BigDecimal assetValue;
/**
* The booking reference.
*/
@Column(name = "reference") @Column(name = "reference")
private String reference; // TODO: what is this for? private String reference;
/**
* An optional arbitrary comment.
*/
@Column(name = "comment") @Column(name = "comment")
private String comment; private String comment;

View File

@ -17,7 +17,7 @@ public interface HsOfficeCoopAssetsTransactionRepository extends Repository<HsOf
WHERE ( CAST(:membershipUuid AS org.hibernate.type.UUIDCharType) IS NULL OR at.membership.uuid = :membershipUuid) WHERE ( CAST(:membershipUuid AS org.hibernate.type.UUIDCharType) IS NULL OR at.membership.uuid = :membershipUuid)
AND ( CAST(:fromValueDate AS java.time.LocalDate) IS NULL OR (at.valueDate >= :fromValueDate)) AND ( CAST(:fromValueDate AS java.time.LocalDate) IS NULL OR (at.valueDate >= :fromValueDate))
AND ( CAST(:toValueDate AS java.time.LocalDate)IS NULL OR (at.valueDate <= :toValueDate)) AND ( CAST(:toValueDate AS java.time.LocalDate)IS NULL OR (at.valueDate <= :toValueDate))
ORDER BY at.membership.memberNumber, at.valueDate ORDER BY at.membership.memberNumberSuffix, at.valueDate
""") """)
List<HsOfficeCoopAssetsTransactionEntity> findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange( List<HsOfficeCoopAssetsTransactionEntity> findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
UUID membershipUuid, LocalDate fromValueDate, LocalDate toValueDate); UUID membershipUuid, LocalDate fromValueDate, LocalDate toValueDate);

View File

@ -1,12 +1,43 @@
package net.hostsharing.hsadminng.hs.office.coopassets; package net.hostsharing.hsadminng.hs.office.coopassets;
public enum HsOfficeCoopAssetsTransactionType { public enum HsOfficeCoopAssetsTransactionType {
ADJUSTMENT, // correction of wrong bookings /**
DEPOSIT, // payment received from member after signing shares, >0 * correction of wrong bookings, value can be positive or negative
DISBURSAL, // payment send to member after cancellation of shares, <0 */
TRANSFER, // transferring shares to another member, <0 ADJUSTMENT,
ADOPTION, // receiving shares from another member, >0
CLEARING, // settlement with members dept, <0 /**
LOSS, // assignment of balance sheet loss in case of cancellation of shares, <0 * payment received from member after signing shares, value >0
LIMITATION // limitation period was reached after impossible disbursal, <0 */
DEPOSIT,
/**
* payment send to member after cancellation of shares, value <0
*/
DISBURSAL,
/**
* transferring shares to another member, value <0
*/
TRANSFER,
/**
* receiving shares from another member, value >0
*/
ADOPTION,
/**
* settlement with members dept, value <0
*/
CLEARING,
/**
* assignment of balance sheet loss in case of cancellation of shares, value <0
*/
LOSS,
/**
* limitation period was reached after impossible disbursal, value <0
*/
LIMITATION
} }

View File

@ -46,15 +46,28 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, HasUu
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
private HsOfficeCoopSharesTransactionType transactionType; private HsOfficeCoopSharesTransactionType transactionType;
/**
* The signed value which directly affects the booking balance.
*
* <p>This means, that a SUBSCRIPTION is always positive, a CANCELLATION is always negative,
* but an ADJUSTMENT can bei either positive or negative.
* See {@link HsOfficeCoopSharesTransactionType} for</p> more information.
*/
@Column(name = "valuedate") @Column(name = "valuedate")
private LocalDate valueDate; private LocalDate valueDate;
@Column(name = "sharecount") @Column(name = "sharecount")
private int shareCount; private int shareCount;
/**
* The Booking reference.
hsh-michaelhoennig marked this conversation as resolved Outdated
*/
@Column(name = "reference") @Column(name = "reference")
private String reference; // TODO: what is this for? private String reference;
/**
* An optional arbitrary comment.
*/
@Column(name = "comment") @Column(name = "comment")
private String comment; private String comment;
@ -69,6 +82,6 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, HasUu
@Override @Override
public String toShortString() { public String toShortString() {
return "%s%+d".formatted(getMemberNumber(), shareCount); return "M-%s%+d".formatted(getMemberNumber(), shareCount);
} }
} }

View File

@ -17,7 +17,7 @@ public interface HsOfficeCoopSharesTransactionRepository extends Repository<HsOf
WHERE ( CAST(:membershipUuid AS org.hibernate.type.UUIDCharType) IS NULL OR st.membership.uuid = :membershipUuid) WHERE ( CAST(:membershipUuid AS org.hibernate.type.UUIDCharType) IS NULL OR st.membership.uuid = :membershipUuid)
AND ( CAST(:fromValueDate AS java.time.LocalDate) IS NULL OR (st.valueDate >= :fromValueDate)) AND ( CAST(:fromValueDate AS java.time.LocalDate) IS NULL OR (st.valueDate >= :fromValueDate))
AND ( CAST(:toValueDate AS java.time.LocalDate)IS NULL OR (st.valueDate <= :toValueDate)) AND ( CAST(:toValueDate AS java.time.LocalDate)IS NULL OR (st.valueDate <= :toValueDate))
ORDER BY st.membership.memberNumber, st.valueDate ORDER BY st.membership.memberNumberSuffix, st.valueDate
""") """)
List<HsOfficeCoopSharesTransactionEntity> findCoopSharesTransactionByOptionalMembershipUuidAndDateRange( List<HsOfficeCoopSharesTransactionEntity> findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
UUID membershipUuid, LocalDate fromValueDate, LocalDate toValueDate); UUID membershipUuid, LocalDate fromValueDate, LocalDate toValueDate);

View File

@ -1,7 +1,18 @@
package net.hostsharing.hsadminng.hs.office.coopshares; package net.hostsharing.hsadminng.hs.office.coopshares;
public enum HsOfficeCoopSharesTransactionType { public enum HsOfficeCoopSharesTransactionType {
ADJUSTMENT, // correction of wrong bookings /**
SUBSCRIPTION, // shares signed, e.g. with the declaration of accession, >0 * correction of wrong bookings, with either positive or negative value
CANCELLATION; // shares terminated, e.g. when a membership is resigned, <0 */
ADJUSTMENT,
/**
* shares signed, e.g. with the declaration of accession, value >0
*/
SUBSCRIPTION,
/**
* shares terminated, e.g. when a membership is resigned, value <0
*/
CANCELLATION;
} }

View File

@ -26,12 +26,14 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
@DisplayName("Debitor") @DisplayName("Debitor")
public class HsOfficeDebitorEntity implements HasUuid, Stringifyable { 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: // TODO: I would rather like to generate something matching this example:
// debitor(1234500: Test AG, tes) // debitor(1234500: Test AG, tes)
// maybe remove withSepararator (always use ', ') and add withBusinessIdProp (with ': ' afterwards)? // maybe remove withSepararator (always use ', ') and add withBusinessIdProp (with ': ' afterwards)?
private static Stringify<HsOfficeDebitorEntity> stringify = private static Stringify<HsOfficeDebitorEntity> stringify =
stringify(HsOfficeDebitorEntity.class, "debitor") stringify(HsOfficeDebitorEntity.class, "debitor")
.withProp(HsOfficeDebitorEntity::getDebitorNumber) .withProp(e -> DEBITOR_NUMBER_TAG + e.getDebitorNumber())
.withProp(HsOfficeDebitorEntity::getPartner) .withProp(HsOfficeDebitorEntity::getPartner)
.withProp(HsOfficeDebitorEntity::getDefaultPrefix) .withProp(HsOfficeDebitorEntity::getDefaultPrefix)
.withSeparator(": ") .withSeparator(": ")
@ -75,18 +77,11 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
@Column(name = "defaultprefix", columnDefinition = "char(3) not null") @Column(name = "defaultprefix", columnDefinition = "char(3) not null")
private String defaultPrefix; private String defaultPrefix;
public String getDebitorNumberString() { private String getDebitorNumberString() {
// TODO: refactor if (partner == null || partner.getPartnerNumber() == null || debitorNumberSuffix == null ) {
if (partner.getDebitorNumberPrefix() == null ) { return null;
if (debitorNumberSuffix == null) {
return null;
}
return String.format("%02d", debitorNumberSuffix);
} }
if (debitorNumberSuffix == null) { return partner.getPartnerNumber() + String.format("%02d", debitorNumberSuffix);
return partner.getDebitorNumberPrefix() + "??";
}
return partner.getDebitorNumberPrefix() + String.format("%02d", debitorNumberSuffix);
} }
public Integer getDebitorNumber() { public Integer getDebitorNumber() {
@ -100,6 +95,6 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
@Override @Override
public String toShortString() { public String toShortString() {
return getDebitorNumberString(); return DEBITOR_NUMBER_TAG + getDebitorNumberString();
} }
} }

View File

@ -13,10 +13,10 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt
@Query(""" @Query("""
SELECT debitor FROM HsOfficeDebitorEntity debitor SELECT debitor FROM HsOfficeDebitorEntity debitor
WHERE cast(debitor.partner.debitorNumberPrefix as integer) = :debitorNumberPrefix WHERE cast(debitor.partner.partnerNumber as integer) = :partnerNumber
AND cast(debitor.debitorNumberSuffix as integer) = :debitorNumberSuffix AND cast(debitor.debitorNumberSuffix as integer) = :debitorNumberSuffix
""") """)
List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int debitorNumberPrefix, byte debitorNumberSuffix); List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int partnerNumber, byte debitorNumberSuffix);
default List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int debitorNumber) { default List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int debitorNumber) {
return findDebitorByDebitorNumber( debitorNumber/100, (byte) (debitorNumber%100)); return findDebitorByDebitorNumber( debitorNumber/100, (byte) (debitorNumber%100));

View File

@ -44,8 +44,9 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
Integer memberNumber) { Integer memberNumber) {
context.define(currentUser, assumedRoles); context.define(currentUser, assumedRoles);
final var entities = final var entities = ( memberNumber != null)
membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(partnerUuid, memberNumber); ? List.of(membershipRepo.findMembershipByMemberNumber(memberNumber))
: membershipRepo.findMembershipsByOptionalPartnerUuid(partnerUuid);
final var resources = mapper.mapList(entities, HsOfficeMembershipResource.class, final var resources = mapper.mapList(entities, HsOfficeMembershipResource.class,
SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER); SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER);

View File

@ -30,8 +30,10 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
@DisplayName("Membership") @DisplayName("Membership")
public class HsOfficeMembershipEntity implements HasUuid, Stringifyable { public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
public static final String MEMBER_NUMBER_TAG = "M-";
private static Stringify<HsOfficeMembershipEntity> stringify = stringify(HsOfficeMembershipEntity.class) private static Stringify<HsOfficeMembershipEntity> stringify = stringify(HsOfficeMembershipEntity.class)
.withProp(HsOfficeMembershipEntity::getMemberNumber) .withProp(e -> MEMBER_NUMBER_TAG + e.getMemberNumber())
.withProp(e -> e.getPartner().toShortString()) .withProp(e -> e.getPartner().toShortString())
.withProp(e -> e.getMainDebitor().toShortString()) .withProp(e -> e.getMainDebitor().toShortString())
.withProp(e -> e.getValidity().asString()) .withProp(e -> e.getValidity().asString())
@ -52,8 +54,8 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
@JoinColumn(name = "maindebitoruuid") @JoinColumn(name = "maindebitoruuid")
private HsOfficeDebitorEntity mainDebitor; private HsOfficeDebitorEntity mainDebitor;
@Column(name = "membernumber") @Column(name = "membernumbersuffix", length = 2)
private int memberNumber; // TODO: migrate to suffix, like debitorNumberSuffix private String memberNumberSuffix;
@Column(name = "validity", columnDefinition = "daterange") @Column(name = "validity", columnDefinition = "daterange")
@Type(PostgreSQLRangeType.class) @Type(PostgreSQLRangeType.class)
@ -82,14 +84,19 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
return upperInclusiveFromPostgresDateRange(getValidity()); return upperInclusiveFromPostgresDateRange(getValidity());
} }
public Range<LocalDate> getValidity() { public Range<LocalDate> getValidity() {
if (validity == null) { if (validity == null) {
validity = Range.infinite(LocalDate.class); validity = Range.infinite(LocalDate.class);
} }
;
return validity; return validity;
} }
public Integer getMemberNumber() {
if (partner == null || partner.getPartnerNumber() == null || memberNumberSuffix == null ) {
return null;
}
return getPartner().getPartnerNumber() * 100 + Integer.parseInt(memberNumberSuffix, 10);
}
@Override @Override
public String toString() { public String toString() {
@ -98,7 +105,7 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
@Override @Override
public String toShortString() { public String toShortString() {
return String.valueOf(memberNumber); return "M-" + getMemberNumber();
} }
@PrePersist @PrePersist

View File

@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.hs.office.membership;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import jakarta.validation.constraints.NotNull;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@ -11,16 +12,30 @@ public interface HsOfficeMembershipRepository extends Repository<HsOfficeMembers
Optional<HsOfficeMembershipEntity> findByUuid(UUID id); Optional<HsOfficeMembershipEntity> findByUuid(UUID id);
HsOfficeMembershipEntity save(final HsOfficeMembershipEntity entity);
@Query(""" @Query("""
SELECT membership FROM HsOfficeMembershipEntity membership SELECT membership FROM HsOfficeMembershipEntity membership
WHERE (:memberNumber is null OR membership.memberNumber = :memberNumber) WHERE ( CAST(:partnerUuid as org.hibernate.type.UUIDCharType) IS NULL
AND ( CAST(:partnerUuid as org.hibernate.type.UUIDCharType) IS NULL OR membership.partner.uuid = :partnerUuid )
OR membership.partner.uuid = :partnerUuid ) ORDER BY membership.partner.partnerNumber, membership.memberNumberSuffix
ORDER BY membership.memberNumber
""") """)
List<HsOfficeMembershipEntity> findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(UUID partnerUuid, Integer memberNumber); List<HsOfficeMembershipEntity> findMembershipsByOptionalPartnerUuid(UUID partnerUuid);
@Query("""
HsOfficeMembershipEntity save(final HsOfficeMembershipEntity entity); SELECT membership FROM HsOfficeMembershipEntity membership
WHERE (:partnerNumber = membership.partner.partnerNumber)
AND (membership.memberNumberSuffix = :suffix)
ORDER BY membership.memberNumberSuffix
""")
HsOfficeMembershipEntity findMembershipByPartnerNumberAndSuffix(
@NotNull Integer partnerNumber,
@NotNull String suffix);
default HsOfficeMembershipEntity findMembershipByMemberNumber(Integer memberNumber) {
final var partnerNumber = memberNumber / 100;
final var suffix = memberNumber % 100;
return findMembershipByPartnerNumberAndSuffix(partnerNumber, String.format("%02d", suffix));
}
long count(); long count();

View File

@ -36,8 +36,8 @@ public class HsOfficePartnerEntity implements Stringifyable, HasUuid {
@GeneratedValue @GeneratedValue
private UUID uuid; private UUID uuid;
@Column(name = "debitornumberprefix", columnDefinition = "numeric(5) not null") @Column(name = "partnernumber", columnDefinition = "numeric(5) not null")
private Integer debitorNumberPrefix; private Integer partnerNumber;
@ManyToOne @ManyToOne
@JoinColumn(name = "personuuid", nullable = false) @JoinColumn(name = "personuuid", nullable = false)

View File

@ -23,6 +23,7 @@ public interface HsOfficePartnerRepository extends Repository<HsOfficePartnerEnt
OR person.familyName like concat(cast(:name as text), '%') OR person.familyName like concat(cast(:name as text), '%')
""") """)
List<HsOfficePartnerEntity> findPartnerByOptionalNameLike(String name); List<HsOfficePartnerEntity> findPartnerByOptionalNameLike(String name);
HsOfficePartnerEntity findPartnerByPartnerNumber(Integer partnerNumber);
HsOfficePartnerEntity save(final HsOfficePartnerEntity entity); HsOfficePartnerEntity save(final HsOfficePartnerEntity entity);

View File

@ -25,6 +25,13 @@ components:
$ref: './hs-office-debitor-schemas.yaml#/components/schemas/HsOfficeDebitor' $ref: './hs-office-debitor-schemas.yaml#/components/schemas/HsOfficeDebitor'
memberNumber: memberNumber:
type: integer type: integer
minimum: 1000000
maximum: 9999999
memberNumberSuffix:
type: string
minLength: 2
maxLength: 2
pattern: '[0-9]+'
validFrom: validFrom:
type: string type: string
format: date format: date
@ -66,8 +73,11 @@ components:
type: string type: string
format: uuid format: uuid
nullable: false nullable: false
memberNumber: memberNumberSuffix:
type: integer type: string
minLength: 2
maxLength: 2
pattern: '[0-9]+'
nullable: false nullable: false
validFrom: validFrom:
type: string type: string
@ -84,6 +94,7 @@ components:
type: boolean type: boolean
required: required:
- partnerUuid - partnerUuid
- memberNumberSuffix
- mainDebitorUuid - mainDebitorUuid
- validFrom - validFrom
- membershipFeeBillable - membershipFeeBillable

View File

@ -1,6 +1,7 @@
get: get:
summary: Returns a list of (optionally filtered) memberships. 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: tags:
- hs-office-memberships - hs-office-memberships
operationId: listMemberships operationId: listMemberships
@ -13,13 +14,13 @@ get:
schema: schema:
type: string type: string
format: uuid format: uuid
description: UUID of the business partner. description: UUID of the business partner, exclusive to `memberNumber`.
- name: memberNumber - name: memberNumber
in: query in: query
required: false required: false
schema: schema:
type: integer type: integer
description: Member number. description: Member number, exclusive to `partnerUuid`.
responses: responses:
"200": "200":
description: OK description: OK

View File

@ -9,7 +9,7 @@ components:
uuid: uuid:
type: string type: string
format: uuid format: uuid
debitorNumberPrefix: partnerNumber:
type: integer type: integer
format: int8 format: int8
minimum: 10000 minimum: 10000
@ -91,7 +91,7 @@ components:
HsOfficePartnerInsert: HsOfficePartnerInsert:
type: object type: object
properties: properties:
debitorNumberPrefix: partnerNumber:
type: integer type: integer
format: int8 format: int8
minimum: 10000 minimum: 10000
@ -105,7 +105,7 @@ components:
details: details:
$ref: '#/components/schemas/HsOfficePartnerDetailsInsert' $ref: '#/components/schemas/HsOfficePartnerDetailsInsert'
required: required:
- debitorNumberPrefix - partnerNumber
- personUuid - personUuid
- contactUuid - contactUuid
- details - details

View File

@ -32,7 +32,7 @@ call create_journal('hs_office_partner_details');
create table hs_office_partner create table hs_office_partner
( (
uuid uuid unique references RbacObject (uuid) initially deferred, uuid uuid unique references RbacObject (uuid) initially deferred,
debitorNumberPrefix varchar(5), partnerNumber numeric(5),
personUuid uuid not null references hs_office_person(uuid), personUuid uuid not null references hs_office_person(uuid),
contactUuid uuid not null references hs_office_contact(uuid), contactUuid uuid not null references hs_office_contact(uuid),
detailsUuid uuid not null references hs_office_partner_details(uuid) on delete cascade detailsUuid uuid not null references hs_office_partner_details(uuid) on delete cascade

View File

@ -165,8 +165,7 @@ execute procedure hsOfficePartnerRbacRolesTrigger();
--changeset hs-office-partner-rbac-IDENTITY-VIEW:1 endDelimiter:--// --changeset hs-office-partner-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacIdentityView('hs_office_partner', $idName$ call generateRbacIdentityView('hs_office_partner', $idName$
-- TODO: simplify by using just debitorNumberPrefix for the essential part partnerNumber || ':' ||
debitorNumberPrefix || ':' ||
(select idName from hs_office_person_iv p where p.uuid = target.personuuid) (select idName from hs_office_person_iv p where p.uuid = target.personuuid)
|| '-' || || '-' ||
(select idName from hs_office_contact_iv c where c.uuid = target.contactuuid) (select idName from hs_office_contact_iv c where c.uuid = target.contactuuid)
@ -180,7 +179,6 @@ call generateRbacIdentityView('hs_office_partner', $idName$
call generateRbacRestrictedView('hs_office_partner', call generateRbacRestrictedView('hs_office_partner',
'(select idName from hs_office_person_iv p where p.uuid = target.personUuid)', '(select idName from hs_office_person_iv p where p.uuid = target.personUuid)',
$updates$ $updates$
debitorNumberPrefix = new.debitorNumberPrefix,
personUuid = new.personUuid, personUuid = new.personUuid,
hsh-michaelhoennig marked this conversation as resolved Outdated

entfernen, nicht sinnvoll

entfernen, nicht sinnvoll
contactUuid = new.contactUuid contactUuid = new.contactUuid
$updates$); $updates$);

View File

@ -9,7 +9,7 @@
Creates a single partner test record. Creates a single partner test record.
*/ */
create or replace procedure createHsOfficePartnerTestData( create or replace procedure createHsOfficePartnerTestData(
debitorNumberPrefix numeric(5), partnerNumber numeric(5),
personTradeOrFamilyName varchar, personTradeOrFamilyName varchar,
contactLabel varchar ) contactLabel varchar )
language plpgsql as $$ language plpgsql as $$
@ -49,8 +49,8 @@ begin
end if; end if;
insert insert
into hs_office_partner (uuid, debitorNumberPrefix, personuuid, contactuuid, detailsUuid) into hs_office_partner (uuid, partnerNumber, personuuid, contactuuid, detailsUuid)
values (uuid_generate_v4(), debitorNumberPrefix, relatedPerson.uuid, relatedContact.uuid, relatedDetailsUuid); values (uuid_generate_v4(), partnerNumber, relatedPerson.uuid, relatedContact.uuid, relatedDetailsUuid);
end; $$; end; $$;
--// --//

View File

@ -173,7 +173,7 @@ execute procedure hsOfficeDebitorRbacRolesTrigger();
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacIdentityView('hs_office_debitor', $idName$ call generateRbacIdentityView('hs_office_debitor', $idName$
'#' || '#' ||
(select debitornumberprefix from hs_office_partner p where p.uuid = target.partnerUuid) || (select partnerNumber from hs_office_partner p where p.uuid = target.partnerUuid) ||
to_char(debitorNumberSuffix, 'fm00') || to_char(debitorNumberSuffix, 'fm00') ||
':' || (select split_part(idName, ':', 2) from hs_office_partner_iv pi where pi.uuid = target.partnerUuid) ':' || (select split_part(idName, ':', 2) from hs_office_partner_iv pi where pi.uuid = target.partnerUuid)
$idName$); $idName$);

View File

@ -13,10 +13,13 @@ create table if not exists hs_office_membership
uuid uuid unique references RbacObject (uuid) initially deferred, uuid uuid unique references RbacObject (uuid) initially deferred,
partnerUuid uuid not null references hs_office_partner(uuid), partnerUuid uuid not null references hs_office_partner(uuid),
mainDebitorUuid uuid not null references hs_office_debitor(uuid), mainDebitorUuid uuid not null references hs_office_debitor(uuid),
memberNumber numeric(5) not null unique, memberNumberSuffix char(2) not null check (
hsh-michaelhoennig marked this conversation as resolved

add unique constraint mit partnerNumber

add unique constraint mit partnerNumber
memberNumberSuffix::text ~ '^[0-9][0-9]$'),
validity daterange not null, validity daterange not null,
reasonForTermination HsOfficeReasonForTermination not null default 'NONE', reasonForTermination HsOfficeReasonForTermination not null default 'NONE',
membershipFeeBillable boolean not null default true membershipFeeBillable boolean not null default true,
UNIQUE(partnerUuid, memberNumberSuffix)
); );
--// --//

View File

@ -92,7 +92,9 @@ execute procedure hsOfficeMembershipRbacRolesTrigger();
--changeset hs-office-membership-rbac-IDENTITY-VIEW:1 endDelimiter:--// --changeset hs-office-membership-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacIdentityView('hs_office_membership', idNameExpression => $idName$ call generateRbacIdentityView('hs_office_membership', idNameExpression => $idName$
target.memberNumber || '#' ||
(select partnerNumber from hs_office_partner p where p.uuid = target.partnerUuid) ||
memberNumberSuffix ||
':' || (select split_part(idName, ':', 2) from hs_office_partner_iv p where p.uuid = target.partnerUuid) ':' || (select split_part(idName, ':', 2) from hs_office_partner_iv p where p.uuid = target.partnerUuid)
$idName$); $idName$);
--// --//
@ -102,7 +104,7 @@ call generateRbacIdentityView('hs_office_membership', idNameExpression => $idNam
--changeset hs-office-membership-rbac-RESTRICTED-VIEW:1 endDelimiter:--// --changeset hs-office-membership-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacRestrictedView('hs_office_membership', call generateRbacRestrictedView('hs_office_membership',
orderby => 'target.memberNumber', orderby => 'target.memberNumberSuffix',
columnUpdates => $updates$ columnUpdates => $updates$
validity = new.validity, validity = new.validity,
reasonForTermination = new.reasonForTermination, reasonForTermination = new.reasonForTermination,

View File

@ -8,16 +8,18 @@
/* /*
Creates a single membership test record. Creates a single membership test record.
*/ */
create or replace procedure createHsOfficeMembershipTestData( forPartnerTradeName varchar, forMainDebitorNumber numeric ) create or replace procedure createHsOfficeMembershipTestData(
forPartnerTradeName varchar,
forMainDebitorNumberSuffix numeric,
newMemberNumberSuffix char(2) )
language plpgsql as $$ language plpgsql as $$
declare declare
currentTask varchar; currentTask varchar;
idName varchar; idName varchar;
relatedPartner hs_office_partner; relatedPartner hs_office_partner;
relatedDebitor hs_office_debitor; relatedDebitor hs_office_debitor;
newMemberNumber numeric;
begin begin
idName := cleanIdentifier( forPartnerTradeName || '#' || forMainDebitorNumber); idName := cleanIdentifier( forPartnerTradeName || '#' || forMainDebitorNumberSuffix);
currentTask := 'creating Membership test-data ' || idName; currentTask := 'creating Membership test-data ' || idName;
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin'); call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
execute format('set local hsadminng.currentTask to %L', currentTask); execute format('set local hsadminng.currentTask to %L', currentTask);
@ -25,15 +27,17 @@ begin
select partner.* from hs_office_partner partner select partner.* from hs_office_partner partner
join hs_office_person person on person.uuid = partner.personUuid join hs_office_person person on person.uuid = partner.personUuid
where person.tradeName = forPartnerTradeName into relatedPartner; where person.tradeName = forPartnerTradeName into relatedPartner;
select d.* from hs_office_debitor d where d.debitorNumberSuffix = forMainDebitorNumber into relatedDebitor; select d.* from hs_office_debitor d
select coalesce(max(memberNumber)+1, 10001) from hs_office_membership into newMemberNumber; where d.partneruuid = relatedPartner.uuid
and d.debitorNumberSuffix = forMainDebitorNumberSuffix
into relatedDebitor;
raise notice 'creating test Membership: %', idName; raise notice 'creating test Membership: %', idName;
raise notice '- using partner (%): %', relatedPartner.uuid, relatedPartner; raise notice '- using partner (%): %', relatedPartner.uuid, relatedPartner;
raise notice '- using debitor (%): %', relatedDebitor.uuid, relatedDebitor; raise notice '- using debitor (%): %', relatedDebitor.uuid, relatedDebitor;
insert insert
into hs_office_membership (uuid, partneruuid, maindebitoruuid, membernumber, validity, reasonfortermination) into hs_office_membership (uuid, partneruuid, maindebitoruuid, memberNumberSuffix, validity, reasonfortermination)
values (uuid_generate_v4(), relatedPartner.uuid, relatedDebitor.uuid, newMemberNumber, daterange('20221001' , null, '[]'), 'NONE'); values (uuid_generate_v4(), relatedPartner.uuid, relatedDebitor.uuid, newMemberNumberSuffix, daterange('20221001' , null, '[]'), 'NONE');
end; $$; end; $$;
--// --//
@ -44,9 +48,9 @@ end; $$;
do language plpgsql $$ do language plpgsql $$
begin begin
call createHsOfficeMembershipTestData('First GmbH', 11); call createHsOfficeMembershipTestData('First GmbH', 11, '01');
call createHsOfficeMembershipTestData('Second e.K.', 12); call createHsOfficeMembershipTestData('Second e.K.', 12, '02');
call createHsOfficeMembershipTestData('Third OHG', 13); call createHsOfficeMembershipTestData('Third OHG', 13, '03');
end; end;
$$; $$;
--// --//

View File

@ -8,25 +8,33 @@
/* /*
Creates a single coopSharesTransaction test record. Creates a single coopSharesTransaction test record.
*/ */
create or replace procedure createHsOfficeCoopSharesTransactionTestData(givenMembershipNumber numeric) create or replace procedure createHsOfficeCoopSharesTransactionTestData(
givenPartnerNumber numeric,
givenMemberNumberSuffix char(2)
)
language plpgsql as $$ language plpgsql as $$
declare declare
currentTask varchar; currentTask varchar;
membership hs_office_membership; membership hs_office_membership;
begin begin
currentTask = 'creating coopSharesTransaction test-data ' || givenMembershipNumber; currentTask = 'creating coopSharesTransaction test-data ' || givenPartnerNumber::text || givenMemberNumberSuffix;
execute format('set local hsadminng.currentTask to %L', currentTask); execute format('set local hsadminng.currentTask to %L', currentTask);
call defineContext(currentTask); call defineContext(currentTask);
select m.uuid from hs_office_membership m where m.memberNumber = givenMembershipNumber into membership; select m.uuid
from hs_office_membership m
join hs_office_partner p on p.uuid = m.partneruuid
where p.partnerNumber = givenPartnerNumber
and m.memberNumberSuffix = givenMemberNumberSuffix
into membership;
raise notice 'creating test coopSharesTransaction: %', givenMembershipNumber; raise notice 'creating test coopSharesTransaction: %', givenPartnerNumber::text || givenMemberNumberSuffix;
insert insert
into hs_office_coopsharestransaction(uuid, membershipuuid, transactiontype, valuedate, sharecount, reference, comment) into hs_office_coopsharestransaction(uuid, membershipuuid, transactiontype, valuedate, sharecount, reference, comment)
values values
(uuid_generate_v4(), membership.uuid, 'SUBSCRIPTION', '2010-03-15', 4, 'ref '||givenMembershipNumber||'-1', 'initial subscription'), (uuid_generate_v4(), membership.uuid, 'SUBSCRIPTION', '2010-03-15', 4, 'ref '||givenPartnerNumber::text || givenMemberNumberSuffix||'-1', 'initial subscription'),
(uuid_generate_v4(), membership.uuid, 'CANCELLATION', '2021-09-01', -2, 'ref '||givenMembershipNumber||'-2', 'cancelling some'), (uuid_generate_v4(), membership.uuid, 'CANCELLATION', '2021-09-01', -2, 'ref '||givenPartnerNumber::text || givenMemberNumberSuffix||'-2', 'cancelling some'),
(uuid_generate_v4(), membership.uuid, 'ADJUSTMENT', '2022-10-20', 2, 'ref '||givenMembershipNumber||'-3', 'some adjustment'); (uuid_generate_v4(), membership.uuid, 'ADJUSTMENT', '2022-10-20', 2, 'ref '||givenPartnerNumber::text || givenMemberNumberSuffix||'-3', 'some adjustment');
end; $$; end; $$;
--// --//
@ -37,8 +45,8 @@ end; $$;
do language plpgsql $$ do language plpgsql $$
begin begin
call createHsOfficeCoopSharesTransactionTestData(10001); call createHsOfficeCoopSharesTransactionTestData(10001, '01');
call createHsOfficeCoopSharesTransactionTestData(10002); call createHsOfficeCoopSharesTransactionTestData(10002, '02');
call createHsOfficeCoopSharesTransactionTestData(10003); call createHsOfficeCoopSharesTransactionTestData(10003, '03');
end; end;
$$; $$;

View File

@ -8,25 +8,33 @@
/* /*
Creates a single coopAssetsTransaction test record. Creates a single coopAssetsTransaction test record.
*/ */
create or replace procedure createHsOfficeCoopAssetsTransactionTestData(givenMembershipNumber numeric) create or replace procedure createHsOfficeCoopAssetsTransactionTestData(
givenPartnerNumber numeric,
givenMemberNumberSuffix char(2)
)
language plpgsql as $$ language plpgsql as $$
declare declare
currentTask varchar; currentTask varchar;
membership hs_office_membership; membership hs_office_membership;
begin begin
currentTask = 'creating coopAssetsTransaction test-data ' || givenMembershipNumber; currentTask = 'creating coopAssetsTransaction test-data ' || givenPartnerNumber || givenMemberNumberSuffix;
execute format('set local hsadminng.currentTask to %L', currentTask); execute format('set local hsadminng.currentTask to %L', currentTask);
call defineContext(currentTask); call defineContext(currentTask);
select m.uuid from hs_office_membership m where m.memberNumber = givenMembershipNumber into membership; select m.uuid
from hs_office_membership m
join hs_office_partner p on p.uuid = m.partneruuid
where p.partnerNumber = givenPartnerNumber
and m.memberNumberSuffix = givenMemberNumberSuffix
into membership;
raise notice 'creating test coopAssetsTransaction: %', givenMembershipNumber; raise notice 'creating test coopAssetsTransaction: %', givenPartnerNumber || givenMemberNumberSuffix;
insert insert
into hs_office_coopassetstransaction(uuid, membershipuuid, transactiontype, valuedate, assetvalue, reference, comment) into hs_office_coopassetstransaction(uuid, membershipuuid, transactiontype, valuedate, assetvalue, reference, comment)
values values
(uuid_generate_v4(), membership.uuid, 'DEPOSIT', '2010-03-15', 320.00, 'ref '||givenMembershipNumber||'-1', 'initial deposit'), (uuid_generate_v4(), membership.uuid, 'DEPOSIT', '2010-03-15', 320.00, 'ref '||givenPartnerNumber || givenMemberNumberSuffix||'-1', 'initial deposit'),
(uuid_generate_v4(), membership.uuid, 'DISBURSAL', '2021-09-01', -128.00, 'ref '||givenMembershipNumber||'-2', 'partial disbursal'), (uuid_generate_v4(), membership.uuid, 'DISBURSAL', '2021-09-01', -128.00, 'ref '||givenPartnerNumber || givenMemberNumberSuffix||'-2', 'partial disbursal'),
(uuid_generate_v4(), membership.uuid, 'ADJUSTMENT', '2022-10-20', 128.00, 'ref '||givenMembershipNumber||'-3', 'some adjustment'); (uuid_generate_v4(), membership.uuid, 'ADJUSTMENT', '2022-10-20', 128.00, 'ref '||givenPartnerNumber || givenMemberNumberSuffix||'-3', 'some adjustment');
end; $$; end; $$;
--// --//
@ -37,8 +45,8 @@ end; $$;
do language plpgsql $$ do language plpgsql $$
begin begin
call createHsOfficeCoopAssetsTransactionTestData(10001); call createHsOfficeCoopAssetsTransactionTestData(10001, '01');
call createHsOfficeCoopAssetsTransactionTestData(10002); call createHsOfficeCoopAssetsTransactionTestData(10002, '02');
call createHsOfficeCoopAssetsTransactionTestData(10003); call createHsOfficeCoopAssetsTransactionTestData(10003, '03');
end; end;
$$; $$;

View File

@ -75,8 +75,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest {
void globalAdmin_canFindCoopAssetsTransactionsByMemberNumber() { void globalAdmin_canFindCoopAssetsTransactionsByMemberNumber() {
hsh-michaelhoennig marked this conversation as resolved Outdated

ohne "Suffix" im Namen

ohne "Suffix" im Namen
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002) final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202);
.get(0);
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -93,21 +92,21 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest {
"transactionType": "DEPOSIT", "transactionType": "DEPOSIT",
"assetValue": 320.00, "assetValue": 320.00,
"valueDate": "2010-03-15", "valueDate": "2010-03-15",
"reference": "ref 10002-1", "reference": "ref 1000202-1",
"comment": "initial deposit" "comment": "initial deposit"
}, },
{ {
"transactionType": "DISBURSAL", "transactionType": "DISBURSAL",
"assetValue": -128.00, "assetValue": -128.00,
"valueDate": "2021-09-01", "valueDate": "2021-09-01",
"reference": "ref 10002-2", "reference": "ref 1000202-2",
"comment": "partial disbursal" "comment": "partial disbursal"
}, },
{ {
"transactionType": "ADJUSTMENT", "transactionType": "ADJUSTMENT",
"assetValue": 128.00, "assetValue": 128.00,
"valueDate": "2022-10-20", "valueDate": "2022-10-20",
"reference": "ref 10002-3", "reference": "ref 1000202-3",
"comment": "some adjustment" "comment": "some adjustment"
} }
] ]
@ -115,11 +114,10 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest {
} }
@Test @Test
void globalAdmin_canFindCoopAssetsTransactionsByMemberNumberAndDateRange() { void globalAdmin_canFindCoopAssetsTransactionsByMembershipUuidAndDateRange() {
hsh-michaelhoennig marked this conversation as resolved Outdated

ohne "Suffix" im Namen

ohne "Suffix" im Namen
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002) final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202);
.get(0);
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -137,7 +135,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest {
"transactionType": "DISBURSAL", "transactionType": "DISBURSAL",
"assetValue": -128.00, "assetValue": -128.00,
"valueDate": "2021-09-01", "valueDate": "2021-09-01",
"reference": "ref 10002-2", "reference": "ref 1000202-2",
"comment": "partial disbursal" "comment": "partial disbursal"
} }
] ]
@ -153,8 +151,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest {
void globalAdmin_canAddCoopAssetsTransaction() { void globalAdmin_canAddCoopAssetsTransaction() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001) final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101);
.get(0);
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
@ -199,8 +196,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest {
void globalAdmin_canNotCancelMoreAssetsThanCurrentlySubscribed() { void globalAdmin_canNotCancelMoreAssetsThanCurrentlySubscribed() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001) final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101);
.get(0);
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()

View File

@ -23,14 +23,14 @@ class HsOfficeCoopAssetsTransactionEntityUnitTest {
void toStringContainsAlmostAllPropertiesAccount() { void toStringContainsAlmostAllPropertiesAccount() {
final var result = givenCoopAssetTransaction.toString(); final var result = givenCoopAssetTransaction.toString();
assertThat(result).isEqualTo("CoopAssetsTransaction(300001, 2020-01-01, DEPOSIT, 128.00, some-ref)"); assertThat(result).isEqualTo("CoopAssetsTransaction(1000101, 2020-01-01, DEPOSIT, 128.00, some-ref)");
} }
@Test @Test
void toShortStringContainsOnlyMemberNumberAndSharesCountOnly() { void toShortStringContainsOnlyMemberNumberSuffixAndSharesCountOnly() {
final var result = givenCoopAssetTransaction.toShortString(); final var result = givenCoopAssetTransaction.toShortString();
assertThat(result).isEqualTo("300001+128.00"); assertThat(result).isEqualTo("1000101+128.00");
} }
@Test @Test

View File

@ -62,8 +62,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var count = coopAssetsTransactionRepo.count(); final var count = coopAssetsTransactionRepo.count();
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001) final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101);
.get(0);
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
@ -96,9 +95,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
// when // when
attempt(em, () -> { attempt(em, () -> {
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber( final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101);
null,
10001).get(0);
final var newCoopAssetsTransaction = HsOfficeCoopAssetsTransactionEntity.builder() final var newCoopAssetsTransaction = HsOfficeCoopAssetsTransactionEntity.builder()
.membership(givenMembership) .membership(givenMembership)
.transactionType(HsOfficeCoopAssetsTransactionType.DEPOSIT) .transactionType(HsOfficeCoopAssetsTransactionType.DEPOSIT)
@ -117,7 +114,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
.map(s -> s.replace("hs_office_", "")) .map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted( .containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames, initialGrantNames,
"{ grant perm view on coopassetstransaction#temprefB to role membership#10001:....tenant by system and assume }", "{ grant perm view on coopassetstransaction#temprefB to role membership#1000101:....tenant by system and assume }",
null)); null));
} }
@ -144,25 +141,24 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
// then // then
allTheseCoopAssetsTransactionsAreReturned( allTheseCoopAssetsTransactionsAreReturned(
result, result,
"CoopAssetsTransaction(10001, 2010-03-15, DEPOSIT, 320.00, ref 10001-1, initial deposit)", "CoopAssetsTransaction(1000101, 2010-03-15, DEPOSIT, 320.00, ref 1000101-1, initial deposit)",
"CoopAssetsTransaction(10001, 2021-09-01, DISBURSAL, -128.00, ref 10001-2, partial disbursal)", "CoopAssetsTransaction(1000101, 2021-09-01, DISBURSAL, -128.00, ref 1000101-2, partial disbursal)",
"CoopAssetsTransaction(10001, 2022-10-20, ADJUSTMENT, 128.00, ref 10001-3, some adjustment)", "CoopAssetsTransaction(1000101, 2022-10-20, ADJUSTMENT, 128.00, ref 1000101-3, some adjustment)",
"CoopAssetsTransaction(10002, 2010-03-15, DEPOSIT, 320.00, ref 10002-1, initial deposit)", "CoopAssetsTransaction(1000202, 2010-03-15, DEPOSIT, 320.00, ref 1000202-1, initial deposit)",
"CoopAssetsTransaction(10002, 2021-09-01, DISBURSAL, -128.00, ref 10002-2, partial disbursal)", "CoopAssetsTransaction(1000202, 2021-09-01, DISBURSAL, -128.00, ref 1000202-2, partial disbursal)",
"CoopAssetsTransaction(10002, 2022-10-20, ADJUSTMENT, 128.00, ref 10002-3, some adjustment)", "CoopAssetsTransaction(1000202, 2022-10-20, ADJUSTMENT, 128.00, ref 1000202-3, some adjustment)",
"CoopAssetsTransaction(10003, 2010-03-15, DEPOSIT, 320.00, ref 10003-1, initial deposit)", "CoopAssetsTransaction(1000303, 2010-03-15, DEPOSIT, 320.00, ref 1000303-1, initial deposit)",
"CoopAssetsTransaction(10003, 2021-09-01, DISBURSAL, -128.00, ref 10003-2, partial disbursal)", "CoopAssetsTransaction(1000303, 2021-09-01, DISBURSAL, -128.00, ref 1000303-2, partial disbursal)",
"CoopAssetsTransaction(10003, 2022-10-20, ADJUSTMENT, 128.00, ref 10003-3, some adjustment)"); "CoopAssetsTransaction(1000303, 2022-10-20, ADJUSTMENT, 128.00, ref 1000303-3, some adjustment)");
} }
@Test @Test
public void globalAdmin_canViewCoopAssetsTransactions_filteredByMembershipUuid() { public void globalAdmin_canViewCoopAssetsTransactions_filteredByMembershipUuid() {
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002) final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202);
.get(0);
// when // when
final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange( final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
@ -173,17 +169,16 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
// then // then
allTheseCoopAssetsTransactionsAreReturned( allTheseCoopAssetsTransactionsAreReturned(
result, result,
"CoopAssetsTransaction(10002, 2010-03-15, DEPOSIT, 320.00, ref 10002-1, initial deposit)", "CoopAssetsTransaction(1000202, 2010-03-15, DEPOSIT, 320.00, ref 1000202-1, initial deposit)",
"CoopAssetsTransaction(10002, 2021-09-01, DISBURSAL, -128.00, ref 10002-2, partial disbursal)", "CoopAssetsTransaction(1000202, 2021-09-01, DISBURSAL, -128.00, ref 1000202-2, partial disbursal)",
"CoopAssetsTransaction(10002, 2022-10-20, ADJUSTMENT, 128.00, ref 10002-3, some adjustment)"); "CoopAssetsTransaction(1000202, 2022-10-20, ADJUSTMENT, 128.00, ref 1000202-3, some adjustment)");
} }
@Test @Test
public void globalAdmin_canViewCoopAssetsTransactions_filteredByMembershipUuidAndValueDateRange() { public void globalAdmin_canViewCoopAssetsTransactions_filteredByMembershipUuidAndValueDateRange() {
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002) final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202);
.get(0);
// when // when
final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange( final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
@ -194,7 +189,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
// then // then
allTheseCoopAssetsTransactionsAreReturned( allTheseCoopAssetsTransactionsAreReturned(
result, result,
"CoopAssetsTransaction(10002, 2021-09-01, DISBURSAL, -128.00, ref 10002-2, partial disbursal)"); "CoopAssetsTransaction(1000202, 2021-09-01, DISBURSAL, -128.00, ref 1000202-2, partial disbursal)");
} }
@Test @Test
@ -211,9 +206,9 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
// then: // then:
exactlyTheseCoopAssetsTransactionsAreReturned( exactlyTheseCoopAssetsTransactionsAreReturned(
result, result,
"CoopAssetsTransaction(10001, 2010-03-15, DEPOSIT, 320.00, ref 10001-1, initial deposit)", "CoopAssetsTransaction(1000101, 2010-03-15, DEPOSIT, 320.00, ref 1000101-1, initial deposit)",
"CoopAssetsTransaction(10001, 2021-09-01, DISBURSAL, -128.00, ref 10001-2, partial disbursal)", "CoopAssetsTransaction(1000101, 2021-09-01, DISBURSAL, -128.00, ref 1000101-2, partial disbursal)",
"CoopAssetsTransaction(10001, 2022-10-20, ADJUSTMENT, 128.00, ref 10001-3, some adjustment)"); "CoopAssetsTransaction(1000101, 2022-10-20, ADJUSTMENT, 128.00, ref 1000101-3, some adjustment)");
} }
} }
@ -232,8 +227,8 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
// then // then
assertThat(customerLogEntries).map(Arrays::toString).contains( assertThat(customerLogEntries).map(Arrays::toString).contains(
"[creating coopAssetsTransaction test-data 10001, hs_office_coopassetstransaction, INSERT]", "[creating coopAssetsTransaction test-data 1000101, hs_office_coopassetstransaction, INSERT]",
"[creating coopAssetsTransaction test-data 10002, hs_office_coopassetstransaction, INSERT]"); "[creating coopAssetsTransaction test-data 1000202, hs_office_coopassetstransaction, INSERT]");
} }
@BeforeEach @BeforeEach

View File

@ -75,7 +75,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest {
void globalAdmin_canFindCoopSharesTransactionsByMemberNumber() { void globalAdmin_canFindCoopSharesTransactionsByMemberNumber() {
hsh-michaelhoennig marked this conversation as resolved Outdated

ohne "Suffix" im Namen

ohne "Suffix" im Namen
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002).get(0); final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202);
RestAssured // @formatter:off 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(""" .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("""
@ -84,21 +84,21 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest {
"transactionType": "SUBSCRIPTION", "transactionType": "SUBSCRIPTION",
"shareCount": 4, "shareCount": 4,
"valueDate": "2010-03-15", "valueDate": "2010-03-15",
"reference": "ref 10002-1", "reference": "ref 1000202-1",
"comment": "initial subscription" "comment": "initial subscription"
}, },
{ {
"transactionType": "CANCELLATION", "transactionType": "CANCELLATION",
"shareCount": -2, "shareCount": -2,
"valueDate": "2021-09-01", "valueDate": "2021-09-01",
"reference": "ref 10002-2", "reference": "ref 1000202-2",
"comment": "cancelling some" "comment": "cancelling some"
}, },
{ {
"transactionType": "ADJUSTMENT", "transactionType": "ADJUSTMENT",
"shareCount": 2, "shareCount": 2,
"valueDate": "2022-10-20", "valueDate": "2022-10-20",
"reference": "ref 10002-3", "reference": "ref 1000202-3",
"comment": "some adjustment" "comment": "some adjustment"
} }
] ]
@ -106,19 +106,20 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest {
} }
@Test @Test
void globalAdmin_canFindCoopSharesTransactionsByMemberNumberAndDateRange() { void globalAdmin_canFindCoopSharesTransactionsByMembershipUuidAndDateRange() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002).get(0); final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202);
RestAssured // @formatter:off 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(""" .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("""
[ [
{ {
"transactionType": "CANCELLATION", "transactionType": "CANCELLATION",
"shareCount": -2, "shareCount": -2,
"valueDate": "2021-09-01", "valueDate": "2021-09-01",
"reference": "ref 10002-2", "reference": "ref 1000202-2",
"comment": "cancelling some" "comment": "cancelling some"
} }
] ]
@ -134,7 +135,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest {
void globalAdmin_canAddCoopSharesTransaction() { void globalAdmin_canAddCoopSharesTransaction() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001).get(0); final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101);
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given().header("current-user", "superuser-alex@hostsharing.net").contentType(ContentType.JSON).body(""" .given().header("current-user", "superuser-alex@hostsharing.net").contentType(ContentType.JSON).body("""
@ -165,7 +166,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest {
void globalAdmin_canNotCancelMoreSharesThanCurrentlySubscribed() { void globalAdmin_canNotCancelMoreSharesThanCurrentlySubscribed() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001).get(0); final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101);
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given().header("current-user", "superuser-alex@hostsharing.net").contentType(ContentType.JSON).body(""" .given().header("current-user", "superuser-alex@hostsharing.net").contentType(ContentType.JSON).body("""

View File

@ -22,14 +22,14 @@ class HsOfficeCoopSharesTransactionEntityUnitTest {
void toStringContainsAlmostAllPropertiesAccount() { void toStringContainsAlmostAllPropertiesAccount() {
final var result = givenCoopSharesTransaction.toString(); final var result = givenCoopSharesTransaction.toString();
assertThat(result).isEqualTo("CoopShareTransaction(300001, 2020-01-01, SUBSCRIPTION, 4, some-ref)"); assertThat(result).isEqualTo("CoopShareTransaction(1000101, 2020-01-01, SUBSCRIPTION, 4, some-ref)");
} }
@Test @Test
void toShortStringContainsOnlyMemberNumberAndShareCountOnly() { void toShortStringContainsOnlyMemberNumberAndShareCountOnly() {
final var result = givenCoopSharesTransaction.toShortString(); final var result = givenCoopSharesTransaction.toShortString();
assertThat(result).isEqualTo("300001+4"); assertThat(result).isEqualTo("M-1000101+4");
} }
@Test @Test
@ -43,6 +43,6 @@ class HsOfficeCoopSharesTransactionEntityUnitTest {
void toShortStringEmptyTransactionDoesNotThrowException() { void toShortStringEmptyTransactionDoesNotThrowException() {
final var result = givenEmptyCoopSharesTransaction.toShortString(); final var result = givenEmptyCoopSharesTransaction.toShortString();
assertThat(result).isEqualTo("null+0"); assertThat(result).isEqualTo("M-null+0");
} }
} }

View File

@ -61,8 +61,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var count = coopSharesTransactionRepo.count(); final var count = coopSharesTransactionRepo.count();
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001) final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101);
.get(0);
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
@ -95,9 +94,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
// when // when
attempt(em, () -> { attempt(em, () -> {
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber( final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000101);
null,
10001).get(0);
final var newCoopSharesTransaction = HsOfficeCoopSharesTransactionEntity.builder() final var newCoopSharesTransaction = HsOfficeCoopSharesTransactionEntity.builder()
.membership(givenMembership) .membership(givenMembership)
.transactionType(HsOfficeCoopSharesTransactionType.SUBSCRIPTION) .transactionType(HsOfficeCoopSharesTransactionType.SUBSCRIPTION)
@ -116,7 +113,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
.map(s -> s.replace("hs_office_", "")) .map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted( .containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames, 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)); null));
} }
@ -143,25 +140,24 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
// then // then
allTheseCoopSharesTransactionsAreReturned( allTheseCoopSharesTransactionsAreReturned(
result, result,
"CoopShareTransaction(10001, 2010-03-15, SUBSCRIPTION, 4, ref 10001-1, initial subscription)", "CoopShareTransaction(1000101, 2010-03-15, SUBSCRIPTION, 4, ref 1000101-1, initial subscription)",
"CoopShareTransaction(10001, 2021-09-01, CANCELLATION, -2, ref 10001-2, cancelling some)", "CoopShareTransaction(1000101, 2021-09-01, CANCELLATION, -2, ref 1000101-2, cancelling some)",
"CoopShareTransaction(10001, 2022-10-20, ADJUSTMENT, 2, ref 10001-3, some adjustment)", "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(1000202, 2010-03-15, SUBSCRIPTION, 4, ref 1000202-1, initial subscription)",
"CoopShareTransaction(10002, 2021-09-01, CANCELLATION, -2, ref 10002-2, cancelling some)", "CoopShareTransaction(1000202, 2021-09-01, CANCELLATION, -2, ref 1000202-2, cancelling some)",
"CoopShareTransaction(10002, 2022-10-20, ADJUSTMENT, 2, ref 10002-3, some adjustment)", "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(1000303, 2010-03-15, SUBSCRIPTION, 4, ref 1000303-1, initial subscription)",
"CoopShareTransaction(10003, 2021-09-01, CANCELLATION, -2, ref 10003-2, cancelling some)", "CoopShareTransaction(1000303, 2021-09-01, CANCELLATION, -2, ref 1000303-2, cancelling some)",
"CoopShareTransaction(10003, 2022-10-20, ADJUSTMENT, 2, ref 10003-3, some adjustment)"); "CoopShareTransaction(1000303, 2022-10-20, ADJUSTMENT, 2, ref 1000303-3, some adjustment)");
} }
@Test @Test
public void globalAdmin_canViewCoopSharesTransactions_filteredByMembershipUuid() { public void globalAdmin_canViewCoopSharesTransactions_filteredByMembershipUuid() {
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002) final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202);
.get(0);
// when // when
final var result = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange( final var result = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
@ -172,17 +168,16 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
// then // then
allTheseCoopSharesTransactionsAreReturned( allTheseCoopSharesTransactionsAreReturned(
result, result,
"CoopShareTransaction(10002, 2010-03-15, SUBSCRIPTION, 4, ref 10002-1, initial subscription)", "CoopShareTransaction(1000202, 2010-03-15, SUBSCRIPTION, 4, ref 1000202-1, initial subscription)",
"CoopShareTransaction(10002, 2021-09-01, CANCELLATION, -2, ref 10002-2, cancelling some)", "CoopShareTransaction(1000202, 2021-09-01, CANCELLATION, -2, ref 1000202-2, cancelling some)",
"CoopShareTransaction(10002, 2022-10-20, ADJUSTMENT, 2, ref 10002-3, some adjustment)"); "CoopShareTransaction(1000202, 2022-10-20, ADJUSTMENT, 2, ref 1000202-3, some adjustment)");
} }
@Test @Test
public void globalAdmin_canViewCoopSharesTransactions_filteredByMembershipUuidAndValueDateRange() { public void globalAdmin_canViewCoopSharesTransactions_filteredByMembershipUuidAndValueDateRange() {
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002) final var givenMembership = membershipRepo.findMembershipByMemberNumber(1000202);
.get(0);
// when // when
final var result = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange( final var result = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
@ -193,7 +188,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
// then // then
allTheseCoopSharesTransactionsAreReturned( allTheseCoopSharesTransactionsAreReturned(
result, 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 @Test
@ -210,9 +205,9 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
// then: // then:
exactlyTheseCoopSharesTransactionsAreReturned( exactlyTheseCoopSharesTransactionsAreReturned(
result, result,
"CoopShareTransaction(10001, 2010-03-15, SUBSCRIPTION, 4, ref 10001-1, initial subscription)", "CoopShareTransaction(1000101, 2010-03-15, SUBSCRIPTION, 4, ref 1000101-1, initial subscription)",
"CoopShareTransaction(10001, 2021-09-01, CANCELLATION, -2, ref 10001-2, cancelling some)", "CoopShareTransaction(1000101, 2021-09-01, CANCELLATION, -2, ref 1000101-2, cancelling some)",
"CoopShareTransaction(10001, 2022-10-20, ADJUSTMENT, 2, ref 10001-3, some adjustment)"); "CoopShareTransaction(1000101, 2022-10-20, ADJUSTMENT, 2, ref 1000101-3, some adjustment)");
} }
} }
@ -231,8 +226,8 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
// then // then
assertThat(customerLogEntries).map(Arrays::toString).contains( assertThat(customerLogEntries).map(Arrays::toString).contains(
"[creating coopSharesTransaction test-data 10001, hs_office_coopsharestransaction, INSERT]", "[creating coopSharesTransaction test-data 1000101, hs_office_coopsharestransaction, INSERT]",
"[creating coopSharesTransaction test-data 10002, hs_office_coopsharestransaction, INSERT]"); "[creating coopSharesTransaction test-data 1000202, hs_office_coopsharestransaction, INSERT]");
} }
@BeforeEach @BeforeEach

View File

@ -21,7 +21,7 @@ class HsOfficeDebitorEntityUnitTest {
.tradeName("some trade name") .tradeName("some trade name")
.build()) .build())
.details(HsOfficePartnerDetailsEntity.builder().birthName("some birth name").build()) .details(HsOfficePartnerDetailsEntity.builder().birthName("some birth name").build())
.debitorNumberPrefix(12345) .partnerNumber(12345)
.build()) .build())
.billingContact(HsOfficeContactEntity.builder().label("some label").build()) .billingContact(HsOfficeContactEntity.builder().label("some label").build())
.defaultPrefix("som") .defaultPrefix("som")
@ -29,7 +29,7 @@ class HsOfficeDebitorEntityUnitTest {
final var result = given.toString(); final var result = given.toString();
assertThat(result).isEqualTo("debitor(1234567: LP some trade name: som)"); assertThat(result).isEqualTo("debitor(D-1234567: LP some trade name: som)");
} }
@Test @Test
@ -39,27 +39,81 @@ class HsOfficeDebitorEntityUnitTest {
.partner(HsOfficePartnerEntity.builder() .partner(HsOfficePartnerEntity.builder()
.person(null) .person(null)
.details(HsOfficePartnerDetailsEntity.builder().birthName("some birth name").build()) .details(HsOfficePartnerDetailsEntity.builder().birthName("some birth name").build())
.debitorNumberPrefix(12345) .partnerNumber(12345)
.build()) .build())
.billingContact(HsOfficeContactEntity.builder().label("some label").build()) .billingContact(HsOfficeContactEntity.builder().label("some label").build())
.build(); .build();
final var result = given.toString(); final var result = given.toString();
assertThat(result).isEqualTo("debitor(1234567: <person=null>)"); assertThat(result).isEqualTo("debitor(D-1234567: <person=null>)");
} }
@Test @Test
void toShortStringContainsDebitorNumber() { void toShortStringContainsDebitorNumber() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.partner(HsOfficePartnerEntity.builder() .partner(HsOfficePartnerEntity.builder()
.debitorNumberPrefix(12345) .partnerNumber(12345)
.build()) .build())
.debitorNumberSuffix((byte)67) .debitorNumberSuffix((byte)67)
.build(); .build();
final var result = given.toShortString(); 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();
} }
} }

View File

@ -211,9 +211,9 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
// then // then
allTheseDebitorsAreReturned( allTheseDebitorsAreReturned(
result, result,
"debitor(1000111: LP First GmbH: fir)", "debitor(D-1000111: LP First GmbH: fir)",
"debitor(1000212: LP Second e.K.: sec)", "debitor(D-1000212: LP Second e.K.: sec)",
"debitor(1000313: IF Third OHG: thi)"); "debitor(D-1000313: IF Third OHG: thi)");
} }
@ParameterizedTest @ParameterizedTest
@ -231,8 +231,8 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
// then: // then:
exactlyTheseDebitorsAreReturned(result, exactlyTheseDebitorsAreReturned(result,
"debitor(1000111: LP First GmbH: fir)", "debitor(D-1000111: LP First GmbH: fir)",
"debitor(1000120: LP First GmbH: fif)"); "debitor(D-1000120: LP First GmbH: fif)");
} }
@Test @Test
@ -260,7 +260,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
final var result = debitorRepo.findDebitorByDebitorNumber(1000313); final var result = debitorRepo.findDebitorByDebitorNumber(1000313);
// then // then
exactlyTheseDebitorsAreReturned(result, "debitor(1000313: IF Third OHG: thi)"); exactlyTheseDebitorsAreReturned(result, "debitor(D-1000313: IF Third OHG: thi)");
} }
} }
@ -276,7 +276,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
final var result = debitorRepo.findDebitorByOptionalNameLike("third contact"); final var result = debitorRepo.findDebitorByOptionalNameLike("third contact");
// then // then
exactlyTheseDebitorsAreReturned(result, "debitor(1000313: IF Third OHG: thi)"); exactlyTheseDebitorsAreReturned(result, "debitor(D-1000313: IF Third OHG: thi)");
} }
} }

View File

@ -11,7 +11,6 @@ import net.hostsharing.test.Accepts;
import net.hostsharing.test.JpaAttempt; import net.hostsharing.test.JpaAttempt;
import org.json.JSONException; import org.json.JSONException;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -37,6 +36,8 @@ import static org.hamcrest.Matchers.*;
@Transactional @Transactional
class HsOfficeMembershipControllerAcceptanceTest { class HsOfficeMembershipControllerAcceptanceTest {
private static String TEMP_MEMBER_NUMBER_SUFFIX = "90";
@LocalServerPort @LocalServerPort
private Integer port; private Integer port;
@ -61,8 +62,6 @@ class HsOfficeMembershipControllerAcceptanceTest {
@PersistenceContext @PersistenceContext
EntityManager em; EntityManager em;
private static int tempMemberNumber = 20010;
@Nested @Nested
@Accepts({ "Membership:F(Find)" }) @Accepts({ "Membership:F(Find)" })
class ListMemberships { class ListMemberships {
@ -84,7 +83,8 @@ class HsOfficeMembershipControllerAcceptanceTest {
{ {
"partner": { "person": { "tradeName": "First GmbH" } }, "partner": { "person": { "tradeName": "First GmbH" } },
"mainDebitor": { "debitorNumber": 1000111 }, "mainDebitor": { "debitorNumber": 1000111 },
"memberNumber": 10001, "memberNumber": 1000101,
"memberNumberSuffix": "01",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
"reasonForTermination": "NONE" "reasonForTermination": "NONE"
@ -92,7 +92,8 @@ class HsOfficeMembershipControllerAcceptanceTest {
{ {
"partner": { "person": { "tradeName": "Second e.K." } }, "partner": { "person": { "tradeName": "Second e.K." } },
"mainDebitor": { "debitorNumber": 1000212 }, "mainDebitor": { "debitorNumber": 1000212 },
"memberNumber": 10002, "memberNumber": 1000202,
"memberNumberSuffix": "02",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
"reasonForTermination": "NONE" "reasonForTermination": "NONE"
@ -100,7 +101,8 @@ class HsOfficeMembershipControllerAcceptanceTest {
{ {
"partner": { "person": { "tradeName": "Third OHG" } }, "partner": { "person": { "tradeName": "Third OHG" } },
"mainDebitor": { "debitorNumber": 1000313 }, "mainDebitor": { "debitorNumber": 1000313 },
"memberNumber": 10003, "memberNumber": 1000303,
"memberNumberSuffix": "03",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
"reasonForTermination": "NONE" "reasonForTermination": "NONE"
@ -109,6 +111,67 @@ class HsOfficeMembershipControllerAcceptanceTest {
""")); """));
// @formatter:on // @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 @Nested
@ -121,6 +184,8 @@ class HsOfficeMembershipControllerAcceptanceTest {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Third").get(0); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Third").get(0);
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("Third").get(0); final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("Third").get(0);
final var givenMemberSuffix = TEMP_MEMBER_NUMBER_SUFFIX;
final var expectedMemberNumber = Integer.parseInt(givenPartner.getPartnerNumber() + TEMP_MEMBER_NUMBER_SUFFIX);
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
@ -130,11 +195,11 @@ class HsOfficeMembershipControllerAcceptanceTest {
{ {
"partnerUuid": "%s", "partnerUuid": "%s",
"mainDebitorUuid": "%s", "mainDebitorUuid": "%s",
"memberNumber": 20001, "memberNumberSuffix": "%s",
"validFrom": "2022-10-13", "validFrom": "2022-10-13",
"membershipFeeBillable": "true" "membershipFeeBillable": "true"
} }
""".formatted(givenPartner.getUuid(), givenDebitor.getUuid())) """.formatted(givenPartner.getUuid(), givenDebitor.getUuid(), givenMemberSuffix))
.port(port) .port(port)
.when() .when()
.post("http://localhost/api/hs/office/memberships") .post("http://localhost/api/hs/office/memberships")
@ -145,7 +210,8 @@ class HsOfficeMembershipControllerAcceptanceTest {
.body("mainDebitor.debitorNumber", is(givenDebitor.getDebitorNumber())) .body("mainDebitor.debitorNumber", is(givenDebitor.getDebitorNumber()))
.body("mainDebitor.debitorNumberSuffix", is((int) givenDebitor.getDebitorNumberSuffix())) .body("mainDebitor.debitorNumberSuffix", is((int) givenDebitor.getDebitorNumberSuffix()))
.body("partner.person.tradeName", is("Third OHG")) .body("partner.person.tradeName", is("Third OHG"))
.body("memberNumber", is(20001)) .body("memberNumber", is(expectedMemberNumber))
.body("memberNumberSuffix", is(givenMemberSuffix))
.body("validFrom", is("2022-10-13")) .body("validFrom", is("2022-10-13"))
.body("validTo", equalTo(null)) .body("validTo", equalTo(null))
.header("Location", startsWith("http://localhost")) .header("Location", startsWith("http://localhost"))
@ -166,11 +232,7 @@ class HsOfficeMembershipControllerAcceptanceTest {
@Test @Test
void globalAdmin_canGetArbitraryMembership() { void globalAdmin_canGetArbitraryMembership() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembershipUuid = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber( final var givenMembershipUuid = membershipRepo.findMembershipByMemberNumber(1000101).getUuid();
null,
10001)
.get(0)
.getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -185,7 +247,8 @@ class HsOfficeMembershipControllerAcceptanceTest {
{ {
"partner": { "person": { "tradeName": "First GmbH" } }, "partner": { "person": { "tradeName": "First GmbH" } },
"mainDebitor": { "debitorNumber": 1000111 }, "mainDebitor": { "debitorNumber": 1000111 },
"memberNumber": 10001, "memberNumber": 1000101,
"memberNumberSuffix": "01",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
"reasonForTermination": "NONE" "reasonForTermination": "NONE"
@ -197,11 +260,7 @@ class HsOfficeMembershipControllerAcceptanceTest {
@Accepts({ "Membership:X(Access Control)" }) @Accepts({ "Membership:X(Access Control)" })
void normalUser_canNotGetUnrelatedMembership() { void normalUser_canNotGetUnrelatedMembership() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembershipUuid = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber( final var givenMembershipUuid = membershipRepo.findMembershipByMemberNumber(1000101).getUuid();
null,
10001)
.get(0)
.getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -217,11 +276,7 @@ class HsOfficeMembershipControllerAcceptanceTest {
@Accepts({ "Membership:X(Access Control)" }) @Accepts({ "Membership:X(Access Control)" })
void debitorAgentUser_canGetRelatedMembership() { void debitorAgentUser_canGetRelatedMembership() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembershipUuid = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber( final var givenMembershipUuid = membershipRepo.findMembershipByMemberNumber(1000303).getUuid();
null,
10003)
.get(0)
.getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -240,7 +295,8 @@ class HsOfficeMembershipControllerAcceptanceTest {
"debitorNumber": 1000313, "debitorNumber": 1000313,
"billingContact": { "label": "third contact" } "billingContact": { "label": "third contact" }
}, },
"memberNumber": 10003, "memberNumber": 1000303,
"memberNumberSuffix": "03",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
"reasonForTermination": "NONE" "reasonForTermination": "NONE"
@ -279,7 +335,8 @@ class HsOfficeMembershipControllerAcceptanceTest {
.body("partner.person.tradeName", is(givenMembership.getPartner().getPerson().getTradeName())) .body("partner.person.tradeName", is(givenMembership.getPartner().getPerson().getTradeName()))
.body("mainDebitor.debitorNumber", is(givenMembership.getMainDebitor().getDebitorNumber())) .body("mainDebitor.debitorNumber", is(givenMembership.getMainDebitor().getDebitorNumber()))
.body("mainDebitor.debitorNumberSuffix", is((int) givenMembership.getMainDebitor().getDebitorNumberSuffix())) .body("mainDebitor.debitorNumberSuffix", is((int) givenMembership.getMainDebitor().getDebitorNumberSuffix()))
.body("memberNumber", is(givenMembership.getMemberNumber())) .body("mainDebitor.debitorNumberSuffix", is((int) givenMembership.getMainDebitor().getDebitorNumberSuffix()))
.body("memberNumberSuffix", is(givenMembership.getMemberNumberSuffix()))
.body("validFrom", is("2022-11-01")) .body("validFrom", is("2022-11-01"))
.body("validTo", is("2023-12-31")) .body("validTo", is("2023-12-31"))
.body("reasonForTermination", is("CANCELLATION")); .body("reasonForTermination", is("CANCELLATION"));
@ -290,7 +347,7 @@ class HsOfficeMembershipControllerAcceptanceTest {
.matches(mandate -> { .matches(mandate -> {
assertThat(mandate.getPartner().toShortString()).isEqualTo("LP First GmbH"); assertThat(mandate.getPartner().toShortString()).isEqualTo("LP First GmbH");
assertThat(mandate.getMainDebitor().toString()).isEqualTo(givenMembership.getMainDebitor().toString()); assertThat(mandate.getMainDebitor().toString()).isEqualTo(givenMembership.getMainDebitor().toString());
assertThat(mandate.getMemberNumber()).isEqualTo(givenMembership.getMemberNumber()); assertThat(mandate.getMemberNumberSuffix()).isEqualTo(givenMembership.getMemberNumberSuffix());
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2024-01-01)"); assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2024-01-01)");
assertThat(mandate.getReasonForTermination()).isEqualTo(HsOfficeReasonForTermination.CANCELLATION); assertThat(mandate.getReasonForTermination()).isEqualTo(HsOfficeReasonForTermination.CANCELLATION);
return true; return true;
@ -322,7 +379,7 @@ class HsOfficeMembershipControllerAcceptanceTest {
.body("uuid", isUuidValid()) .body("uuid", isUuidValid())
.body("partner.person.tradeName", is(givenMembership.getPartner().getPerson().getTradeName())) .body("partner.person.tradeName", is(givenMembership.getPartner().getPerson().getTradeName()))
.body("mainDebitor.debitorNumber", is(1000313)) .body("mainDebitor.debitorNumber", is(1000313))
.body("memberNumber", is(givenMembership.getMemberNumber())) .body("memberNumberSuffix", is(givenMembership.getMemberNumberSuffix()))
.body("validFrom", is("2022-11-01")) .body("validFrom", is("2022-11-01"))
.body("validTo", nullValue()) .body("validTo", nullValue())
.body("reasonForTermination", is("NONE")); .body("reasonForTermination", is("NONE"));
@ -333,7 +390,7 @@ class HsOfficeMembershipControllerAcceptanceTest {
.matches(mandate -> { .matches(mandate -> {
assertThat(mandate.getPartner().toShortString()).isEqualTo("LP First GmbH"); assertThat(mandate.getPartner().toShortString()).isEqualTo("LP First GmbH");
assertThat(mandate.getMainDebitor().toString()).isEqualTo(givenMembership.getMainDebitor().toString()); assertThat(mandate.getMainDebitor().toString()).isEqualTo(givenMembership.getMainDebitor().toString());
assertThat(mandate.getMemberNumber()).isEqualTo(givenMembership.getMemberNumber()); assertThat(mandate.getMemberNumberSuffix()).isEqualTo(givenMembership.getMemberNumberSuffix());
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,)"); assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,)");
assertThat(mandate.getReasonForTermination()).isEqualTo(NONE); assertThat(mandate.getReasonForTermination()).isEqualTo(NONE);
return true; return true;
@ -444,7 +501,7 @@ class HsOfficeMembershipControllerAcceptanceTest {
.uuid(UUID.randomUUID()) .uuid(UUID.randomUUID())
.partner(givenPartner) .partner(givenPartner)
.mainDebitor(givenDebitor) .mainDebitor(givenDebitor)
.memberNumber(++tempMemberNumber) .memberNumberSuffix(TEMP_MEMBER_NUMBER_SUFFIX)
.validity(Range.closedInfinite(LocalDate.parse("2022-11-01"))) .validity(Range.closedInfinite(LocalDate.parse("2022-11-01")))
.reasonForTermination(NONE) .reasonForTermination(NONE)
.membershipFeeBillable(true) .membershipFeeBillable(true)
@ -454,13 +511,15 @@ class HsOfficeMembershipControllerAcceptanceTest {
}).assertSuccessful().returnedValue(); }).assertSuccessful().returnedValue();
} }
@BeforeEach
@AfterEach @AfterEach
void cleanup() { void cleanup() {
jpaAttempt.transacted(() -> { jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null); context.define("superuser-alex@hostsharing.net", null);
final var query = em.createQuery("DELETE FROM HsOfficeMembershipEntity m WHERE m.memberNumber >= 20000"); final var query = em.createQuery(
"DELETE FROM HsOfficeMembershipEntity m WHERE m.memberNumberSuffix >= '%s'"
.formatted(TEMP_MEMBER_NUMBER_SUFFIX)
);
query.executeUpdate(); query.executeUpdate();
}); }).assertSuccessful();
} }
} }

View File

@ -6,7 +6,10 @@ import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.hsadminng.mapper.Mapper; import net.hostsharing.hsadminng.mapper.Mapper;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; 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.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
@ -22,6 +25,7 @@ import jakarta.persistence.SynchronizationType;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -59,119 +63,166 @@ public class HsOfficeMembershipControllerRestTest {
when(emf.createEntityManager(any(SynchronizationType.class), any(Map.class))).thenReturn(em); when(emf.createEntityManager(any(SynchronizationType.class), any(Map.class))).thenReturn(em);
} }
@Test @Nested
void respondBadRequest_ifPartnerUuidIsMissing() throws Exception { class AddMembership {
@Test
void respondBadRequest_ifPartnerUuidIsMissing() throws Exception {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/memberships") .post("/api/hs/office/memberships")
.header("current-user", "superuser-alex@hostsharing.net") .header("current-user", "superuser-alex@hostsharing.net")
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
"partnerUuid": null, "partnerUuid": null,
"mainDebitorUuid": "%s", "mainDebitorUuid": "%s",
"memberNumber": 20001, "memberNumberSuffix": "01",
"validFrom": "2022-10-13", "validFrom": "2022-10-13",
"membershipFeeBillable": "true" "membershipFeeBillable": "true"
} }
""".formatted(UUID.randomUUID())) """.formatted(UUID.randomUUID()))
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
// then // then
.andExpect(status().is4xxClientError()) .andExpect(status().is4xxClientError())
.andExpect(jsonPath("statusCode", is(400))) .andExpect(jsonPath("statusCode", is(400)))
.andExpect(jsonPath("statusPhrase", is("Bad Request"))) .andExpect(jsonPath("statusPhrase", is("Bad Request")))
.andExpect(jsonPath("message", is("[partnerUuid must not be null but is \"null\"]"))); .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,
"memberNumber": 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",
"memberNumber": 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",
"memberNumber": 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)));
}
} }

View File

@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.hs.office.membership; package net.hostsharing.hsadminng.hs.office.membership;
import com.vladmihalcea.hibernate.type.range.Range; import com.vladmihalcea.hibernate.type.range.Range;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import jakarta.persistence.PrePersist; import jakarta.persistence.PrePersist;
@ -17,7 +18,7 @@ class HsOfficeMembershipEntityUnitTest {
public static final LocalDate GIVEN_VALID_FROM = LocalDate.parse("2020-01-01"); public static final LocalDate GIVEN_VALID_FROM = LocalDate.parse("2020-01-01");
final HsOfficeMembershipEntity givenMembership = HsOfficeMembershipEntity.builder() final HsOfficeMembershipEntity givenMembership = HsOfficeMembershipEntity.builder()
.memberNumber(10001) .memberNumberSuffix("01")
.partner(TEST_PARTNER) .partner(TEST_PARTNER)
.mainDebitor(TEST_DEBITOR) .mainDebitor(TEST_DEBITOR)
.validity(Range.closedInfinite(GIVEN_VALID_FROM)) .validity(Range.closedInfinite(GIVEN_VALID_FROM))
@ -26,15 +27,47 @@ class HsOfficeMembershipEntityUnitTest {
@Test @Test
void toStringContainsAllProps() { void toStringContainsAllProps() {
final var result = givenMembership.toString(); final var result = givenMembership.toString();
assertThat(result).isEqualTo("Membership(M-1000101, LP Test Ltd., D-1000100, [2020-01-01,))");
assertThat(result).isEqualTo("Membership(10001, LP Test Ltd., 1000100, [2020-01-01,))");
} }
@Test @Test
void toShortStringContainsMemberNumberOnly() { void toShortStringContainsMemberNumberSuffixOnly() {
final var result = givenMembership.toShortString(); final var result = givenMembership.toShortString();
assertThat(result).isEqualTo("M-1000101");
}
assertThat(result).isEqualTo("10001"); @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 @Test

View File

@ -77,7 +77,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
final var newMembership = toCleanup(HsOfficeMembershipEntity.builder() final var newMembership = toCleanup(HsOfficeMembershipEntity.builder()
.memberNumber(20001) .memberNumberSuffix("11")
.partner(givenPartner) .partner(givenPartner)
.mainDebitor(givenDebitor) .mainDebitor(givenDebitor)
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01"))) .validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))
@ -108,7 +108,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0);
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0); final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0);
final var newMembership = toCleanup(HsOfficeMembershipEntity.builder() final var newMembership = toCleanup(HsOfficeMembershipEntity.builder()
.memberNumber(20002) .memberNumberSuffix("07")
.partner(givenPartner) .partner(givenPartner)
.mainDebitor(givenDebitor) .mainDebitor(givenDebitor)
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01"))) .validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))
@ -121,11 +121,11 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
final var all = rawRoleRepo.findAll(); final var all = rawRoleRepo.findAll();
assertThat(roleNamesOf(all)).containsExactlyInAnyOrder(Array.from( assertThat(roleNamesOf(all)).containsExactlyInAnyOrder(Array.from(
initialRoleNames, initialRoleNames,
"hs_office_membership#20002:FirstGmbH-firstcontact.admin", "hs_office_membership#1000107:FirstGmbH-firstcontact.admin",
"hs_office_membership#20002:FirstGmbH-firstcontact.agent", "hs_office_membership#1000107:FirstGmbH-firstcontact.agent",
"hs_office_membership#20002:FirstGmbH-firstcontact.guest", "hs_office_membership#1000107:FirstGmbH-firstcontact.guest",
"hs_office_membership#20002:FirstGmbH-firstcontact.owner", "hs_office_membership#1000107:FirstGmbH-firstcontact.owner",
"hs_office_membership#20002:FirstGmbH-firstcontact.tenant")); "hs_office_membership#1000107:FirstGmbH-firstcontact.tenant"));
assertThat(grantDisplaysOf(rawGrantRepo.findAll())) assertThat(grantDisplaysOf(rawGrantRepo.findAll()))
.map(s -> s.replace("GmbH-firstcontact", "")) .map(s -> s.replace("GmbH-firstcontact", ""))
.map(s -> s.replace("hs_office_", "")) .map(s -> s.replace("hs_office_", ""))
@ -133,33 +133,33 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
initialGrantNames, initialGrantNames,
// owner // owner
"{ grant perm * on membership#20002:First to role membership#20002:First.owner by system and assume }", "{ grant perm * on membership#1000107:First to role membership#1000107:First.owner by system and assume }",
"{ grant role membership#20002:First.owner to role global#global.admin by system and assume }", "{ grant role membership#1000107:First.owner to role global#global.admin by system and assume }",
// admin // admin
"{ grant perm edit on membership#20002:First to role membership#20002:First.admin by system and assume }", "{ grant perm edit on membership#1000107:First to role membership#1000107:First.admin by system and assume }",
"{ grant role membership#20002:First.admin to role membership#20002:First.owner by system and assume }", "{ grant role membership#1000107:First.admin to role membership#1000107:First.owner by system and assume }",
// agent // agent
"{ grant role membership#20002:First.agent to role membership#20002:First.admin by system and assume }", "{ grant role membership#1000107:First.agent to role membership#1000107:First.admin by system and assume }",
"{ grant role partner#10001:First.tenant to role membership#20002:First.agent by system and assume }", "{ grant role partner#10001:First.tenant to role membership#1000107:First.agent by system and assume }",
"{ grant role membership#20002:First.agent to role debitor#1000111:First.admin by system and assume }", "{ grant role membership#1000107:First.agent to role debitor#1000111:First.admin by system and assume }",
"{ grant role membership#20002:First.agent to role partner#10001:First.admin by system and assume }", "{ grant role membership#1000107:First.agent to role partner#10001:First.admin by system and assume }",
"{ grant role debitor#1000111:First.tenant to role membership#20002:First.agent by system and assume }", "{ grant role debitor#1000111:First.tenant to role membership#1000107:First.agent by system and assume }",
// tenant // tenant
"{ grant role membership#20002:First.tenant to role membership#20002:First.agent by system and assume }", "{ grant role membership#1000107:First.tenant to role membership#1000107:First.agent by system and assume }",
"{ grant role partner#10001:First.guest to role membership#20002:First.tenant by system and assume }", "{ grant role partner#10001:First.guest to role membership#1000107:First.tenant by system and assume }",
"{ grant role debitor#1000111:First.guest to role membership#20002:First.tenant by system and assume }", "{ grant role debitor#1000111:First.guest to role membership#1000107:First.tenant by system and assume }",
"{ grant role membership#20002:First.tenant to role debitor#1000111:First.agent by system and assume }", "{ grant role membership#1000107:First.tenant to role debitor#1000111:First.agent by system and assume }",
"{ grant role membership#20002:First.tenant to role partner#10001:First.agent by system and assume }", "{ grant role membership#1000107:First.tenant to role partner#10001:First.agent by system and assume }",
// guest // guest
"{ grant perm view on membership#20002:First to role membership#20002:First.guest by system and assume }", "{ grant perm view on membership#1000107:First to role membership#1000107:First.guest by system and assume }",
"{ grant role membership#20002:First.guest to role membership#20002:First.tenant by system and assume }", "{ grant role membership#1000107:First.guest to role membership#1000107:First.tenant by system and assume }",
"{ grant role membership#20002:First.guest to role partner#10001:First.tenant by system and assume }", "{ grant role membership#1000107:First.guest to role partner#10001:First.tenant by system and assume }",
"{ grant role membership#20002:First.guest to role debitor#1000111:First.tenant by system and assume }", "{ grant role membership#1000107:First.guest to role debitor#1000111:First.tenant by system and assume }",
null)); null));
} }
@ -179,14 +179,14 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
// when // when
final var result = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, null); final var result = membershipRepo.findMembershipsByOptionalPartnerUuid(null);
// then // then
exactlyTheseMembershipsAreReturned( exactlyTheseMembershipsAreReturned(
result, result,
"Membership(10001, LP First GmbH, 1000111, [2022-10-01,), NONE)", "Membership(M-1000101, LP First GmbH, D-1000111, [2022-10-01,), NONE)",
"Membership(10002, LP Second e.K., 1000212, [2022-10-01,), NONE)", "Membership(M-1000202, LP Second e.K., D-1000212, [2022-10-01,), NONE)",
"Membership(10003, IF Third OHG, 1000313, [2022-10-01,), NONE)"); "Membership(M-1000303, IF Third OHG, D-1000313, [2022-10-01,), NONE)");
} }
@Test @Test
@ -196,24 +196,26 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0);
// when // when
final var result = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber( final var result = membershipRepo.findMembershipsByOptionalPartnerUuid(givenPartner.getUuid());
givenPartner.getUuid(),
null);
// then // then
exactlyTheseMembershipsAreReturned(result, "Membership(10001, LP First GmbH, 1000111, [2022-10-01,), NONE)"); exactlyTheseMembershipsAreReturned(result,
"Membership(M-1000101, LP First GmbH, D-1000111, [2022-10-01,), NONE)");
} }
@Test @Test
public void globalAdmin_withoutAssumedRole_canFindAllMembershipByMemberNumber() { public void globalAdmin_withoutAssumedRole_canFindAllMemberships() {
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
// when // when
final var result = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002); final var result = membershipRepo.findMembershipByMemberNumber(1000202);
// then // then
exactlyTheseMembershipsAreReturned(result, "Membership(10002, LP Second e.K., 1000212, [2022-10-01,), NONE)"); assertThat(result)
.isNotNull()
.extracting(Object::toString)
.isEqualTo("Membership(M-1000202, LP Second e.K., D-1000212, [2022-10-01,), NONE)");
} }
} }
@ -401,7 +403,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
}); });
jpaAttempt.transacted(() -> { jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net", null); context("superuser-alex@hostsharing.net", null);
em.createQuery("DELETE FROM HsOfficeMembershipEntity WHERE memberNumber >= 20000"); em.createQuery("DELETE FROM HsOfficeMembershipEntity WHERE memberNumberSuffix >= '20'");
}); });
} }
@ -411,7 +413,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike(partnerTradeName).get(0); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike(partnerTradeName).get(0);
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike(debitorName).get(0); final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike(debitorName).get(0);
final var newMembership = HsOfficeMembershipEntity.builder() final var newMembership = HsOfficeMembershipEntity.builder()
.memberNumber(20002) .memberNumberSuffix("02")
.partner(givenPartner) .partner(givenPartner)
.mainDebitor(givenDebitor) .mainDebitor(givenDebitor)
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01"))) .validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))

View File

@ -11,7 +11,7 @@ public class TestHsMembership {
public static final HsOfficeMembershipEntity TEST_MEMBERSHIP = public static final HsOfficeMembershipEntity TEST_MEMBERSHIP =
HsOfficeMembershipEntity.builder() HsOfficeMembershipEntity.builder()
.partner(TEST_PARTNER) .partner(TEST_PARTNER)
.memberNumber(300001) .memberNumberSuffix("01")
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01"))) .validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))
.build(); .build();
} }

View File

@ -176,15 +176,15 @@ public class ImportOfficeData extends ContextBasedTest {
assertThat(toFormattedString(contacts)).isEqualTo("{}"); assertThat(toFormattedString(contacts)).isEqualTo("{}");
assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace("""
{ {
17=debitor(1001700: null null, null: mih), 17=debitor(D-1001700: null null, null: mih),
20=debitor(1002000: null null, null: xyz), 20=debitor(D-1002000: null null, null: xyz),
22=debitor(1102200: null null, null: xxx)} 22=debitor(D-1102200: null null, null: xxx)}
"""); """);
assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
{ {
17=Membership(10017, null null, null, 1001700, [2000-12-06,), NONE), 17=Membership(M-1001700, null null, null, D-1001700, [2000-12-06,), NONE),
20=Membership(10020, null null, null, 1002000, [2000-12-06,2016-01-01), UNKNOWN), 20=Membership(M-1002000, null null, null, D-1002000, [2000-12-06,2016-01-01), UNKNOWN),
22=Membership(11022, null null, null, 1102200, [2021-04-01,), NONE) 22=Membership(M-1102200, null null, null, D-1102200, [2021-04-01,), NONE)
} }
"""); """);
} }
@ -235,16 +235,16 @@ public class ImportOfficeData extends ContextBasedTest {
"""); """);
assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace("""
{ {
17=debitor(1001700: NP Mellies, Michael: mih), 17=debitor(D-1001700: NP Mellies, Michael: mih),
20=debitor(1002000: LP JM GmbH: xyz), 20=debitor(D-1002000: LP JM GmbH: xyz),
22=debitor(1102200: ?? Test PS: xxx) 22=debitor(D-1102200: ?? Test PS: xxx)
} }
"""); """);
assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
{ {
17=Membership(10017, NP Mellies, Michael, 1001700, [2000-12-06,), NONE), 17=Membership(M-1001700, NP Mellies, Michael, D-1001700, [2000-12-06,), NONE),
20=Membership(10020, LP JM GmbH, 1002000, [2000-12-06,2016-01-01), UNKNOWN), 20=Membership(M-1002000, LP JM GmbH, D-1002000, [2000-12-06,2016-01-01), UNKNOWN),
22=Membership(11022, ?? Test PS, 1102200, [2021-04-01,), NONE) 22=Membership(M-1102200, ?? Test PS, D-1102200, [2021-04-01,), NONE)
} }
"""); """);
assertThat(toFormattedString(relationships)).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(relationships)).isEqualToIgnoringWhitespace("""
@ -312,10 +312,10 @@ public class ImportOfficeData extends ContextBasedTest {
assertThat(toFormattedString(coopShares)).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(coopShares)).isEqualToIgnoringWhitespace("""
{ {
33443=CoopShareTransaction(10017, 2000-12-06, SUBSCRIPTION, 20, initial share subscription), 33443=CoopShareTransaction(M-1001700, 2000-12-06, SUBSCRIPTION, 20, initial share subscription),
33451=CoopShareTransaction(10020, 2000-12-06, SUBSCRIPTION, 2, initial share subscription), 33451=CoopShareTransaction(M-1002000, 2000-12-06, SUBSCRIPTION, 2, initial share subscription),
33701=CoopShareTransaction(10017, 2005-01-10, SUBSCRIPTION, 40, increase), 33701=CoopShareTransaction(M-1001700, 2005-01-10, SUBSCRIPTION, 40, increase),
33810=CoopShareTransaction(10020, 2016-12-31, CANCELLATION, 22, membership ended) 33810=CoopShareTransaction(M-1002000, 2016-12-31, CANCELLATION, 22, membership ended)
} }
"""); """);
} }
@ -549,7 +549,7 @@ public class ImportOfficeData extends ContextBasedTest {
final var person = HsOfficePersonEntity.builder().build(); final var person = HsOfficePersonEntity.builder().build();
final var partner = HsOfficePartnerEntity.builder() final var partner = HsOfficePartnerEntity.builder()
.debitorNumberPrefix(rec.getInteger("member_id")) .partnerNumber(rec.getInteger("member_id"))
.details(HsOfficePartnerDetailsEntity.builder().build()) .details(HsOfficePartnerDetailsEntity.builder().build())
.contact(null) // is set during contacts import depending on assigned roles .contact(null) // is set during contacts import depending on assigned roles
.person(person) .person(person)
@ -571,9 +571,10 @@ public class ImportOfficeData extends ContextBasedTest {
partners.put(rec.getInteger("bp_id"), partner); partners.put(rec.getInteger("bp_id"), partner);
if (isNotBlank(rec.getString("member_since"))) { if (isNotBlank(rec.getString("member_since"))) {
assertThat(rec.getInteger("member_id")).isEqualTo(partner.getPartnerNumber());
final var membership = HsOfficeMembershipEntity.builder() final var membership = HsOfficeMembershipEntity.builder()
.partner(partner) .partner(partner)
.memberNumber(rec.getInteger("member_id")) .memberNumberSuffix("00")
.validity(toPostgresDateRange( .validity(toPostgresDateRange(
rec.getLocalDate("member_since"), rec.getLocalDate("member_since"),
rec.getLocalDate("member_until"))) rec.getLocalDate("member_until")))
@ -610,7 +611,7 @@ public class ImportOfficeData extends ContextBasedTest {
: HsOfficeCoopSharesTransactionType.ADJUSTMENT : HsOfficeCoopSharesTransactionType.ADJUSTMENT
) )
.shareCount(rec.getInteger("quantity")) .shareCount(rec.getInteger("quantity"))
.comment(rec.getString("comment")) .comment( rec.getString("comment"))
.build(); .build();
coopShares.put(rec.getInteger("member_share_id"), shareTransaction); coopShares.put(rec.getInteger("member_share_id"), shareTransaction);

View File

@ -125,7 +125,7 @@ class HsOfficePartnerControllerAcceptanceTest {
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
"debitorNumberPrefix": "12345", "partnerNumber": "12345",
"contactUuid": "%s", "contactUuid": "%s",
"personUuid": "%s", "personUuid": "%s",
"details": { "details": {
@ -167,7 +167,7 @@ class HsOfficePartnerControllerAcceptanceTest {
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
"debitorNumberPrefix": "12345", "partnerNumber": "12345",
"contactUuid": "%s", "contactUuid": "%s",
"personUuid": "%s", "personUuid": "%s",
"details": {} "details": {}
@ -195,7 +195,7 @@ class HsOfficePartnerControllerAcceptanceTest {
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
"debitorNumberPrefix": "12345", "partnerNumber": "12345",
"contactUuid": "%s", "contactUuid": "%s",
"personUuid": "%s", "personUuid": "%s",
"details": {} "details": {}
@ -297,7 +297,7 @@ class HsOfficePartnerControllerAcceptanceTest {
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
"debitorNumberPrefix": "12345", "debitorNumerPrefix": "12345",
"contactUuid": "%s", "contactUuid": "%s",
"personUuid": "%s", "personUuid": "%s",
"details": { "details": {

View File

@ -105,7 +105,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
final var givenPerson = personRepo.findPersonByOptionalNameLike("Erben Bessler").get(0); final var givenPerson = personRepo.findPersonByOptionalNameLike("Erben Bessler").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0); final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
final var newPartner = toCleanup(HsOfficePartnerEntity.builder() final var newPartner = toCleanup(HsOfficePartnerEntity.builder()
.debitorNumberPrefix(22222) .partnerNumber(22222)
.person(givenPerson) .person(givenPerson)
.contact(givenContact) .contact(givenContact)
.details(HsOfficePartnerDetailsEntity.builder().build()) .details(HsOfficePartnerDetailsEntity.builder().build())
@ -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(LP First GmbH: first contact)");
}
}
@Nested @Nested
class UpdatePartner { class UpdatePartner {
@ -396,13 +415,13 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
} }
private HsOfficePartnerEntity givenSomeTemporaryPartnerBessler( private HsOfficePartnerEntity givenSomeTemporaryPartnerBessler(
final Integer debitorNumberPrefix, final String person, final String contact) { final Integer partnerNumber, final String person, final String contact) {
return jpaAttempt.transacted(() -> { return jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenPerson = personRepo.findPersonByOptionalNameLike(person).get(0); final var givenPerson = personRepo.findPersonByOptionalNameLike(person).get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike(contact).get(0); final var givenContact = contactRepo.findContactByOptionalLabelLike(contact).get(0);
final var newPartner = HsOfficePartnerEntity.builder() final var newPartner = HsOfficePartnerEntity.builder()
.debitorNumberPrefix(debitorNumberPrefix) .partnerNumber(partnerNumber)
.person(givenPerson) .person(givenPerson)
.contact(givenContact) .contact(givenContact)
.details(HsOfficePartnerDetailsEntity.builder().build()) .details(HsOfficePartnerDetailsEntity.builder().build())

View File

@ -12,7 +12,7 @@ public class TestHsOfficePartner {
static public HsOfficePartnerEntity hsOfficePartnerWithLegalPerson(final String tradeName) { static public HsOfficePartnerEntity hsOfficePartnerWithLegalPerson(final String tradeName) {
return HsOfficePartnerEntity.builder() return HsOfficePartnerEntity.builder()
.debitorNumberPrefix(10001) .partnerNumber(10001)
.person(HsOfficePersonEntity.builder() .person(HsOfficePersonEntity.builder()
.personType(LEGAL_PERSON) .personType(LEGAL_PERSON)
.tradeName(tradeName) .tradeName(tradeName)

View File

@ -1,5 +1,6 @@
package net.hostsharing.hsadminng.hs.office.person; package net.hostsharing.hsadminng.hs.office.person;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.EnumSource;
@ -15,10 +16,19 @@ class HsOfficePersonTypeConverterUnitTest {
assertThat(converter.convertToDatabaseColumn(given)).isEqualTo(given.shortName); assertThat(converter.convertToDatabaseColumn(given)).isEqualTo(given.shortName);
} }
@Test
void mapsNullToDatabaseValue() {
assertThat(converter.convertToDatabaseColumn(null)).isEqualTo(null);
}
@ParameterizedTest @ParameterizedTest
@EnumSource(HsOfficePersonType.class) @EnumSource(HsOfficePersonType.class)
void mapsFromDatabaseValue(final HsOfficePersonType given) { void mapsFromDatabaseValue(final HsOfficePersonType given) {
assertThat(converter.convertToEntityAttribute(given.shortName)).isEqualTo(given); assertThat(converter.convertToEntityAttribute(given.shortName)).isEqualTo(given);
} }
@Test
void mapsNullFromDatabaseValue() {
assertThat(converter.convertToEntityAttribute(null)).isEqualTo(null);
}
} }

View File

@ -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_PERSON)
.tradeName("some trade name")
.build();
private HsOfficePersonEntity holder = HsOfficePersonEntity.builder()
.personType(HsOfficePersonType.NATURAL_PERSON)
.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='LP some trade name', relType='REPRESENTATIVE', relHolder='NP Meier, Mellie')");
}
}

View File

@ -376,7 +376,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent().get() assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent().get()
.matches(mandate -> { .matches(mandate -> {
assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(1000111: LP First GmbH: fir)"); assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(D-1000111: LP First GmbH: fir)");
assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH"); assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH");
assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z - patched"); assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z - patched");
assertThat(mandate.getValidFrom()).isEqualTo("2020-06-05"); assertThat(mandate.getValidFrom()).isEqualTo("2020-06-05");
@ -417,7 +417,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
// finally, the sepaMandate is actually updated // finally, the sepaMandate is actually updated
assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent().get() assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent().get()
.matches(mandate -> { .matches(mandate -> {
assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(1000111: LP First GmbH: fir)"); assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(D-1000111: LP First GmbH: fir)");
assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH"); assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH");
assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z"); assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z");
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2023-01-01)"); assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2023-01-01)");

View File

@ -13,8 +13,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import java.util.UUID; import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -30,9 +28,6 @@ class RbacUserControllerAcceptanceTest {
@LocalServerPort @LocalServerPort
private Integer port; private Integer port;
@PersistenceContext
EntityManager em;
@Autowired @Autowired
JpaAttempt jpaAttempt; JpaAttempt jpaAttempt;