feature/prefixes-for-partner-member-debitor-in-api (#122)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: #122
Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
This commit is contained in:
Michael Hoennig 2024-11-18 12:11:16 +01:00
parent c98a5acb38
commit 35db9aad43
51 changed files with 277 additions and 216 deletions

View File

@ -118,8 +118,8 @@ openapiProcessor {
springRoot { springRoot {
processorName 'spring' processorName 'spring'
processor 'io.openapiprocessor:openapi-processor-spring:2022.5' processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
apiPath "$projectDir/src/main/resources/api-definition.yaml" apiPath "$projectDir/src/main/resources/api-definition/api-definition.yaml"
mapping "$projectDir/src/main/resources/api-mappings.yaml" mapping "$projectDir/src/main/resources/api-definition/api-mappings.yaml"
targetDir "$buildDir/generated/sources/openapi-javax" targetDir "$buildDir/generated/sources/openapi-javax"
showWarnings true showWarnings true
openApiNullable true openApiNullable true

View File

@ -64,7 +64,7 @@ classDiagram
} }
class partner-MeierGmbH { class partner-MeierGmbH {
+Numeric partnerNumber: 12345 +Numeric partnerNumber: P-12345
+Relation partnerRel +Relation partnerRel
} }
partner-MeierGmbH *-- rel-MeierGmbH partner-MeierGmbH *-- rel-MeierGmbH

View File

@ -5,8 +5,8 @@ import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import net.hostsharing.hsadminng.errors.DisplayAs; import net.hostsharing.hsadminng.errors.DisplayAs;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
@ -14,7 +14,7 @@ import jakarta.persistence.Id;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
// a partial HsOfficeDebitorEntity to reduce the number of SQL queries to load the entity // a partial HsOfficeDebitorEntity to reduce the number of SQL queries to load the entity
@Entity @Entity

View File

@ -15,8 +15,8 @@ import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealEntity;
import net.hostsharing.hsadminng.hs.validation.PropertiesProvider; import net.hostsharing.hsadminng.hs.validation.PropertiesProvider;
import net.hostsharing.hsadminng.mapper.PatchableMapWrapper; import net.hostsharing.hsadminng.mapper.PatchableMapWrapper;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.hibernate.annotations.Type; import org.hibernate.annotations.Type;
import jakarta.persistence.CascadeType; import jakarta.persistence.CascadeType;
@ -45,7 +45,7 @@ import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.lowerInclusiveFromPostgresDateRange; import static net.hostsharing.hsadminng.mapper.PostgresDateRange.lowerInclusiveFromPostgresDateRange;
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange; import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange;
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.upperInclusiveFromPostgresDateRange; import static net.hostsharing.hsadminng.mapper.PostgresDateRange.upperInclusiveFromPostgresDateRange;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@MappedSuperclass @MappedSuperclass
@Getter @Getter

View File

@ -4,14 +4,14 @@ import lombok.*;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorEntity; import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorEntity;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.util.UUID; import java.util.UUID;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@MappedSuperclass @MappedSuperclass
@Getter @Getter

View File

@ -15,8 +15,8 @@ import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
import net.hostsharing.hsadminng.hs.validation.PropertiesProvider; import net.hostsharing.hsadminng.hs.validation.PropertiesProvider;
import net.hostsharing.hsadminng.mapper.PatchableMapWrapper; import net.hostsharing.hsadminng.mapper.PatchableMapWrapper;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.hibernate.annotations.Type; import org.hibernate.annotations.Type;
import jakarta.persistence.CascadeType; import jakarta.persistence.CascadeType;
@ -42,7 +42,7 @@ import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static java.util.Collections.emptyMap; import static java.util.Collections.emptyMap;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@MappedSuperclass @MappedSuperclass
@Getter @Getter

View File

@ -5,8 +5,8 @@ import lombok.experimental.FieldNameConstants;
import net.hostsharing.hsadminng.errors.DisplayAs; import net.hostsharing.hsadminng.errors.DisplayAs;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.rbac.generator.RbacView; import net.hostsharing.hsadminng.rbac.generator.RbacView;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.io.IOException; import java.io.IOException;
@ -16,7 +16,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Permission.*; import static net.hostsharing.hsadminng.rbac.generator.RbacView.Permission.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.RbacSubjectReference.UserRole.CREATOR; import static net.hostsharing.hsadminng.rbac.generator.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*; import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@Entity @Entity
@Table(schema = "hs_office", name = "bankaccount_rv") @Table(schema = "hs_office", name = "bankaccount_rv")

View File

@ -12,8 +12,8 @@ import lombok.experimental.SuperBuilder;
import net.hostsharing.hsadminng.errors.DisplayAs; import net.hostsharing.hsadminng.errors.DisplayAs;
import net.hostsharing.hsadminng.mapper.PatchableMapWrapper; import net.hostsharing.hsadminng.mapper.PatchableMapWrapper;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type; import org.hibernate.annotations.Type;
@ -27,7 +27,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@MappedSuperclass @MappedSuperclass
@Getter @Getter

View File

@ -10,8 +10,8 @@ import net.hostsharing.hsadminng.errors.DisplayAs;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.rbac.generator.RbacView; import net.hostsharing.hsadminng.rbac.generator.RbacView;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import jakarta.persistence.*; import jakarta.persistence.*;
@ -31,7 +31,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.ADMIN;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.AGENT; import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.AGENT;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.directlyFetchedByDependsOnColumn; import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.directlyFetchedByDependsOnColumn;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@Entity @Entity
@Table(schema = "hs_office", name = "coopassettx_rv") @Table(schema = "hs_office", name = "coopassettx_rv")

View File

@ -10,8 +10,8 @@ import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.rbac.generator.RbacView; import net.hostsharing.hsadminng.rbac.generator.RbacView;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL; import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.io.IOException; import java.io.IOException;
@ -29,7 +29,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.ADMIN;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.AGENT; import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.AGENT;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.directlyFetchedByDependsOnColumn; import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.directlyFetchedByDependsOnColumn;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@Entity @Entity
@Table(schema = "hs_office", name = "coopsharetx_rv") @Table(schema = "hs_office", name = "coopsharetx_rv")

View File

@ -22,8 +22,10 @@ import jakarta.persistence.PersistenceContext;
import jakarta.validation.ValidationException; import jakarta.validation.ValidationException;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.function.BiConsumer;
import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.DEBITOR; import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.DEBITOR;
import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
@RestController @RestController
@ -49,24 +51,24 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public ResponseEntity<List<HsOfficeDebitorResource>> listDebitors( public ResponseEntity<List<HsOfficeDebitorResource>> getListOfDebitors(
final String currentSubject, final String currentSubject,
final String assumedRoles, final String assumedRoles,
final String name, final String name,
final Integer debitorNumber) { final String debitorNumber) {
context.define(currentSubject, assumedRoles); context.define(currentSubject, assumedRoles);
final var entities = debitorNumber != null final var entities = debitorNumber != null
? debitorRepo.findDebitorByDebitorNumber(debitorNumber) ? debitorRepo.findDebitorByDebitorNumber(cropTag("D-", debitorNumber))
: debitorRepo.findDebitorByOptionalNameLike(name); : debitorRepo.findDebitorByOptionalNameLike(name);
final var resources = mapper.mapList(entities, HsOfficeDebitorResource.class); final var resources = mapper.mapList(entities, HsOfficeDebitorResource.class, ENTITY_TO_RESOURCE_POSTMAPPER);
return ResponseEntity.ok(resources); return ResponseEntity.ok(resources);
} }
@Override @Override
@Transactional @Transactional
public ResponseEntity<HsOfficeDebitorResource> addDebitor( public ResponseEntity<HsOfficeDebitorResource> postNewDebitor(
String currentSubject, String currentSubject,
String assumedRoles, String assumedRoles,
HsOfficeDebitorInsertResource body) { HsOfficeDebitorInsertResource body) {
@ -107,13 +109,13 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
.path("/api/hs/office/debitors/{id}") .path("/api/hs/office/debitors/{id}")
.buildAndExpand(savedEntity.getUuid()) .buildAndExpand(savedEntity.getUuid())
.toUri(); .toUri();
final var mapped = mapper.map(savedEntity, HsOfficeDebitorResource.class); final var mapped = mapper.map(savedEntity, HsOfficeDebitorResource.class, ENTITY_TO_RESOURCE_POSTMAPPER);
return ResponseEntity.created(uri).body(mapped); return ResponseEntity.created(uri).body(mapped);
} }
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public ResponseEntity<HsOfficeDebitorResource> getDebitorByUuid( public ResponseEntity<HsOfficeDebitorResource> getSingleDebitorByUuid(
final String currentSubject, final String currentSubject,
final String assumedRoles, final String assumedRoles,
final UUID debitorUuid) { final UUID debitorUuid) {
@ -124,7 +126,7 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
if (result.isEmpty()) { if (result.isEmpty()) {
return ResponseEntity.notFound().build(); return ResponseEntity.notFound().build();
} }
return ResponseEntity.ok(mapper.map(result.get(), HsOfficeDebitorResource.class)); return ResponseEntity.ok(mapper.map(result.get(), HsOfficeDebitorResource.class, ENTITY_TO_RESOURCE_POSTMAPPER));
} }
@Override @Override
@ -159,7 +161,11 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
final var saved = debitorRepo.save(current); final var saved = debitorRepo.save(current);
Hibernate.initialize(saved); Hibernate.initialize(saved);
final var mapped = mapper.map(saved, HsOfficeDebitorResource.class); final var mapped = mapper.map(saved, HsOfficeDebitorResource.class, ENTITY_TO_RESOURCE_POSTMAPPER);
return ResponseEntity.ok(mapped); return ResponseEntity.ok(mapped);
} }
final BiConsumer<HsOfficeDebitorEntity, HsOfficeDebitorResource> ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource) -> {
resource.setDebitorNumber(entity.getTaggedDebitorNumber());
};
} }

View File

@ -14,8 +14,8 @@ import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRbacEntity;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.rbac.generator.RbacView; import net.hostsharing.hsadminng.rbac.generator.RbacView;
import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL; import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.JoinFormula; import org.hibernate.annotations.JoinFormula;
import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFound;
@ -51,7 +51,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.directlyFetchedByDependsOnColumn; import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.directlyFetchedByDependsOnColumn;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.fetchedBySql; import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.fetchedBySql;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@Entity @Entity
@Table(schema = "hs_office", name = "debitor_rv") @Table(schema = "hs_office", name = "debitor_rv")
@ -142,19 +142,14 @@ public class HsOfficeDebitorEntity implements BaseEntity<HsOfficeDebitorEntity>,
return this; return this;
} }
private String getDebitorNumberString() { public String getTaggedDebitorNumber() {
return ofNullable(partner) return ofNullable(partner)
.filter(partner -> debitorNumberSuffix != null) .filter(partner -> debitorNumberSuffix != null)
.map(HsOfficePartnerEntity::getPartnerNumber) .map(HsOfficePartnerEntity::getPartnerNumber)
.map(Object::toString) .map(partnerNumber -> DEBITOR_NUMBER_TAG + partnerNumber + debitorNumberSuffix)
.map(partnerNumber -> partnerNumber + debitorNumberSuffix)
.orElse(null); .orElse(null);
} }
public Integer getDebitorNumber() {
return ofNullable(getDebitorNumberString()).map(Integer::parseInt).orElse(null);
}
@Override @Override
public String toString() { public String toString() {
return stringify.apply(this); return stringify.apply(this);
@ -162,7 +157,7 @@ public class HsOfficeDebitorEntity implements BaseEntity<HsOfficeDebitorEntity>,
@Override @Override
public String toShortString() { public String toShortString() {
return DEBITOR_NUMBER_TAG + getDebitorNumberString(); return getTaggedDebitorNumber();
} }
public static RbacView rbac() { public static RbacView rbac() {

View File

@ -16,13 +16,16 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt
JOIN HsOfficePartnerEntity partner JOIN HsOfficePartnerEntity partner
ON partner.partnerRel.holder = debitor.debitorRel.anchor ON partner.partnerRel.holder = debitor.debitorRel.anchor
AND partner.partnerRel.type = 'PARTNER' AND debitor.debitorRel.type = 'DEBITOR' AND partner.partnerRel.type = 'PARTNER' AND debitor.debitorRel.type = 'DEBITOR'
WHERE cast(partner.partnerNumber as integer) = :partnerNumber WHERE partner.partnerNumber = :partnerNumber
AND cast(debitor.debitorNumberSuffix as integer) = :debitorNumberSuffix AND debitor.debitorNumberSuffix = :debitorNumberSuffix
""") """)
List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int partnerNumber, byte debitorNumberSuffix); List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int partnerNumber, String debitorNumberSuffix);
default List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int debitorNumber) { default List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int debitorNumber) {
return findDebitorByDebitorNumber( debitorNumber/100, (byte) (debitorNumber%100)); final var partnerNumber = debitorNumber / 100;
final String suffix = String.format("%02d", debitorNumber % 100);
final var result = findDebitorByDebitorNumber(partnerNumber, suffix);
return result;
} }
@Query(""" @Query("""

View File

@ -17,9 +17,9 @@ import java.util.UUID;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
@RestController @RestController
public class HsOfficeMembershipController implements HsOfficeMembershipsApi { public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
@Autowired @Autowired
@ -33,16 +33,18 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public ResponseEntity<List<HsOfficeMembershipResource>> listMemberships( public ResponseEntity<List<HsOfficeMembershipResource>> getListOfMemberships(
final String currentSubject, final String currentSubject,
final String assumedRoles, final String assumedRoles,
final UUID partnerUuid, final UUID partnerUuid,
final Integer memberNumber) { final String memberNumber) {
context.define(currentSubject, assumedRoles); context.define(currentSubject, assumedRoles);
final var entities = ( memberNumber != null) final var entities = (memberNumber != null)
? ofNullable(membershipRepo.findMembershipByMemberNumber(memberNumber)).stream().toList() ? ofNullable(membershipRepo.findMembershipByMemberNumber(
: membershipRepo.findMembershipsByOptionalPartnerUuid(partnerUuid); cropTag(HsOfficeMembershipEntity.MEMBER_NUMBER_TAG, memberNumber))).stream()
.toList()
: 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);
@ -51,7 +53,7 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
@Override @Override
@Transactional @Transactional
public ResponseEntity<HsOfficeMembershipResource> addMembership( public ResponseEntity<HsOfficeMembershipResource> postNewMembership(
final String currentSubject, final String currentSubject,
final String assumedRoles, final String assumedRoles,
final HsOfficeMembershipInsertResource body) { final HsOfficeMembershipInsertResource body) {
@ -74,7 +76,7 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public ResponseEntity<HsOfficeMembershipResource> getMembershipByUuid( public ResponseEntity<HsOfficeMembershipResource> getSingleMembershipByUuid(
final String currentSubject, final String currentSubject,
final String assumedRoles, final String assumedRoles,
final UUID membershipUuid) { final UUID membershipUuid) {
@ -125,7 +127,7 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
} }
final BiConsumer<HsOfficeMembershipEntity, HsOfficeMembershipResource> SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource) -> { final BiConsumer<HsOfficeMembershipEntity, HsOfficeMembershipResource> SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource) -> {
// TODO.refa: this should be possible via ModelMapper config resource.setMemberNumber(entity.getTaggedMemberNumber());
resource.setValidFrom(entity.getValidity().lower()); resource.setValidFrom(entity.getValidity().lower());
if (entity.getValidity().hasUpperBound()) { if (entity.getValidity().hasUpperBound()) {
resource.setValidTo(entity.getValidity().upper().minusDays(1)); resource.setValidTo(entity.getValidity().upper().minusDays(1));

View File

@ -13,8 +13,8 @@ import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.hsadminng.rbac.generator.RbacView; import net.hostsharing.hsadminng.rbac.generator.RbacView;
import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL; import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.hibernate.annotations.Type; import org.hibernate.annotations.Type;
import jakarta.persistence.Column; import jakarta.persistence.Column;
@ -53,7 +53,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.OWNER;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.TENANT; import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.TENANT;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.fetchedBySql; import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.fetchedBySql;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@Entity @Entity
@Table(schema = "hs_office", name = "membership_rv") @Table(schema = "hs_office", name = "membership_rv")
@ -130,6 +130,7 @@ public class HsOfficeMembershipEntity implements BaseEntity<HsOfficeMembershipEn
} }
return validity; return validity;
} }
public Integer getMemberNumber() { public Integer getMemberNumber() {
if (partner == null || partner.getPartnerNumber() == null || memberNumberSuffix == null ) { if (partner == null || partner.getPartnerNumber() == null || memberNumberSuffix == null ) {
return null; return null;
@ -138,6 +139,10 @@ public class HsOfficeMembershipEntity implements BaseEntity<HsOfficeMembershipEn
return getPartner().getPartnerNumber() * 100 + Integer.parseInt(memberNumberSuffix, 10); return getPartner().getPartnerNumber() * 100 + Integer.parseInt(memberNumberSuffix, 10);
} }
public String getTaggedMemberNumber() {
return MEMBER_NUMBER_TAG + getMemberNumber();
}
@Override @Override
public String toString() { public String toString() {
return stringify.apply(this); return stringify.apply(this);

View File

@ -27,6 +27,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.EX_PARTNER; import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.EX_PARTNER;
import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
@RestController @RestController
@ -150,7 +151,7 @@ public class HsOfficePartnerController implements HsOfficePartnersApi {
private HsOfficePartnerEntity createPartnerEntity(final HsOfficePartnerInsertResource body) { private HsOfficePartnerEntity createPartnerEntity(final HsOfficePartnerInsertResource body) {
final var entityToSave = new HsOfficePartnerEntity(); final var entityToSave = new HsOfficePartnerEntity();
entityToSave.setPartnerNumber(body.getPartnerNumber()); entityToSave.setPartnerNumber(cropTag(HsOfficePartnerEntity.PARTNER_NUMBER_TAG, body.getPartnerNumber()));
entityToSave.setPartnerRel(persistPartnerRel(body.getPartnerRel())); entityToSave.setPartnerRel(persistPartnerRel(body.getPartnerRel()));
entityToSave.setDetails(mapper.map(body.getDetails(), HsOfficePartnerDetailsEntity.class)); entityToSave.setDetails(mapper.map(body.getDetails(), HsOfficePartnerDetailsEntity.class));
return entityToSave; return entityToSave;

View File

@ -5,8 +5,8 @@ import net.hostsharing.hsadminng.errors.DisplayAs;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.rbac.generator.RbacView; import net.hostsharing.hsadminng.rbac.generator.RbacView;
import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL; import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.io.IOException; import java.io.IOException;
@ -17,7 +17,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.GLOBAL;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Permission.*; import static net.hostsharing.hsadminng.rbac.generator.RbacView.Permission.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*; import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@Entity @Entity
@Table(schema = "hs_office", name = "partner_details_rv") @Table(schema = "hs_office", name = "partner_details_rv")

View File

@ -14,8 +14,8 @@ import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelation; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelation;
import net.hostsharing.hsadminng.rbac.generator.RbacView; import net.hostsharing.hsadminng.rbac.generator.RbacView;
import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL; import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction; import org.hibernate.annotations.NotFoundAction;
@ -33,7 +33,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.directlyFetchedByDependsOnColumn; import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.directlyFetchedByDependsOnColumn;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@Entity @Entity
@Table(schema = "hs_office", name = "partner_rv") @Table(schema = "hs_office", name = "partner_rv")

View File

@ -6,8 +6,8 @@ import net.hostsharing.hsadminng.errors.DisplayAs;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.rbac.generator.RbacView; import net.hostsharing.hsadminng.rbac.generator.RbacView;
import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL; import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import jakarta.persistence.*; import jakarta.persistence.*;
@ -19,7 +19,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.Permission.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.RbacSubjectReference.UserRole.CREATOR; import static net.hostsharing.hsadminng.rbac.generator.RbacView.RbacSubjectReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*; import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
// TODO.refa: split HsOfficePersonEntity into Real+Rbac-Entity // TODO.refa: split HsOfficePersonEntity into Real+Rbac-Entity
@Entity @Entity

View File

@ -6,14 +6,14 @@ import lombok.experimental.SuperBuilder;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@MappedSuperclass @MappedSuperclass
@NoArgsConstructor(access = AccessLevel.PROTECTED) @NoArgsConstructor(access = AccessLevel.PROTECTED)

View File

@ -131,7 +131,7 @@ public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi {
if (entity.getValidity().hasUpperBound()) { if (entity.getValidity().hasUpperBound()) {
resource.setValidTo(entity.getValidity().upper().minusDays(1)); resource.setValidTo(entity.getValidity().upper().minusDays(1));
} }
resource.getDebitor().setDebitorNumber(entity.getDebitor().getDebitorNumber()); resource.getDebitor().setDebitorNumber(entity.getDebitor().getTaggedDebitorNumber());
}; };
final BiConsumer<HsOfficeSepaMandateInsertResource, HsOfficeSepaMandateEntity> SEPA_MANDATE_RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> { final BiConsumer<HsOfficeSepaMandateInsertResource, HsOfficeSepaMandateEntity> SEPA_MANDATE_RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {

View File

@ -9,8 +9,8 @@ import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRbacEntity; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRbacEntity;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.rbac.generator.RbacView; import net.hostsharing.hsadminng.rbac.generator.RbacView;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.hibernate.annotations.Type; import org.hibernate.annotations.Type;
import jakarta.persistence.*; import jakarta.persistence.*;
@ -30,7 +30,7 @@ import static net.hostsharing.hsadminng.rbac.generator.RbacView.RbacSubjectRefer
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*; import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.*; import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.*;
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@Entity @Entity
@Table(schema = "hs_office", name = "sepamandate_rv") @Table(schema = "hs_office", name = "sepamandate_rv")

View File

@ -1,4 +1,4 @@
package net.hostsharing.hsadminng.stringify; package net.hostsharing.hsadminng.repr;
import net.hostsharing.hsadminng.errors.DisplayAs; import net.hostsharing.hsadminng.errors.DisplayAs;

View File

@ -1,4 +1,4 @@
package net.hostsharing.hsadminng.stringify; package net.hostsharing.hsadminng.repr;
public interface Stringifyable { public interface Stringifyable {

View File

@ -0,0 +1,15 @@
package net.hostsharing.hsadminng.repr;
import lombok.experimental.UtilityClass;
@UtilityClass
public class TaggedNumber {
public static Integer cropTag(final String tag, final String taggedNumber) {
return taggedNumber.startsWith(tag) ? Integer.valueOf(taggedNumber.substring(tag.length())) : invalidTag(tag, taggedNumber);
}
private static Integer invalidTag(final String tag, final String taggedNumber) {
throw new IllegalArgumentException("Expected " + tag + "... but got: " + taggedNumber);
}
}

View File

@ -12,10 +12,10 @@ components:
debitorRel: debitorRel:
$ref: 'hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelation' $ref: 'hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelation'
debitorNumber: debitorNumber:
type: integer type: string
format: int32 minLength: 9
minimum: 1000000 maxLength: 9
maximum: 9999999 pattern: 'D-[0-9]{7}'
debitorNumberSuffix: debitorNumberSuffix:
type: string type: string
pattern: '^[0-9][0-9]$' pattern: '^[0-9][0-9]$'

View File

@ -2,7 +2,7 @@ get:
tags: tags:
- hs-office-debitors - hs-office-debitors
description: 'Fetch a single debitor by its uuid, if visible for the current subject.' description: 'Fetch a single debitor by its uuid, if visible for the current subject.'
operationId: getDebitorByUuid operationId: getSingleDebitorByUuid
parameters: parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject' - $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles' - $ref: 'auth.yaml#/components/parameters/assumedRoles'

View File

@ -3,7 +3,7 @@ get:
description: Returns the list of (optionally filtered) debitors which are visible to the current subject or any of it's assumed roles. description: Returns the list of (optionally filtered) debitors which are visible to the current subject or any of it's assumed roles.
tags: tags:
- hs-office-debitors - hs-office-debitors
operationId: listDebitors operationId: getListOfDebitors
parameters: parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject' - $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles' - $ref: 'auth.yaml#/components/parameters/assumedRoles'
@ -17,7 +17,10 @@ get:
in: query in: query
required: false required: false
schema: schema:
type: integer type: string
minLength: 9
maxLength: 9
pattern: 'D-[0-9]{7}'
description: Debitor number of the requested debitor. description: Debitor number of the requested debitor.
responses: responses:
"200": "200":
@ -37,7 +40,7 @@ post:
summary: Adds a new debitor. summary: Adds a new debitor.
tags: tags:
- hs-office-debitors - hs-office-debitors
operationId: addDebitor operationId: postNewDebitor
parameters: parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject' - $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles' - $ref: 'auth.yaml#/components/parameters/assumedRoles'

View File

@ -26,9 +26,10 @@ components:
mainDebitor: mainDebitor:
$ref: 'hs-office-debitor-schemas.yaml#/components/schemas/HsOfficeDebitor' $ref: 'hs-office-debitor-schemas.yaml#/components/schemas/HsOfficeDebitor'
memberNumber: memberNumber:
type: integer type: string
minimum: 1000000 minLength: 9
maximum: 9999999 maxLength: 9
pattern: 'M-[0-9]{7}'
memberNumberSuffix: memberNumberSuffix:
type: string type: string
minLength: 2 minLength: 2

View File

@ -2,7 +2,7 @@ get:
tags: tags:
- hs-office-memberships - hs-office-memberships
description: 'Fetch a single membership by its uuid, if visible for the current subject.' description: 'Fetch a single membership by its uuid, if visible for the current subject.'
operationId: getMembershipByUuid operationId: getSingleMembershipByUuid
parameters: parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject' - $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles' - $ref: 'auth.yaml#/components/parameters/assumedRoles'

View File

@ -4,7 +4,7 @@ get:
The list can optionally be filtered by either the `partnerUuid` or the `memberNumber` - not both at the same time. 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: getListOfMemberships
parameters: parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject' - $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles' - $ref: 'auth.yaml#/components/parameters/assumedRoles'
@ -19,7 +19,10 @@ get:
in: query in: query
required: false required: false
schema: schema:
type: integer type: string
minLength: 9
maxLength: 9
pattern: 'M-[0-9]{7}'
description: Member number, exclusive to `partnerUuid`. description: Member number, exclusive to `partnerUuid`.
responses: responses:
"200": "200":
@ -39,7 +42,7 @@ post:
summary: Adds a new membership. summary: Adds a new membership.
tags: tags:
- hs-office-memberships - hs-office-memberships
operationId: addMembership operationId: postNewMembership
parameters: parameters:
- $ref: 'auth.yaml#/components/parameters/currentSubject' - $ref: 'auth.yaml#/components/parameters/currentSubject'
- $ref: 'auth.yaml#/components/parameters/assumedRoles' - $ref: 'auth.yaml#/components/parameters/assumedRoles'

View File

@ -10,10 +10,10 @@ components:
type: string type: string
format: uuid format: uuid
partnerNumber: partnerNumber:
type: integer type: string
format: int8 minLength: 7
minimum: 10000 maxLength: 7
maximum: 99999 pattern: 'P-[0-9]{5}'
partnerRel: partnerRel:
$ref: 'hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelation' $ref: 'hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelation'
details: details:
@ -86,10 +86,10 @@ components:
type: object type: object
properties: properties:
partnerNumber: partnerNumber:
type: integer type: string
format: int8 minLength: 7
minimum: 10000 maxLength: 7
maximum: 99999 pattern: 'P-[0-9]{5}'
partnerRel: partnerRel:
$ref: '#/components/schemas/HsOfficePartnerRelInsert' $ref: '#/components/schemas/HsOfficePartnerRelInsert'
details: details:

View File

@ -77,7 +77,7 @@ public class ArchitectureTest {
"..rbac.grant", "..rbac.grant",
"..rbac.role", "..rbac.role",
"..rbac.object", "..rbac.object",
"..stringify" "..repr"
// ATTENTION: Don't simply add packages here, also add arch rules for the new package! // ATTENTION: Don't simply add packages here, also add arch rules for the new package!
); );

View File

@ -72,7 +72,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
EntityManager em; EntityManager em;
@Nested @Nested
class ListDebitors { class GetListOfDebitors {
@Test @Test
void globalAdmin_withoutAssumedRoles_canViewAllDebitors_ifNoCriteriaGiven() { void globalAdmin_withoutAssumedRoles_canViewAllDebitors_ifNoCriteriaGiven() {
@ -110,10 +110,10 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
"phoneNumbers": { "phone_office": "+49 123 1234567" } "phoneNumbers": { "phone_office": "+49 123 1234567" }
} }
}, },
"debitorNumber": 1000111, "debitorNumber": "D-1000111",
"debitorNumberSuffix": "11", "debitorNumberSuffix": "11",
"partner": { "partner": {
"partnerNumber": 10001, "partnerNumber": "P-10001",
"partnerRel": { "partnerRel": {
"anchor": { "anchor": {
"personType": "LEGAL_PERSON", "personType": "LEGAL_PERSON",
@ -165,10 +165,10 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
"emailAddresses": { "main": "contact-admin@secondcontact.example.com" } "emailAddresses": { "main": "contact-admin@secondcontact.example.com" }
} }
}, },
"debitorNumber": 1000212, "debitorNumber": "D-1000212",
"debitorNumberSuffix": "12", "debitorNumberSuffix": "12",
"partner": { "partner": {
"partnerNumber": 10002, "partnerNumber": "P-10002",
"partnerRel": { "partnerRel": {
"anchor": {"tradeName": "Hostsharing eG"}, "anchor": {"tradeName": "Hostsharing eG"},
"holder": {"tradeName": "Second e.K."}, "holder": {"tradeName": "Second e.K."},
@ -199,10 +199,10 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
"emailAddresses": { "main": "contact-admin@thirdcontact.example.com" } "emailAddresses": { "main": "contact-admin@thirdcontact.example.com" }
} }
}, },
"debitorNumber": 1000313, "debitorNumber": "D-1000313",
"debitorNumberSuffix": "13", "debitorNumberSuffix": "13",
"partner": { "partner": {
"partnerNumber": 10003, "partnerNumber": "P-10003",
"partnerRel": { "partnerRel": {
"anchor": {"tradeName": "Hostsharing eG"}, "anchor": {"tradeName": "Hostsharing eG"},
"holder": {"tradeName": "Third OHG"}, "holder": {"tradeName": "Third OHG"},
@ -237,15 +237,15 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
.header("current-subject", "superuser-alex@hostsharing.net") .header("current-subject", "superuser-alex@hostsharing.net")
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/debitors?debitorNumber=1000212") .get("http://localhost/api/hs/office/debitors?debitorNumber=D-1000212")
.then().log().all().assertThat() .then().log().all().assertThat()
.statusCode(200) .statusCode(200)
.contentType("application/json") .contentType("application/json")
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
[ [
{ {
"debitorNumber": 1000212, "debitorNumber": "D-1000212",
"partner": { "partnerNumber": 10002 }, "partner": { "partnerNumber": "P-10002" },
"debitorRel": { "debitorRel": {
"contact": { "caption": "second contact" } "contact": { "caption": "second contact" }
}, },
@ -260,7 +260,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
} }
@Nested @Nested
class AddDebitor { class PostNewDebitor {
@Test @Test
void globalAdmin_withoutAssumedRole_canAddDebitorWithBankAccount() { void globalAdmin_withoutAssumedRole_canAddDebitorWithBankAccount() {
@ -436,7 +436,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
} }
@Nested @Nested
class GetDebitor { class GetSingleDebitorByUuid {
@Test @Test
void globalAdmin_withoutAssumedRole_canGetArbitraryDebitor() { void globalAdmin_withoutAssumedRole_canGetArbitraryDebitor() {
@ -534,8 +534,8 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
.contentType("application/json") .contentType("application/json")
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
{ {
"debitorNumber": 1000111, "debitorNumber": "D-1000111",
"partner": { "partnerNumber": 10001 }, "partner": { "partnerNumber": "P-10001" },
"debitorRel": { "contact": { "caption": "first contact" } }, "debitorRel": { "contact": { "caption": "first contact" } },
"refundBankAccount": null "refundBankAccount": null
} }
@ -581,10 +581,10 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
"mark": null, "mark": null,
"contact": { "caption": "fourth contact" } "contact": { "caption": "fourth contact" }
}, },
"debitorNumber": 10004${debitorNumberSuffix}, "debitorNumber": "D-10004${debitorNumberSuffix}",
"debitorNumberSuffix": "${debitorNumberSuffix}", "debitorNumberSuffix": "${debitorNumberSuffix}",
"partner": { "partner": {
"partnerNumber": 10004, "partnerNumber": "P-10004",
"partnerRel": { "partnerRel": {
"anchor": { "tradeName": "Hostsharing eG" }, "anchor": { "tradeName": "Hostsharing eG" },
"holder": { "tradeName": "Fourth eG" }, "holder": { "tradeName": "Fourth eG" },

View File

@ -65,9 +65,9 @@ class HsOfficeDebitorEntityUnitTest {
.build()) .build())
.build(); .build();
final var result = given.getDebitorNumber(); final var result = given.getTaggedDebitorNumber();
assertThat(result).isEqualTo(1234567); assertThat(result).isEqualTo("D-1234567");
} }
@Test @Test
@ -78,7 +78,7 @@ class HsOfficeDebitorEntityUnitTest {
.partner(null) .partner(null)
.build(); .build();
final var result = given.getDebitorNumber(); final var result = given.getTaggedDebitorNumber();
assertThat(result).isNull(); assertThat(result).isNull();
} }
@ -91,7 +91,7 @@ class HsOfficeDebitorEntityUnitTest {
.partner(HsOfficePartnerEntity.builder().build()) .partner(HsOfficePartnerEntity.builder().build())
.build(); .build();
final var result = given.getDebitorNumber(); final var result = given.getTaggedDebitorNumber();
assertThat(result).isNull(); assertThat(result).isNull();
} }
@ -106,7 +106,7 @@ class HsOfficeDebitorEntityUnitTest {
.build()) .build())
.build(); .build();
final var result = given.getDebitorNumber(); final var result = given.getTaggedDebitorNumber();
assertThat(result).isNull(); assertThat(result).isNull();
} }

View File

@ -77,24 +77,24 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
[ [
{ {
"partner": { "partnerNumber": 10001 }, "partner": { "partnerNumber": "P-10001" },
"memberNumber": 1000101, "memberNumber": "M-1000101",
"memberNumberSuffix": "01", "memberNumberSuffix": "01",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
"status": "ACTIVE" "status": "ACTIVE"
}, },
{ {
"partner": { "partnerNumber": 10002 }, "partner": { "partnerNumber": "P-10002" },
"memberNumber": 1000202, "memberNumber": "M-1000202",
"memberNumberSuffix": "02", "memberNumberSuffix": "02",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
"status": "ACTIVE" "status": "ACTIVE"
}, },
{ {
"partner": { "partnerNumber": 10003 }, "partner": { "partnerNumber": "P-10003" },
"memberNumber": 1000303, "memberNumber": "M-1000303",
"memberNumberSuffix": "03", "memberNumberSuffix": "03",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
@ -124,8 +124,8 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
[ [
{ {
"partner": { "partnerNumber": 10001 }, "partner": { "partnerNumber": "P-10001" },
"memberNumber": 1000101, "memberNumber": "M-1000101",
"memberNumberSuffix": "01", "memberNumberSuffix": "01",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
@ -144,7 +144,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
.header("current-subject", "superuser-alex@hostsharing.net") .header("current-subject", "superuser-alex@hostsharing.net")
.port(port) .port(port)
.when() .when()
.queryParam("memberNumber", 1000202 ) .queryParam("memberNumber", "M-1000202" )
.get("http://localhost/api/hs/office/memberships") .get("http://localhost/api/hs/office/memberships")
.then().log().all().assertThat() .then().log().all().assertThat()
.statusCode(200) .statusCode(200)
@ -152,8 +152,8 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
[ [
{ {
"partner": { "partnerNumber": 10002 }, "partner": { "partnerNumber": "P-10002" },
"memberNumber": 1000202, "memberNumber": "M-1000202",
"memberNumberSuffix": "02", "memberNumberSuffix": "02",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
@ -195,8 +195,8 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
.statusCode(201) .statusCode(201)
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body("uuid", isUuidValid()) .body("uuid", isUuidValid())
.body("partner.partnerNumber", is(10003)) .body("partner.partnerNumber", is("P-10003"))
.body("memberNumber", is(expectedMemberNumber)) .body("memberNumber", is("M-" + expectedMemberNumber))
.body("memberNumberSuffix", is(givenMemberSuffix)) .body("memberNumberSuffix", is(givenMemberSuffix))
.body("validFrom", is("2022-10-13")) .body("validFrom", is("2022-10-13"))
.body("validTo", equalTo(null)) .body("validTo", equalTo(null))
@ -230,8 +230,8 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
.contentType("application/json") .contentType("application/json")
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
{ {
"partner": { "partnerNumber": 10001 }, "partner": { "partnerNumber": "P-10001" },
"memberNumber": 1000101, "memberNumber": "M-1000101",
"memberNumberSuffix": "01", "memberNumberSuffix": "01",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
@ -256,7 +256,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
} }
@Test @Test
void parnerRelAgent_canGetRelatedMembership() { void partnerRelAgent_canGetRelatedMembership() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMembershipUuid = membershipRepo.findMembershipByMemberNumber(1000303).getUuid(); final var givenMembershipUuid = membershipRepo.findMembershipByMemberNumber(1000303).getUuid();
@ -272,8 +272,8 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
.contentType("application/json") .contentType("application/json")
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
{ {
"partner": { "partnerNumber": 10003 }, "partner": { "partnerNumber": "P-10003" },
"memberNumber": 1000303, "memberNumber": "M-1000303",
"memberNumberSuffix": "03", "memberNumberSuffix": "03",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": null, "validTo": null,
@ -309,7 +309,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
.statusCode(200) .statusCode(200)
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body("uuid", isUuidValid()) .body("uuid", isUuidValid())
.body("partner.partnerNumber", is(givenMembership.getPartner().getPartnerNumber())) .body("partner.partnerNumber", is("P-" + givenMembership.getPartner().getPartnerNumber()))
.body("memberNumberSuffix", is(givenMembership.getMemberNumberSuffix())) .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"))

View File

@ -46,14 +46,14 @@ public class HsOfficeMembershipControllerRestTest {
EntityManagerWrapper em; EntityManagerWrapper em;
@Nested @Nested
class GetMemberships { class GetListOfMemberships {
@Test @Test
void findMembershipByNonExistingMemberNumberReturnsEmptyList() throws Exception { void findMembershipByNonExistingMemberNumberReturnsEmptyList() throws Exception {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/memberships?memberNumber=12345") .get("/api/hs/office/memberships?memberNumber=M-1234501")
.header("current-subject", "superuser-alex@hostsharing.net") .header("current-subject", "superuser-alex@hostsharing.net")
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
@ -73,7 +73,7 @@ public class HsOfficeMembershipControllerRestTest {
} }
@Nested @Nested
class AddMembership { class PostNewMembership {
@Test @Test
void respondBadRequest_ifPartnerUuidIsMissing() throws Exception { void respondBadRequest_ifPartnerUuidIsMissing() throws Exception {

View File

@ -71,11 +71,11 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
.contentType("application/json") .contentType("application/json")
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
[ [
{ partnerNumber: 10001 }, { partnerNumber: "P-10001" },
{ partnerNumber: 10002 }, { partnerNumber: "P-10002" },
{ partnerNumber: 10003 }, { partnerNumber: "P-10003" },
{ partnerNumber: 10004 }, { partnerNumber: "P-10004" },
{ partnerNumber: 10010 } { partnerNumber: "P-10010" }
] ]
""")); """));
// @formatter:on // @formatter:on
@ -100,7 +100,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
"partnerNumber": "20002", "partnerNumber": "P-20002",
"partnerRel": { "partnerRel": {
"anchor.uuid": "%s", "anchor.uuid": "%s",
"holder.uuid": "%s", "holder.uuid": "%s",
@ -123,7 +123,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
{ {
"partnerNumber": 20002, "partnerNumber": "P-20002",
"partnerRel": { "partnerRel": {
"anchor": { "tradeName": "Hostsharing eG" }, "anchor": { "tradeName": "Hostsharing eG" },
"holder": { "tradeName": "Third OHG" }, "holder": { "tradeName": "Third OHG" },
@ -159,7 +159,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
"partnerNumber": "20003", "partnerNumber": "P-20003",
"partnerRel": { "partnerRel": {
"anchor.uuid": "%s", "anchor.uuid": "%s",
"holder.uuid": "%s", "holder.uuid": "%s",
@ -197,7 +197,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
"partnerNumber": "20004", "partnerNumber": "P-20004",
"partnerRel": { "partnerRel": {
"anchor.uuid": "%s", "anchor.uuid": "%s",
"holder.uuid": "%s", "holder.uuid": "%s",
@ -247,7 +247,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
.contentType("application/json") .contentType("application/json")
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
{ {
"partnerNumber": 10001, "partnerNumber": "P-10001",
"partnerRel": { "partnerRel": {
"anchor": { "tradeName": "Hostsharing eG" }, "anchor": { "tradeName": "Hostsharing eG" },
"holder": { "tradeName": "First GmbH" }, "holder": { "tradeName": "First GmbH" },
@ -320,7 +320,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
"partnerNumber": "20011", "partnerNumber": "P-20011",
"partnerRel.uuid": "%s", "partnerRel.uuid": "%s",
"details": { "details": {
"registrationOffice": "Temp Registergericht Aurich", "registrationOffice": "Temp Registergericht Aurich",
@ -339,7 +339,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
{ {
"partnerNumber": 20011, "partnerNumber": "P-20011",
"partnerRel": { "partnerRel": {
"anchor": { "tradeName": "Hostsharing eG" }, "anchor": { "tradeName": "Hostsharing eG" },
"holder": { "tradeName": "Third OHG" }, "holder": { "tradeName": "Third OHG" },

View File

@ -99,7 +99,7 @@ class HsOfficePartnerControllerRestTest {
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
"partnerNumber": "20002", "partnerNumber": "P-20002",
"partnerRel": { "partnerRel": {
"anchor.uuid": "%s", "anchor.uuid": "%s",
"holder.uuid": "%s", "holder.uuid": "%s",
@ -136,7 +136,7 @@ class HsOfficePartnerControllerRestTest {
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
"partnerNumber": "20002", "partnerNumber": "P-20002",
"partnerRel": { "partnerRel": {
"anchor.uuid": "%s", "anchor.uuid": "%s",
"holder.uuid": "%s", "holder.uuid": "%s",

View File

@ -8,8 +8,9 @@ import net.hostsharing.hsadminng.hs.office.scenarios.contact.ReplaceContactData;
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateExternalDebitorForPartner; import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateExternalDebitorForPartner;
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSelfDebitorForPartner; import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSelfDebitorForPartner;
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSepaMandateForDebitor; import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSepaMandateForDebitor;
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.FinallyDeleteSepaMandateForDebitor; import net.hostsharing.hsadminng.hs.office.scenarios.debitor.DeleteDebitor;
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.DontDeleteDefaultDebitor; import net.hostsharing.hsadminng.hs.office.scenarios.debitor.DontDeleteDefaultDebitor;
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.FinallyDeleteSepaMandateForDebitor;
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.InvalidateSepaMandateForDebitor; import net.hostsharing.hsadminng.hs.office.scenarios.debitor.InvalidateSepaMandateForDebitor;
import net.hostsharing.hsadminng.hs.office.scenarios.membership.CancelMembership; import net.hostsharing.hsadminng.hs.office.scenarios.membership.CancelMembership;
import net.hostsharing.hsadminng.hs.office.scenarios.membership.CreateMembership; import net.hostsharing.hsadminng.hs.office.scenarios.membership.CreateMembership;
@ -20,10 +21,9 @@ import net.hostsharing.hsadminng.hs.office.scenarios.membership.coopshares.Creat
import net.hostsharing.hsadminng.hs.office.scenarios.membership.coopshares.CreateCoopSharesRevertTransaction; import net.hostsharing.hsadminng.hs.office.scenarios.membership.coopshares.CreateCoopSharesRevertTransaction;
import net.hostsharing.hsadminng.hs.office.scenarios.membership.coopshares.CreateCoopSharesSubscriptionTransaction; import net.hostsharing.hsadminng.hs.office.scenarios.membership.coopshares.CreateCoopSharesSubscriptionTransaction;
import net.hostsharing.hsadminng.hs.office.scenarios.partner.AddOperationsContactToPartner; import net.hostsharing.hsadminng.hs.office.scenarios.partner.AddOperationsContactToPartner;
import net.hostsharing.hsadminng.hs.office.scenarios.partner.CreatePartner;
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.DeleteDebitor;
import net.hostsharing.hsadminng.hs.office.scenarios.partner.DeletePartner;
import net.hostsharing.hsadminng.hs.office.scenarios.partner.AddRepresentativeToPartner; import net.hostsharing.hsadminng.hs.office.scenarios.partner.AddRepresentativeToPartner;
import net.hostsharing.hsadminng.hs.office.scenarios.partner.CreatePartner;
import net.hostsharing.hsadminng.hs.office.scenarios.partner.DeletePartner;
import net.hostsharing.hsadminng.hs.office.scenarios.person.ShouldUpdatePersonData; import net.hostsharing.hsadminng.hs.office.scenarios.person.ShouldUpdatePersonData;
import net.hostsharing.hsadminng.hs.office.scenarios.subscription.RemoveOperationsContactFromPartner; import net.hostsharing.hsadminng.hs.office.scenarios.subscription.RemoveOperationsContactFromPartner;
import net.hostsharing.hsadminng.hs.office.scenarios.subscription.SubscribeToMailinglist; import net.hostsharing.hsadminng.hs.office.scenarios.subscription.SubscribeToMailinglist;
@ -55,10 +55,10 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Test @Test
@Order(1010) @Order(1010)
@Produces(explicitly = "Partner: P-31010 - Test AG", implicitly = {"Person: Test AG", "Contact: Test AG - Hamburg"}) @Produces(explicitly = "Partner: P-31010 - Test AG", implicitly = { "Person: Test AG", "Contact: Test AG - Hamburg" })
void shouldCreateLegalPersonAsPartner() { void shouldCreateLegalPersonAsPartner() {
new CreatePartner(this) new CreatePartner(this)
.given("partnerNumber", 31010) .given("partnerNumber", "P-31010")
.given("personType", "LEGAL_PERSON") .given("personType", "LEGAL_PERSON")
.given("tradeName", "Test AG") .given("tradeName", "Test AG")
.given("contactCaption", "Test AG - Hamburg") .given("contactCaption", "Test AG - Hamburg")
@ -77,10 +77,11 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Test @Test
@Order(1011) @Order(1011)
@Produces(explicitly = "Partner: P-31011 - Michelle Matthieu", implicitly = {"Person: Michelle Matthieu", "Contact: Michelle Matthieu"}) @Produces(explicitly = "Partner: P-31011 - Michelle Matthieu", implicitly = { "Person: Michelle Matthieu",
"Contact: Michelle Matthieu" })
void shouldCreateNaturalPersonAsPartner() { void shouldCreateNaturalPersonAsPartner() {
new CreatePartner(this) new CreatePartner(this)
.given("partnerNumber", 31011) .given("partnerNumber", "P-31011")
.given("personType", "NATURAL_PERSON") .given("personType", "NATURAL_PERSON")
.given("givenName", "Michelle") .given("givenName", "Michelle")
.given("familyName", "Matthieu") .given("familyName", "Matthieu")
@ -148,7 +149,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Order(1090) @Order(1090)
void shouldDeletePartner() { void shouldDeletePartner() {
new DeletePartner(this) new DeletePartner(this)
.given("partnerNumber", 31020) .given("partnerNumber", "P-31020")
.doRun(); .doRun();
} }
@ -191,16 +192,16 @@ class HsOfficeScenarioTests extends ScenarioTest {
.given("partnerName", "Test AG") .given("partnerName", "Test AG")
.given("newContactCaption", "Test AG - China") .given("newContactCaption", "Test AG - China")
.given("newPostalAddress", """ .given("newPostalAddress", """
"firm": "Test AG", "firm": "Test AG",
"name": "Fi Zhong-Kha", "name": "Fi Zhong-Kha",
"building": "Thi Chi Koh Building", "building": "Thi Chi Koh Building",
"street": "No.2 Commercial Second Street", "street": "No.2 Commercial Second Street",
"district": "Niushan Wei Wu", "district": "Niushan Wei Wu",
"city": "Dongguan City", "city": "Dongguan City",
"province": "Guangdong Province", "province": "Guangdong Province",
"country": "China" "country": "China"
""") """)
.given("newOfficePhoneNumber", "++15 999 654321" ) .given("newOfficePhoneNumber", "++15 999 654321")
.given("newEmailAddress", "norden@test-ag.example.org") .given("newEmailAddress", "norden@test-ag.example.org")
.doRun(); .doRun();
} }
@ -218,9 +219,9 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Test @Test
@Order(2010) @Order(2010)
@Requires("Partner: P-31010 - Test AG") @Requires("Partner: P-31010 - Test AG")
@Produces("Debitor: Test AG - main debitor") @Produces("Debitor: D-3101000 - Test AG - main debitor")
void shouldCreateSelfDebitorForPartner() { void shouldCreateSelfDebitorForPartner() {
new CreateSelfDebitorForPartner(this, "Debitor: Test AG - main debitor") new CreateSelfDebitorForPartner(this)
.given("partnerPersonTradeName", "Test AG") .given("partnerPersonTradeName", "Test AG")
.given("billingContactCaption", "Test AG - billing department") .given("billingContactCaption", "Test AG - billing department")
.given("billingContactEmailAddress", "billing@test-ag.example.org") .given("billingContactEmailAddress", "billing@test-ag.example.org")
@ -238,7 +239,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Test @Test
@Order(2011) @Order(2011)
@Requires("Person: Test AG") @Requires("Person: Test AG")
@Produces("Debitor: Billing GmbH") @Produces("Debitor: D-3101001 - Test AG - main debitor")
void shouldCreateExternalDebitorForPartner() { void shouldCreateExternalDebitorForPartner() {
new CreateExternalDebitorForPartner(this) new CreateExternalDebitorForPartner(this)
.given("partnerPersonTradeName", "Test AG") .given("partnerPersonTradeName", "Test AG")
@ -258,9 +259,10 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Test @Test
@Order(2020) @Order(2020)
@Requires("Person: Test AG") @Requires("Person: Test AG")
@Produces(explicitly = "Debitor: D-3101000 - Test AG - delete debitor", permanent = false)
void shouldDeleteDebitor() { void shouldDeleteDebitor() {
new DeleteDebitor(this) new DeleteDebitor(this)
.given("partnerNumber", 31020) .given("partnerNumber", "P-31020")
.given("debitorSuffix", "02") .given("debitorSuffix", "02")
.doRun(); .doRun();
} }
@ -271,7 +273,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Disabled("see TODO.spec in DontDeleteDefaultDebitor") @Disabled("see TODO.spec in DontDeleteDefaultDebitor")
void shouldNotDeleteDefaultDebitor() { void shouldNotDeleteDefaultDebitor() {
new DontDeleteDefaultDebitor(this) new DontDeleteDefaultDebitor(this)
.given("partnerNumber", 31010) .given("partnerNumber", "P-31010")
.given("debitorSuffix", "00") .given("debitorSuffix", "00")
.doRun(); .doRun();
} }
@ -283,7 +285,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
void shouldCreateSepaMandateForDebitor() { void shouldCreateSepaMandateForDebitor() {
new CreateSepaMandateForDebitor(this) new CreateSepaMandateForDebitor(this)
// existing debitor // existing debitor
.given("debitorNumber", "3101000") .given("debitorNumber", "D-3101000")
// new sepa-mandate // new sepa-mandate
.given("mandateReference", "Test AG - main debitor") .given("mandateReference", "Test AG - main debitor")
@ -337,7 +339,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Produces("Coop-Shares SUBSCRIPTION Transaction") @Produces("Coop-Shares SUBSCRIPTION Transaction")
void shouldSubscribeCoopShares() { void shouldSubscribeCoopShares() {
new CreateCoopSharesSubscriptionTransaction(this) new CreateCoopSharesSubscriptionTransaction(this)
.given("memberNumber", "3101000") .given("memberNumber", "M-3101000")
.given("reference", "sign 2024-01-15") .given("reference", "sign 2024-01-15")
.given("shareCount", 100) .given("shareCount", 100)
.given("comment", "Signing the Membership") .given("comment", "Signing the Membership")
@ -350,7 +352,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Requires("Membership: M-3101000 - Test AG") @Requires("Membership: M-3101000 - Test AG")
void shouldRevertCoopSharesSubscription() { void shouldRevertCoopSharesSubscription() {
new CreateCoopSharesRevertTransaction(this) new CreateCoopSharesRevertTransaction(this)
.given("memberNumber", "3101000") .given("memberNumber", "M-3101000")
.given("comment", "reverting some incorrect transaction") .given("comment", "reverting some incorrect transaction")
.given("dateOfIncorrectTransaction", "2024-02-15") .given("dateOfIncorrectTransaction", "2024-02-15")
.doRun(); .doRun();
@ -362,7 +364,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Produces("Coop-Shares CANCELLATION Transaction") @Produces("Coop-Shares CANCELLATION Transaction")
void shouldCancelCoopSharesSubscription() { void shouldCancelCoopSharesSubscription() {
new CreateCoopSharesCancellationTransaction(this) new CreateCoopSharesCancellationTransaction(this)
.given("memberNumber", "3101000") .given("memberNumber", "M-3101000")
.given("reference", "cancel 2024-01-15") .given("reference", "cancel 2024-01-15")
.given("sharesToCancel", 8) .given("sharesToCancel", 8)
.given("comment", "Cancelling 8 Shares") .given("comment", "Cancelling 8 Shares")
@ -376,9 +378,9 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Produces("Coop-Assets DEPOSIT Transaction") @Produces("Coop-Assets DEPOSIT Transaction")
void shouldSubscribeCoopAssets() { void shouldSubscribeCoopAssets() {
new CreateCoopAssetsDepositTransaction(this) new CreateCoopAssetsDepositTransaction(this)
.given("memberNumber", "3101000") .given("memberNumber", "M-3101000")
.given("reference", "sign 2024-01-15") .given("reference", "sign 2024-01-15")
.given("assetValue", 100*64) .given("assetValue", 100 * 64)
.given("comment", "disposal for initial shares") .given("comment", "disposal for initial shares")
.given("transactionDate", "2024-01-15") .given("transactionDate", "2024-01-15")
.doRun(); .doRun();
@ -386,10 +388,10 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Test @Test
@Order(4302) @Order(4302)
@Requires("Membership: M-3101000 - Test AG") @Requires("Coop-Assets DEPOSIT Transaction")
void shouldRevertCoopAssetsSubscription() { void shouldRevertCoopAssetsSubscription() {
new CreateCoopAssetsRevertTransaction(this) new CreateCoopAssetsRevertTransaction(this)
.given("memberNumber", "3101000") .given("memberNumber", "M-3101000")
.given("comment", "reverting some incorrect transaction") .given("comment", "reverting some incorrect transaction")
.given("dateOfIncorrectTransaction", "2024-02-15") .given("dateOfIncorrectTransaction", "2024-02-15")
.doRun(); .doRun();
@ -401,9 +403,9 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Produces("Coop-Assets DISBURSAL Transaction") @Produces("Coop-Assets DISBURSAL Transaction")
void shouldDisburseCoopAssets() { void shouldDisburseCoopAssets() {
new CreateCoopAssetsDisbursalTransaction(this) new CreateCoopAssetsDisbursalTransaction(this)
.given("memberNumber", "3101000") .given("memberNumber", "M-3101000")
.given("reference", "cancel 2024-01-15") .given("reference", "cancel 2024-01-15")
.given("valueToDisburse", 8*64) .given("valueToDisburse", 8 * 64)
.given("comment", "disbursal according to shares cancellation") .given("comment", "disbursal according to shares cancellation")
.given("transactionDate", "2024-02-15") .given("transactionDate", "2024-02-15")
.doRun(); .doRun();
@ -414,7 +416,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Requires("Membership: M-3101000 - Test AG") @Requires("Membership: M-3101000 - Test AG")
void shouldCancelMembershipOfPartner() { void shouldCancelMembershipOfPartner() {
new CancelMembership(this) new CancelMembership(this)
.given("memberNumber", "3101000") .given("memberNumber", "M-3101000")
.given("validTo", "2025-12-30") .given("validTo", "2025-12-30")
.given("newStatus", "CANCELLED") .given("newStatus", "CANCELLED")
.doRun(); .doRun();

View File

@ -12,4 +12,5 @@ public @interface Produces {
String value() default ""; // same as explicitly, makes it possible to omit the property name String value() default ""; // same as explicitly, makes it possible to omit the property name
String explicitly() default ""; // same as value String explicitly() default ""; // same as value
String[] implicitly() default {}; String[] implicitly() default {};
boolean permanent() default true; // false means that the object gets deleted again in the process
} }

View File

@ -113,6 +113,8 @@ public abstract class ScenarioTest extends ContextBasedTest {
// and it does not produce anything we already have (would cause errors) // and it does not produce anything we already have (would cause errors)
SetUtils.intersection(testMethodProduces, knowVariables().keySet()).isEmpty() SetUtils.intersection(testMethodProduces, knowVariables().keySet()).isEmpty()
) { ) {
assertThat(producesAnnot.permanent()).as("cannot depend on non-permanent producer: " + potentialProducerMethod);
// then we recursively produce the pre-requisites of the producer method // then we recursively produce the pre-requisites of the producer method
callRequiredProducers(potentialProducerMethod); callRequiredProducers(potentialProducerMethod);

View File

@ -9,8 +9,8 @@ import static org.springframework.http.HttpStatus.OK;
public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPartner> { public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPartner> {
public CreateSelfDebitorForPartner(final ScenarioTest testSuite, final String resultAlias) { public CreateSelfDebitorForPartner(final ScenarioTest testSuite) {
super(testSuite, resultAlias); super(testSuite);
} }
@Override @Override

View File

@ -9,7 +9,7 @@ public class DeleteDebitor extends UseCase<DeleteDebitor> {
public DeleteDebitor(final ScenarioTest testSuite) { public DeleteDebitor(final ScenarioTest testSuite) {
super(testSuite); super(testSuite);
requires("Debitor: Test AG - delete debitor", alias -> new CreateSelfDebitorForPartner(testSuite, alias) requires("Debitor: Test AG - delete debitor", alias -> new CreateSelfDebitorForPartner(testSuite)
.given("partnerPersonTradeName", "Test AG") .given("partnerPersonTradeName", "Test AG")
.given("billingContactCaption", "Test AG - billing department") .given("billingContactCaption", "Test AG - billing department")
.given("billingContactEmailAddress", "billing@test-ag.example.org") .given("billingContactEmailAddress", "billing@test-ag.example.org")

View File

@ -9,7 +9,7 @@ public class CreateCoopAssetsRevertTransaction extends CreateCoopAssetsTransacti
requires("CoopAssets-Transaction with incorrect assetValue", alias -> requires("CoopAssets-Transaction with incorrect assetValue", alias ->
new CreateCoopAssetsDepositTransaction(testSuite) new CreateCoopAssetsDepositTransaction(testSuite)
.given("memberNumber", "3101000") .given("memberNumber", "%{memberNumber}")
.given("reference", "sign %{dateOfIncorrectTransaction}") // same as revertedAssetTx .given("reference", "sign %{dateOfIncorrectTransaction}") // same as revertedAssetTx
.given("assetValue", 10) .given("assetValue", 10)
.given("comment", "coop-assets deposit transaction with wrong asset value") .given("comment", "coop-assets deposit transaction with wrong asset value")

View File

@ -9,7 +9,7 @@ public class CreateCoopSharesRevertTransaction extends CreateCoopSharesTransacti
requires("CoopShares-Transaction with incorrect shareCount", alias -> requires("CoopShares-Transaction with incorrect shareCount", alias ->
new CreateCoopSharesSubscriptionTransaction(testSuite) new CreateCoopSharesSubscriptionTransaction(testSuite)
.given("memberNumber", "3101000") .given("memberNumber", "%{memberNumber}")
.given("reference", "sign %{dateOfIncorrectTransaction}") // same as revertedShareTx .given("reference", "sign %{dateOfIncorrectTransaction}") // same as revertedShareTx
.given("shareCount", 100) .given("shareCount", 100)
.given("comment", "coop-shares subscription transaction with wrong share count") .given("comment", "coop-shares subscription transaction with wrong share count")

View File

@ -72,21 +72,21 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
[ [
{ {
"debitor": { "debitorNumber": 1000111 }, "debitor": { "debitorNumber": "D-1000111" },
"bankAccount": { "holder": "First GmbH" }, "bankAccount": { "holder": "First GmbH" },
"reference": "ref-10001-11", "reference": "ref-10001-11",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": "2026-12-31" "validTo": "2026-12-31"
}, },
{ {
"debitor": { "debitorNumber": 1000212 }, "debitor": { "debitorNumber": "D-1000212" },
"bankAccount": { "holder": "Second e.K." }, "bankAccount": { "holder": "Second e.K." },
"reference": "ref-10002-12", "reference": "ref-10002-12",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
"validTo": "2026-12-31" "validTo": "2026-12-31"
}, },
{ {
"debitor": { "debitorNumber": 1000313 }, "debitor": { "debitorNumber": "D-1000313" },
"bankAccount": { "holder": "Third OHG" }, "bankAccount": { "holder": "Third OHG" },
"reference": "ref-10003-13", "reference": "ref-10003-13",
"validFrom": "2022-10-01", "validFrom": "2022-10-01",
@ -113,7 +113,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
[ [
{ {
"debitor": { "debitorNumber": 1000111 }, "debitor": { "debitorNumber": "D-1000111" },
"bankAccount": { "bankAccount": {
"iban": "DE02120300000000202051", "iban": "DE02120300000000202051",
"holder": "First GmbH" "holder": "First GmbH"
@ -158,7 +158,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
.statusCode(201) .statusCode(201)
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body("uuid", isUuidValid()) .body("uuid", isUuidValid())
.body("debitor.partner.partnerNumber", is(10003)) .body("debitor.partner.partnerNumber", is("P-10003"))
.body("bankAccount.iban", is("DE02200505501015871393")) .body("bankAccount.iban", is("DE02200505501015871393"))
.body("reference", is("temp ref CAT A")) .body("reference", is("temp ref CAT A"))
.body("validFrom", is("2022-10-13")) .body("validFrom", is("2022-10-13"))
@ -280,7 +280,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
.contentType("application/json") .contentType("application/json")
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
{ {
"debitor": { "debitorNumber": 1000111 }, "debitor": { "debitorNumber": "D-1000111" },
"bankAccount": { "bankAccount": {
"holder": "First GmbH", "holder": "First GmbH",
"iban": "DE02120300000000202051" "iban": "DE02120300000000202051"
@ -327,7 +327,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
.contentType("application/json") .contentType("application/json")
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
{ {
"debitor": { "debitorNumber": 1000111 }, "debitor": { "debitorNumber": "D-1000111" },
"bankAccount": { "bankAccount": {
"holder": "First GmbH", "holder": "First GmbH",
"iban": "DE02120300000000202051" "iban": "DE02120300000000202051"
@ -367,7 +367,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
.statusCode(200) .statusCode(200)
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body("uuid", isUuidValid()) .body("uuid", isUuidValid())
.body("debitor.debitorNumber", is(1000111)) .body("debitor.debitorNumber", is("D-1000111"))
.body("bankAccount.iban", is("DE02120300000000202051")) .body("bankAccount.iban", is("DE02120300000000202051"))
.body("reference", is("temp ref CAT Z - patched")) .body("reference", is("temp ref CAT Z - patched"))
.body("agreement", is("2020-06-01")) .body("agreement", is("2020-06-01"))
@ -410,7 +410,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
.statusCode(200) .statusCode(200)
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body("uuid", isUuidValid()) .body("uuid", isUuidValid())
.body("debitor.debitorNumber", is(1000111)) .body("debitor.debitorNumber", is("D-1000111"))
.body("bankAccount.iban", is("DE02120300000000202051")) .body("bankAccount.iban", is("DE02120300000000202051"))
.body("reference", is("temp ref CAT Z")) .body("reference", is("temp ref CAT Z"))
.body("validFrom", is("2022-11-01")) .body("validFrom", is("2022-11-01"))

View File

@ -2,13 +2,13 @@ package net.hostsharing.hsadminng.rbac.test;
import lombok.*; import lombok.*;
import lombok.experimental.FieldNameConstants; import lombok.experimental.FieldNameConstants;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.repr.Stringify.stringify;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
class StringifyUnitTest { class StringifyUnitTest {

View File

@ -0,0 +1,22 @@
package net.hostsharing.hsadminng.repr;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
class TaggedNumberUnitTest {
@Test
void cropsProperTag() {
assertThat(TaggedNumber.cropTag("P-", "P-12345")).isEqualTo(12345);
}
@Test
void throwsExceptionForImproperTag() {
final var exception = catchThrowable(() -> TaggedNumber.cropTag("P-", "X-12345"));
assertThat(exception).isInstanceOf(IllegalArgumentException.class);
assertThat(exception.getMessage()).isEqualTo("Expected P-... but got: X-12345");
}
}