debitornumbersuffix-as-string (#30)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: #30
Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
This commit is contained in:
Michael Hoennig 2024-04-02 13:09:12 +02:00
parent 87af20a3a1
commit 277369a960
11 changed files with 33 additions and 24 deletions

View File

@ -16,6 +16,7 @@ import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction; import org.hibernate.annotations.NotFoundAction;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.validation.constraints.Pattern;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.util.UUID;
@ -45,6 +46,7 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
public class HsOfficeDebitorEntity implements HasUuid, Stringifyable { public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
public static final String DEBITOR_NUMBER_TAG = "D-"; public static final String DEBITOR_NUMBER_TAG = "D-";
public static final String TWO_DECIMAL_DIGITS = "^([0-9]{2})$";
private static Stringify<HsOfficeDebitorEntity> stringify = private static Stringify<HsOfficeDebitorEntity> stringify =
stringify(HsOfficeDebitorEntity.class, "debitor") stringify(HsOfficeDebitorEntity.class, "debitor")
@ -75,8 +77,9 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
@NotFound(action = NotFoundAction.IGNORE) @NotFound(action = NotFoundAction.IGNORE)
private HsOfficePartnerEntity partner; private HsOfficePartnerEntity partner;
@Column(name = "debitornumbersuffix", columnDefinition = "numeric(2)") @Column(name = "debitornumbersuffix", length = 2)
private Byte debitorNumberSuffix; // TODO maybe rather as a formatted String? @Pattern(regexp = TWO_DECIMAL_DIGITS)
private String debitorNumberSuffix;
@ManyToOne(cascade = { PERSIST, MERGE, REFRESH, DETACH }, optional = false) @ManyToOne(cascade = { PERSIST, MERGE, REFRESH, DETACH }, optional = false)
@JoinColumn(name = "debitorreluuid", nullable = false) @JoinColumn(name = "debitorreluuid", nullable = false)
@ -109,7 +112,7 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
.filter(partner -> debitorNumberSuffix != null) .filter(partner -> debitorNumberSuffix != null)
.map(HsOfficePartnerEntity::getPartnerNumber) .map(HsOfficePartnerEntity::getPartnerNumber)
.map(Object::toString) .map(Object::toString)
.map(partnerNumber -> partnerNumber + String.format("%02d", debitorNumberSuffix)) .map(partnerNumber -> partnerNumber + debitorNumberSuffix)
.orElse(null); .orElse(null);
} }
@ -138,7 +141,7 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
JOIN hs_office_relation debitorRel JOIN hs_office_relation debitorRel
ON debitorRel.anchorUuid = partnerRel.holderUuid AND debitorRel.type = 'DEBITOR' ON debitorRel.anchorUuid = partnerRel.holderUuid AND debitorRel.type = 'DEBITOR'
WHERE debitorRel.uuid = debitor.debitorRelUuid) WHERE debitorRel.uuid = debitor.debitorRelUuid)
|| to_char(debitorNumberSuffix, 'fm00') as idName || debitorNumberSuffix as idName
FROM hs_office_debitor AS debitor FROM hs_office_debitor AS debitor
""")) """))
.withRestrictedViewOrderBy(SQL.projection("defaultPrefix")) .withRestrictedViewOrderBy(SQL.projection("defaultPrefix"))

View File

@ -14,6 +14,7 @@ import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.hibernate.annotations.Type; import org.hibernate.annotations.Type;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.validation.constraints.Pattern;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
@ -44,6 +45,7 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
public class HsOfficeMembershipEntity implements HasUuid, Stringifyable { public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
public static final String MEMBER_NUMBER_TAG = "M-"; public static final String MEMBER_NUMBER_TAG = "M-";
public static final String TWO_DECIMAL_DIGITS = "^([0-9]{2})$";
private static Stringify<HsOfficeMembershipEntity> stringify = stringify(HsOfficeMembershipEntity.class) private static Stringify<HsOfficeMembershipEntity> stringify = stringify(HsOfficeMembershipEntity.class)
.withProp(e -> MEMBER_NUMBER_TAG + e.getMemberNumber()) .withProp(e -> MEMBER_NUMBER_TAG + e.getMemberNumber())
@ -61,6 +63,7 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
private HsOfficePartnerEntity partner; private HsOfficePartnerEntity partner;
@Column(name = "membernumbersuffix", length = 2) @Column(name = "membernumbersuffix", length = 2)
@Pattern(regexp = TWO_DECIMAL_DIGITS)
private String memberNumberSuffix; private String memberNumberSuffix;
@Column(name = "validity", columnDefinition = "daterange") @Column(name = "validity", columnDefinition = "daterange")

View File

@ -7,7 +7,7 @@
create table hs_office_debitor create table hs_office_debitor
( (
uuid uuid unique references RbacObject (uuid) initially deferred, uuid uuid unique references RbacObject (uuid) initially deferred,
debitorNumberSuffix numeric(2) not null, debitorNumberSuffix char(2) not null check (debitorNumberSuffix::text ~ '^[0-9][0-9]$'),
debitorRelUuid uuid not null references hs_office_relation(uuid), debitorRelUuid uuid not null references hs_office_relation(uuid),
billable boolean not null default true, billable boolean not null default true,
vatId varchar(24), -- TODO.spec: here or in person? vatId varchar(24), -- TODO.spec: here or in person?

View File

@ -201,7 +201,7 @@ create trigger hs_office_debitor_insert_permission_check_tg
JOIN hs_office_relation debitorRel JOIN hs_office_relation debitorRel
ON debitorRel.anchorUuid = partnerRel.holderUuid AND debitorRel.type = 'DEBITOR' ON debitorRel.anchorUuid = partnerRel.holderUuid AND debitorRel.type = 'DEBITOR'
WHERE debitorRel.uuid = debitor.debitorRelUuid) WHERE debitorRel.uuid = debitor.debitorRelUuid)
|| to_char(debitorNumberSuffix, 'fm00') as idName || debitorNumberSuffix as idName
FROM hs_office_debitor AS debitor FROM hs_office_debitor AS debitor
$idName$); $idName$);
--// --//

View File

@ -10,7 +10,7 @@
*/ */
create or replace procedure createHsOfficeSepaMandateTestData( create or replace procedure createHsOfficeSepaMandateTestData(
forPartnerNumber numeric(5), forPartnerNumber numeric(5),
forDebitorSuffix numeric(2), forDebitorSuffix char(2),
forIban varchar, forIban varchar,
withReference varchar) withReference varchar)
language plpgsql as $$ language plpgsql as $$
@ -48,9 +48,9 @@ end; $$;
do language plpgsql $$ do language plpgsql $$
begin begin
call createHsOfficeSepaMandateTestData(10001, 11, 'DE02120300000000202051', 'ref-10001-11'); call createHsOfficeSepaMandateTestData(10001, '11', 'DE02120300000000202051', 'ref-10001-11');
call createHsOfficeSepaMandateTestData(10002, 12, 'DE02100500000054540402', 'ref-10002-12'); call createHsOfficeSepaMandateTestData(10002, '12', 'DE02100500000054540402', 'ref-10002-12');
call createHsOfficeSepaMandateTestData(10003, 13, 'DE02300209000106531065', 'ref-10003-13'); call createHsOfficeSepaMandateTestData(10003, '13', 'DE02300209000106531065', 'ref-10003-13');
end; end;
$$; $$;
--// --//

View File

@ -12,8 +12,7 @@ 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),
memberNumberSuffix char(2) not null check ( memberNumberSuffix char(2) not null check (memberNumberSuffix::text ~ '^[0-9][0-9]$'),
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,

View File

@ -722,7 +722,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Fourth").get(0); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Fourth").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth contact").get(0); final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth contact").get(0);
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix(++nextDebitorSuffix) .debitorNumberSuffix(nextDebitorSuffix())
.billable(true) .billable(true)
.debitorRel( .debitorRel(
HsOfficeRelationEntity.builder() HsOfficeRelationEntity.builder()
@ -751,4 +751,8 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
System.out.printf("deleted %d entities%n", count); System.out.printf("deleted %d entities%n", count);
}); });
} }
private String nextDebitorSuffix() {
return String.format("%02d", nextDebitorSuffix++);
}
} }

View File

@ -26,7 +26,7 @@ class HsOfficeDebitorEntityUnitTest {
@Test @Test
void toStringContainsPartnerAndContact() { void toStringContainsPartnerAndContact() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)67) .debitorNumberSuffix("67")
.debitorRel(givenDebitorRel) .debitorRel(givenDebitorRel)
.defaultPrefix("som") .defaultPrefix("som")
.partner(HsOfficePartnerEntity.builder() .partner(HsOfficePartnerEntity.builder()
@ -43,7 +43,7 @@ class HsOfficeDebitorEntityUnitTest {
void toShortStringContainsDebitorNumber() { void toShortStringContainsDebitorNumber() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .debitorRel(givenDebitorRel)
.debitorNumberSuffix((byte)67) .debitorNumberSuffix("67")
.partner(HsOfficePartnerEntity.builder() .partner(HsOfficePartnerEntity.builder()
.partnerNumber(12345) .partnerNumber(12345)
.build()) .build())
@ -58,7 +58,7 @@ class HsOfficeDebitorEntityUnitTest {
void getDebitorNumberWithPartnerNumberAndDebitorNumberSuffix() { void getDebitorNumberWithPartnerNumberAndDebitorNumberSuffix() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .debitorRel(givenDebitorRel)
.debitorNumberSuffix((byte)67) .debitorNumberSuffix("67")
.partner(HsOfficePartnerEntity.builder() .partner(HsOfficePartnerEntity.builder()
.partnerNumber(12345) .partnerNumber(12345)
.build()) .build())
@ -73,7 +73,7 @@ class HsOfficeDebitorEntityUnitTest {
void getDebitorNumberWithoutPartnerReturnsNull() { void getDebitorNumberWithoutPartnerReturnsNull() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .debitorRel(givenDebitorRel)
.debitorNumberSuffix((byte)67) .debitorNumberSuffix("67")
.partner(null) .partner(null)
.build(); .build();
@ -86,7 +86,7 @@ class HsOfficeDebitorEntityUnitTest {
void getDebitorNumberWithoutPartnerNumberReturnsNull() { void getDebitorNumberWithoutPartnerNumberReturnsNull() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .debitorRel(givenDebitorRel)
.debitorNumberSuffix((byte)67) .debitorNumberSuffix("67")
.partner(HsOfficePartnerEntity.builder().build()) .partner(HsOfficePartnerEntity.builder().build())
.build(); .build();

View File

@ -89,7 +89,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)21) .debitorNumberSuffix("21")
.debitorRel(HsOfficeRelationEntity.builder() .debitorRel(HsOfficeRelationEntity.builder()
.type(HsOfficeRelationType.DEBITOR) .type(HsOfficeRelationType.DEBITOR)
.anchor(givenPartnerPerson) .anchor(givenPartnerPerson)
@ -121,7 +121,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)21) .debitorNumberSuffix("21")
.debitorRel(HsOfficeRelationEntity.builder() .debitorRel(HsOfficeRelationEntity.builder()
.type(HsOfficeRelationType.DEBITOR) .type(HsOfficeRelationType.DEBITOR)
.anchor(givenPartnerPerson) .anchor(givenPartnerPerson)
@ -156,7 +156,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
final var givenDebitorPerson = one(personRepo.findPersonByOptionalNameLike("Fourth eG")); final var givenDebitorPerson = one(personRepo.findPersonByOptionalNameLike("Fourth eG"));
final var givenContact = one(contactRepo.findContactByOptionalLabelLike("fourth contact")); final var givenContact = one(contactRepo.findContactByOptionalLabelLike("fourth contact"));
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)22) .debitorNumberSuffix("22")
.debitorRel(HsOfficeRelationEntity.builder() .debitorRel(HsOfficeRelationEntity.builder()
.type(HsOfficeRelationType.DEBITOR) .type(HsOfficeRelationType.DEBITOR)
.anchor(givenPartnerPerson) .anchor(givenPartnerPerson)
@ -613,7 +613,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
final var givenBankAccount = final var givenBankAccount =
bankAccountHolder != null ? one(bankAccountRepo.findByOptionalHolderLike(bankAccountHolder)) : null; bankAccountHolder != null ? one(bankAccountRepo.findByOptionalHolderLike(bankAccountHolder)) : null;
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte)20) .debitorNumberSuffix("20")
.debitorRel(HsOfficeRelationEntity.builder() .debitorRel(HsOfficeRelationEntity.builder()
.type(HsOfficeRelationType.DEBITOR) .type(HsOfficeRelationType.DEBITOR)
.anchor(givenPartnerPerson) .anchor(givenPartnerPerson)

View File

@ -10,7 +10,7 @@ import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TE
@UtilityClass @UtilityClass
public class TestHsOfficeDebitor { public class TestHsOfficeDebitor {
public byte DEFAULT_DEBITOR_SUFFIX = 0; public String DEFAULT_DEBITOR_SUFFIX = "00";
public static final HsOfficeDebitorEntity TEST_DEBITOR = HsOfficeDebitorEntity.builder() public static final HsOfficeDebitorEntity TEST_DEBITOR = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix(DEFAULT_DEBITOR_SUFFIX) .debitorNumberSuffix(DEFAULT_DEBITOR_SUFFIX)

View File

@ -724,7 +724,7 @@ public class ImportOfficeData extends ContextBasedTest {
relations.put(relationId++, debitorRel); relations.put(relationId++, debitorRel);
final var debitor = HsOfficeDebitorEntity.builder() final var debitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix((byte) 0) .debitorNumberSuffix("00")
.partner(partner) .partner(partner)
.debitorRel(debitorRel) .debitorRel(debitorRel)
.defaultPrefix(rec.getString("member_code").replace("hsh00-", "")) .defaultPrefix(rec.getString("member_code").replace("hsh00-", ""))