add ex-partner to Relationship-Type and properly extract distinct persons from contacts.csv

This commit is contained in:
Michael Hoennig 2024-01-18 14:03:06 +01:00
parent d03fb70465
commit 007e1522b7
10 changed files with 242 additions and 189 deletions

View File

@ -53,7 +53,7 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
private HsOfficeDebitorEntity mainDebitor; private HsOfficeDebitorEntity mainDebitor;
@Column(name = "membernumber") @Column(name = "membernumber")
private int memberNumber; private int memberNumber; // TODO: migrate to suffix, like debitorNumberSuffix
@Column(name = "validity", columnDefinition = "daterange") @Column(name = "validity", columnDefinition = "daterange")
@Type(PostgreSQLRangeType.class) @Type(PostgreSQLRangeType.class)

View File

@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.hs.office.relationship;
public enum HsOfficeRelationshipType { public enum HsOfficeRelationshipType {
UNKNOWN, UNKNOWN,
EX_PARTNER,
REPRESENTATIVE, REPRESENTATIVE,
ACCOUNTING, ACCOUNTING,
OPERATIONS OPERATIONS

View File

@ -37,6 +37,7 @@ begin
grantedByRole => globalAdmin() grantedByRole => globalAdmin()
); );
-- TODO: who is admin? the person itself? is it allowed for the person itself or a representative to edit the data?
perform createRoleWithGrants( perform createRoleWithGrants(
hsOfficePersonAdmin(NEW), hsOfficePersonAdmin(NEW),
permissions => array['edit'], permissions => array['edit'],

View File

@ -4,7 +4,7 @@
--changeset hs-office-relationship-MAIN-TABLE:1 endDelimiter:--// --changeset hs-office-relationship-MAIN-TABLE:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
CREATE TYPE HsOfficeRelationshipType AS ENUM ('UNKNOWN', 'REPRESENTATIVE', 'ACCOUNTING', 'OPERATIONS'); CREATE TYPE HsOfficeRelationshipType AS ENUM ('UNKNOWN', 'EX-PARTNER', 'REPRESENTATIVE', 'ACCOUNTING', 'OPERATIONS');
CREATE CAST (character varying as HsOfficeRelationshipType) WITH INOUT AS IMPLICIT; CREATE CAST (character varying as HsOfficeRelationshipType) WITH INOUT AS IMPLICIT;

View File

@ -22,11 +22,12 @@ import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEnti
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipType; import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipType;
import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity; import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity;
import net.hostsharing.test.JpaAttempt; import net.hostsharing.test.JpaAttempt;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestWatcher;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
@ -45,6 +46,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import static java.util.Arrays.stream; import static java.util.Arrays.stream;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@ -85,22 +87,24 @@ import static org.assertj.core.api.Fail.fail;
-- maybe something like that is needed for the 2nd user -- maybe something like that is needed for the 2nd user
-- GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to hsh99_restricted; -- GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to hsh99_restricted;
* Then copy this to a file named .environment (excluded from git): * Then copy this to a file named .environment (excluded from git) and fill in your specific values:
export HSADMINNG_POSTGRES_JDBC_URL=jdbc:postgresql://localhost:6432/hsh99_hsadminng export HSADMINNG_POSTGRES_JDBC_URL=jdbc:postgresql://localhost:6432/hsh99_hsadminng
export HSADMINNG_POSTGRES_ADMIN_USERNAME=hsh99_admin export HSADMINNG_POSTGRES_ADMIN_USERNAME=hsh99_admin
export HSADMINNG_POSTGRES_ADMIN_PASSWORD=password export HSADMINNG_POSTGRES_ADMIN_PASSWORD=password
export HSADMINNG_POSTGRES_RESTRICTED_USERNAME=hsh99_restricted export HSADMINNG_POSTGRES_RESTRICTED_USERNAME=hsh99_restricted
export HSADMINNG_SUPERUSER=some-precreated-superuser@example.org
* Then, import the office data, uncomment the @Diabled and then run: * To finally import the office data, run:
* *
* import-office-tables # comes from .aliases file * import-office-tables # comes from .aliases file and uses .environment
*/ */
@Tag("import") @Tag("import")
@DataJpaTest(properties = { @DataJpaTest(properties = {
"spring.datasource.url=${HSADMINNG_POSTGRES_JDBC_URL:jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers}", "spring.datasource.url=${HSADMINNG_POSTGRES_JDBC_URL:jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers}",
"spring.datasource.username=${HSADMINNG_POSTGRES_ADMIN_USERNAME:admin}", "spring.datasource.username=${HSADMINNG_POSTGRES_ADMIN_USERNAME:admin}",
"spring.datasource.password=${HSADMINNG_POSTGRES_ADMIN_PASSWORD:password}" "spring.datasource.password=${HSADMINNG_POSTGRES_ADMIN_PASSWORD:password}",
"hsadminng.superuser=${HSADMINNG_SUPERUSER:superuser-alex@hostsharing.net}"
}) })
@Import({ Context.class, JpaAttempt.class }) @Import({ Context.class, JpaAttempt.class })
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -110,8 +114,8 @@ public class ImportOfficeTables extends ContextBasedTest {
@Value("${spring.datasource.username}") @Value("${spring.datasource.username}")
private String postgresAdminUser; private String postgresAdminUser;
// TODO: use real rbacSuperuser for actual import @Value("${hsadminng.superuser}")
private static final String rbacSuperuser = "superuser-alex@hostsharing.net"; private String rbacSuperuser;
private static NavigableMap<Integer, HsOfficeContactEntity> contacts = new TreeMap<>(); private static NavigableMap<Integer, HsOfficeContactEntity> contacts = new TreeMap<>();
private static NavigableMap<Integer, HsOfficePersonEntity> persons = new TreeMap<>(); private static NavigableMap<Integer, HsOfficePersonEntity> persons = new TreeMap<>();
@ -150,30 +154,28 @@ public class ImportOfficeTables extends ContextBasedTest {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if ( !"admin".equals(postgresAdminUser) ) { assumeThat(postgresAdminUser).isEqualTo("admin");
return;
}
// no contacts yet => mostly null values // no contacts yet => mostly null values
assertThat(partners.toString()).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(partners)).isEqualToIgnoringWhitespace("""
{ {
7=partner(UNKNOWN null, null), 17=partner(null null, null),
10=partner(UNKNOWN null, null), 20=partner(null null, null),
12=partner(UNKNOWN null, null) 22=partner(null null, null)
} }
"""); """);
assertThat(contacts.toString()).isEqualTo("{}"); assertThat(toFormattedString(contacts)).isEqualTo("{}");
assertThat(debitors.toString()).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace("""
{ {
7=debitor(1000700: UNKNOWN null, null: mih), 17=debitor(1001700: null null, null: mih),
10=debitor(1001000: UNKNOWN null, null: xyz), 20=debitor(1002000: null null, null: xyz),
12=debitor(1101200: UNKNOWN null, null: xxx)} 22=debitor(1102200: null null, null: xxx)}
"""); """);
assertThat(memberships.toString()).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
{ {
7=Membership(10007, UNKNOWN null, null, 1000700, [2000-12-06,), NONE), 17=Membership(10017, null null, null, 1001700, [2000-12-06,), NONE),
10=Membership(10010, UNKNOWN null, null, 1001000, [2000-12-06,2016-01-01), UNKNOWN), 20=Membership(10020, null null, null, 1002000, [2000-12-06,2016-01-01), UNKNOWN),
12=Membership(11012, UNKNOWN null, null, 1101200, [2021-04-01,), NONE) 22=Membership(11022, null null, null, 1102200, [2021-04-01,), NONE)
} }
"""); """);
} }
@ -189,18 +191,16 @@ public class ImportOfficeTables extends ContextBasedTest {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if ( !"admin".equals(postgresAdminUser) ) { assumeThat(postgresAdminUser).isEqualTo("admin");
return;
}
assertThat(partners.toString()).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(partners)).isEqualToIgnoringWhitespace("""
{ {
7=partner(NATURAL Mellies, Michael: Herr Michael Mellies ), 17=partner(NATURAL Mellies, Michael: Herr Michael Mellies ),
10=partner(LEGAL JM e.K.: Herr Philip Meyer-Contract , JM e.K.), 20=partner(LEGAL JM e.K.: Herr Philip Meyer-Contract , JM e.K.),
12=partner(LEGAL Test PS: Petra Schmidt , Test PS) 22=partner(LEGAL Test PS: Petra Schmidt , Test PS)
} }
"""); """);
assertThat(contacts.toString()).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(contacts)).isEqualToIgnoringWhitespace("""
{ {
1101=contact(label='Herr Michael Mellies ', emailAddresses='mih@example.org'), 1101=contact(label='Herr Michael Mellies ', emailAddresses='mih@example.org'),
1201=contact(label='Frau Dr. Jenny Meyer-Billing , JM e.K.', emailAddresses='jm-billing@example.org'), 1201=contact(label='Frau Dr. Jenny Meyer-Billing , JM e.K.', emailAddresses='jm-billing@example.org'),
@ -209,28 +209,30 @@ public class ImportOfficeTables extends ContextBasedTest {
1301=contact(label='Petra Schmidt , Test PS', emailAddresses='ps@example.com') 1301=contact(label='Petra Schmidt , Test PS', emailAddresses='ps@example.com')
} }
"""); """);
assertThat(persons.toString()).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(persons)).isEqualToIgnoringWhitespace("""
{ {
900000=person(personType='NATURAL', tradeName='', familyName='Mellies', givenName='Michael'), 1101=person(personType='NATURAL', tradeName='', familyName='Mellies', givenName='Michael'),
900001=person(personType='LEGAL', tradeName='JM e.K.', familyName='Meyer-Contract', givenName='Philip'), 1201=person(personType='LEGAL', tradeName='JM e.K.', familyName='Meyer-Billing', givenName='Jenny'),
900002=person(personType='LEGAL', tradeName='Test PS', familyName='Schmidt', givenName='Petra') 1202=person(personType='LEGAL', tradeName='JM e.K.', familyName='Meyer-Operation', givenName='Andrew'),
1203=person(personType='LEGAL', tradeName='JM e.K.', familyName='Meyer-Contract', givenName='Philip'),
1301=person(personType='LEGAL', tradeName='Test PS', familyName='Schmidt', givenName='Petra')
} }
"""); """);
assertThat(debitors.toString()).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace("""
{ {
7=debitor(1000700: NATURAL Mellies, Michael: mih), 17=debitor(1001700: NATURAL Mellies, Michael: mih),
10=debitor(1001000: LEGAL JM e.K.: xyz), 20=debitor(1002000: LEGAL JM e.K.: xyz),
12=debitor(1101200: LEGAL Test PS: xxx) 22=debitor(1102200: LEGAL Test PS: xxx)
} }
"""); """);
assertThat(memberships.toString()).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
{ {
7=Membership(10007, NATURAL Mellies, Michael, 1000700, [2000-12-06,), NONE), 17=Membership(10017, NATURAL Mellies, Michael, 1001700, [2000-12-06,), NONE),
10=Membership(10010, LEGAL JM e.K., 1001000, [2000-12-06,2016-01-01), UNKNOWN), 20=Membership(10020, LEGAL JM e.K., 1002000, [2000-12-06,2016-01-01), UNKNOWN),
12=Membership(11012, LEGAL Test PS, 1101200, [2021-04-01,), NONE) 22=Membership(11022, LEGAL Test PS, 1102200, [2021-04-01,), NONE)
} }
"""); """);
assertThat(relationships.toString()).isEqualToIgnoringWhitespace(""" assertThat(toFormattedString(relationships)).isEqualToIgnoringWhitespace("""
{ {
1101=rel(relAnchor='NATURAL Mellies, Michael', relType='OPERATIONS', relHolder='NATURAL Mellies, Michael', contact='Herr Michael Mellies '), 1101=rel(relAnchor='NATURAL Mellies, Michael', relType='OPERATIONS', relHolder='NATURAL Mellies, Michael', contact='Herr Michael Mellies '),
1202=rel(relAnchor='LEGAL JM e.K.', relType='OPERATIONS', relHolder='LEGAL JM e.K.', contact='Herr Andrew Meyer-Operation , JM e.K.'), 1202=rel(relAnchor='LEGAL JM e.K.', relType='OPERATIONS', relHolder='LEGAL JM e.K.', contact='Herr Andrew Meyer-Operation , JM e.K.'),
@ -251,9 +253,7 @@ public class ImportOfficeTables extends ContextBasedTest {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if ( !"admin".equals(postgresAdminUser) ) { assumeThat(postgresAdminUser).isEqualTo("admin");
return;
}
assertThat(bankAccounts.toString()).isEqualToIgnoringWhitespace(""" assertThat(bankAccounts.toString()).isEqualToIgnoringWhitespace("""
{ {
@ -280,16 +280,14 @@ public class ImportOfficeTables extends ContextBasedTest {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if ( !"admin".equals(postgresAdminUser) ) { assumeThat(postgresAdminUser).isEqualTo("admin");
return;
}
assertThat(coopShares.toString()).isEqualToIgnoringWhitespace(""" assertThat(coopShares.toString()).isEqualToIgnoringWhitespace("""
{ {
33443=CoopShareTransaction(10007, 2000-12-06, SUBSCRIPTION, 20, initial share subscription), 33443=CoopShareTransaction(10017, 2000-12-06, SUBSCRIPTION, 20, initial share subscription),
33451=CoopShareTransaction(10010, 2000-12-06, SUBSCRIPTION, 2, initial share subscription), 33451=CoopShareTransaction(10020, 2000-12-06, SUBSCRIPTION, 2, initial share subscription),
33701=CoopShareTransaction(10007, 2005-01-10, SUBSCRIPTION, 40, increase), 33701=CoopShareTransaction(10017, 2005-01-10, SUBSCRIPTION, 40, increase),
33810=CoopShareTransaction(10010, 2016-12-31, CANCELLATION, 22, membership ended) 33810=CoopShareTransaction(10020, 2016-12-31, CANCELLATION, 22, membership ended)
} }
"""); """);
} }
@ -305,20 +303,18 @@ public class ImportOfficeTables extends ContextBasedTest {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if ( !"admin".equals(postgresAdminUser) ) { assumeThat(postgresAdminUser).isEqualTo("admin");
return;
}
assertThat(coopAssets.toString()).isEqualToIgnoringWhitespace(""" assertThat(coopAssets.toString()).isEqualToIgnoringWhitespace("""
{ {
30000=CoopAssetsTransaction(10007, 2000-12-06, DEPOSIT, 1280.00, for subscription A), 30000=CoopAssetsTransaction(10017, 2000-12-06, DEPOSIT, 1280.00, for subscription A),
31000=CoopAssetsTransaction(10010, 2000-12-06, DEPOSIT, 128.00, for subscription B), 31000=CoopAssetsTransaction(10020, 2000-12-06, DEPOSIT, 128.00, for subscription B),
32000=CoopAssetsTransaction(10007, 2005-01-10, DEPOSIT, 2560.00, for subscription C), 32000=CoopAssetsTransaction(10017, 2005-01-10, DEPOSIT, 2560.00, for subscription C),
33001=CoopAssetsTransaction(10007, 2005-01-10, TRANSFER, -512.00, for transfer to 10), 33001=CoopAssetsTransaction(10017, 2005-01-10, TRANSFER, -512.00, for transfer to 10),
33002=CoopAssetsTransaction(10010, 2005-01-10, ADOPTION, 512.00, for transfer from 7), 33002=CoopAssetsTransaction(10020, 2005-01-10, ADOPTION, 512.00, for transfer from 7),
34001=CoopAssetsTransaction(10010, 2016-12-31, CLEARING, -8.00, for cancellation D), 34001=CoopAssetsTransaction(10020, 2016-12-31, CLEARING, -8.00, for cancellation D),
34002=CoopAssetsTransaction(10010, 2016-12-31, DISBURSAL, -100.00, for cancellation D), 34002=CoopAssetsTransaction(10020, 2016-12-31, DISBURSAL, -100.00, for cancellation D),
34003=CoopAssetsTransaction(10010, 2016-12-31, LOSS, -20.00, for cancellation D) 34003=CoopAssetsTransaction(10020, 2016-12-31, LOSS, -20.00, for cancellation D)
} }
"""); """);
} }
@ -411,60 +407,66 @@ public class ImportOfficeTables extends ContextBasedTest {
private void deleteTestDataFromHsOfficeTables() { private void deleteTestDataFromHsOfficeTables() {
jpaAttempt.transacted(() -> { jpaAttempt.transacted(() -> {
context(rbacSuperuser); context(rbacSuperuser);
em.createNativeQuery("DELETE FROM hs_office_relationship WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_relationship where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_coopassetstransaction WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_coopassetstransaction where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_coopassetstransaction_legacy_id WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_coopassetstransaction_legacy_id where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_coopsharestransaction WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_coopsharestransaction where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_coopsharestransaction_legacy_id WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_coopsharestransaction_legacy_id where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_membership WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_membership where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_sepamandate WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_sepamandate where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_sepamandate_legacy_id WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_sepamandate_legacy_id where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_debitor WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_debitor where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_bankaccount WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_bankaccount where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_partner WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_partner where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_partner_details WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_partner_details where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_contact WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_contact where true").executeUpdate();
em.createNativeQuery("DELETE FROM hs_office_person WHERE true").executeUpdate(); em.createNativeQuery("delete from hs_office_person where true").executeUpdate();
}).assertSuccessful(); }).assertSuccessful();
} }
private void resetFromHsOfficeSequences() { private void resetFromHsOfficeSequences() {
jpaAttempt.transacted(() -> { jpaAttempt.transacted(() -> {
context(rbacSuperuser); context(rbacSuperuser);
em.createNativeQuery("ALTER SEQUENCE hs_office_contact_legacy_id_seq RESTART WITH 1000000000;").executeUpdate(); em.createNativeQuery("alter sequence hs_office_contact_legacy_id_seq restart with 1000000000;").executeUpdate();
em.createNativeQuery("ALTER SEQUENCE hs_office_coopassetstransaction_legacy_id_seq RESTART WITH 1000000000;").executeUpdate(); em.createNativeQuery("alter sequence hs_office_coopassetstransaction_legacy_id_seq restart with 1000000000;")
em.createNativeQuery("ALTER SEQUENCE public.hs_office_coopsharestransaction_legacy_id_seq RESTART WITH 1000000000;").executeUpdate(); .executeUpdate();
em.createNativeQuery("ALTER SEQUENCE public.hs_office_partner_legacy_id_seq RESTART WITH 1000000000;").executeUpdate(); em.createNativeQuery("alter sequence public.hs_office_coopsharestransaction_legacy_id_seq restart with 1000000000;")
em.createNativeQuery("ALTER SEQUENCE public.hs_office_sepamandate_legacy_id_seq RESTART WITH 1000000000;").executeUpdate(); .executeUpdate();
em.createNativeQuery("alter sequence public.hs_office_partner_legacy_id_seq restart with 1000000000;")
.executeUpdate();
em.createNativeQuery("alter sequence public.hs_office_sepamandate_legacy_id_seq restart with 1000000000;")
.executeUpdate();
}); });
} }
private void deleteFromTestTables() { private void deleteFromTestTables() {
jpaAttempt.transacted(() -> { jpaAttempt.transacted(() -> {
context(rbacSuperuser); context(rbacSuperuser);
em.createNativeQuery("DELETE FROM test_domain WHERE true").executeUpdate(); em.createNativeQuery("delete from test_domain where true").executeUpdate();
em.createNativeQuery("DELETE FROM test_package WHERE true").executeUpdate(); em.createNativeQuery("delete from test_package where true").executeUpdate();
em.createNativeQuery("DELETE FROM test_customer WHERE true").executeUpdate(); em.createNativeQuery("delete from test_customer where true").executeUpdate();
}).assertSuccessful(); }).assertSuccessful();
} }
private void deleteFromRbacTables() { private void deleteFromRbacTables() {
jpaAttempt.transacted(() -> { jpaAttempt.transacted(() -> {
context(rbacSuperuser); context(rbacSuperuser);
final var usersNotToDelete = em.createNativeQuery("SELECT name FROM rbacuser WHERE name like 'superuser-%'").getResultList(); final var usersNotToDelete = em.createNativeQuery("select name from rbacuser where name like 'superuser-%'")
final var usersToDelete = em.createNativeQuery("SELECT name FROM rbacuser WHERE name not like 'superuser-%'").getResultList(); .getResultList();
final var usersToDelete = em.createNativeQuery("select name from rbacuser where name not like 'superuser-%'")
.getResultList();
System.getenv(); System.getenv();
}); });
jpaAttempt.transacted(() -> { jpaAttempt.transacted(() -> {
context(rbacSuperuser); context(rbacSuperuser);
// em.createNativeQuery("DELETE FROM rbacobject WHERE objecttable like 'hs_%'").executeUpdate(); // em.createNativeQuery("DELETE FROM rbacobject WHERE objecttable like 'hs_%'").executeUpdate();
// em.createNativeQuery("DELETE FROM rbacgrants WHERE true").executeUpdate(); // em.createNativeQuery("DELETE FROM rbacgrants WHERE true").executeUpdate();
// em.createNativeQuery("DELETE FROM rbacpermission WHERE true").executeUpdate(); // em.createNativeQuery("DELETE FROM rbacpermission WHERE true").executeUpdate();
// em.createNativeQuery("DELETE FROM rbacreference WHERE true").executeUpdate(); // em.createNativeQuery("DELETE FROM rbacreference WHERE true").executeUpdate();
em.createNativeQuery("DELETE FROM rbacuser_rv WHERE name not like 'superuser-%'").executeUpdate(); em.createNativeQuery("delete from rbacuser_rv where name not like 'superuser-%'").executeUpdate();
em.createNativeQuery("DELETE FROM tx_journal WHERE true").executeUpdate(); em.createNativeQuery("delete from tx_journal where true").executeUpdate();
em.createNativeQuery("DELETE FROM tx_context WHERE true").executeUpdate(); em.createNativeQuery("delete from tx_context where true").executeUpdate();
}).assertSuccessful(); }).assertSuccessful();
} }
@ -499,6 +501,7 @@ public class ImportOfficeTables extends ContextBasedTest {
return csvReader.readAll(); return csvReader.readAll();
} }
} }
public static Reader skippingEmptyAndCommentLines(Reader reader) throws IOException { public static Reader skippingEmptyAndCommentLines(Reader reader) throws IOException {
try (var bufferedReader = new BufferedReader(reader); try (var bufferedReader = new BufferedReader(reader);
StringWriter writer = new StringWriter()) { StringWriter writer = new StringWriter()) {
@ -523,10 +526,7 @@ public class ImportOfficeTables extends ContextBasedTest {
.map(this::trimAll) .map(this::trimAll)
.map(row -> new Record(columns, row)) .map(row -> new Record(columns, row))
.forEach(rec -> { .forEach(rec -> {
final var person = HsOfficePersonEntity.builder() final var person = HsOfficePersonEntity.builder().build();
.personType(HsOfficePersonType.UNKNOWN) // TODO
.build();
persons.put(personId++, person);
final var partner = HsOfficePartnerEntity.builder() final var partner = HsOfficePartnerEntity.builder()
.debitorNumberPrefix(rec.getInteger("member_id")) .debitorNumberPrefix(rec.getInteger("member_id"))
@ -687,82 +687,132 @@ public class ImportOfficeTables extends ContextBasedTest {
final var partner = partners.get(rec.getInteger("bp_id")); final var partner = partners.get(rec.getInteger("bp_id"));
final var debitor = debitors.get(rec.getInteger("bp_id")); final var debitor = debitors.get(rec.getInteger("bp_id"));
final var person = partner.getPerson(); final var partnerPerson = partner.getPerson();
person.setTradeName(rec.getString("firma")); if (rec.getString("roles").contains("partner")) {
determinePersonType(person); initPerson(partner.getPerson(), rec);
// TODO: title+salutation: add to person }
person.setGivenName(rec.getString("first_name"));
person.setFamilyName(rec.getString("last_name")); HsOfficePersonEntity contactPerson = partnerPerson;
if (!StringUtils.equals(rec.getString("firma"), partnerPerson.getTradeName()) ||
!StringUtils.equals(rec.getString("first_name"), partnerPerson.getGivenName()) ||
!StringUtils.equals(rec.getString("last_name"), partnerPerson.getFamilyName())) {
contactPerson = initPerson(HsOfficePersonEntity.builder().build(), rec);
}
final var contact = HsOfficeContactEntity.builder().build(); final var contact = HsOfficeContactEntity.builder().build();
contacts.put(contactId, initContact(contact, rec)); initContact(contact, rec);
var imported = false;
if (rec.getString("roles").contains("partner")) { if (rec.getString("roles").contains("partner")) {
assertThat(partner.getContact()).isNull(); assertThat(partner.getContact()).isNull();
partner.setContact(contact); partner.setContact(contact);
imported = true;
} }
if (rec.getString("roles").contains("billing")) { if (rec.getString("roles").contains("billing")) {
assertThat(debitor.getBillingContact()).isNull(); assertThat(debitor.getBillingContact()).isNull();
debitor.setBillingContact(contact); debitor.setBillingContact(contact);
imported = true;
} }
if (rec.getString("roles").contains("operation")) { if (rec.getString("roles").contains("operation")) {
final var rel = HsOfficeRelationshipEntity.builder() final var rel = HsOfficeRelationshipEntity.builder()
.relAnchor(partner.getPerson()) .relAnchor(partnerPerson)
.relHolder(person) .relHolder(contactPerson)
.contact(contact) .contact(contact)
.relType(HsOfficeRelationshipType.OPERATIONS) .relType(HsOfficeRelationshipType.OPERATIONS)
.build(); .build();
relationships.put(contactId, rel); relationships.put(contactId, rel);
imported = true;
} }
if (rec.getString("roles").contains("contractual")) { if (rec.getString("roles").contains("contractual")) {
final var rel = HsOfficeRelationshipEntity.builder() final var rel = HsOfficeRelationshipEntity.builder()
.relAnchor(partner.getPerson()) .relAnchor(partnerPerson)
.relHolder(person) .relHolder(contactPerson)
.contact(contact) .contact(contact)
.relType(HsOfficeRelationshipType.REPRESENTATIVE) .relType(HsOfficeRelationshipType.REPRESENTATIVE)
.build(); .build();
relationships.put(contactId, rel); relationships.put(contactId, rel);
imported = true;
} }
if (!imported) { if (rec.getString("roles").contains("ex-partner")) {
final var rel = HsOfficeRelationshipEntity.builder() final var rel = HsOfficeRelationshipEntity.builder()
.relAnchor(partner.getPerson()) .relAnchor(partnerPerson)
.relHolder(person) .relHolder(contactPerson)
.contact(contact) .contact(contact)
.relType(HsOfficeRelationshipType.UNKNOWN) .relType(HsOfficeRelationshipType.EX_PARTNER)
.build(); .build();
relationships.put(contactId, rel); relationships.put(contactId, rel);
} }
verifyContainsOnly(rec.getString("roles"), "partner", "ex-partner", "billing", "contractual", "operation");
}); });
} }
private void determinePersonType(final HsOfficePersonEntity person) { private HsOfficePersonEntity initPerson(final HsOfficePersonEntity person, final Record contactRecord) {
// TODO: title+salutation: add to person
person.setGivenName(contactRecord.getString("first_name"));
person.setFamilyName(contactRecord.getString("last_name"));
person.setTradeName(contactRecord.getString("firma"));
determinePersonType(person, contactRecord.getString("roles"));
persons.put(contactRecord.getInteger("contact_id"), person);
return person;
}
private static void determinePersonType(final HsOfficePersonEntity person, final String roles) {
if (person.getTradeName().isBlank()) { if (person.getTradeName().isBlank()) {
person.setPersonType(HsOfficePersonType.NATURAL); person.setPersonType(HsOfficePersonType.NATURAL);
} else if (roles.contains("partner")) {
person.setPersonType(HsOfficePersonType.LEGAL);
} else if (roles.contains("contractual") &&
!person.getFamilyName().isBlank() && !person.getGivenName().isBlank()) {
person.setPersonType(HsOfficePersonType.NATURAL);
} else if ( endsWithWord(person.getTradeName(), "e.K.", "e.G.", "eG", "GmbH", "AG") ) {
person.setPersonType(HsOfficePersonType.LEGAL);
} else { } else {
person.setPersonType(HsOfficePersonType.LEGAL); // TODO: add rules if we distinguish // TODO: detect the other person types as soon as we've switche to the new person types
person.setPersonType(HsOfficePersonType.UNKNOWN);
} }
} }
private HsOfficeContactEntity initContact(final HsOfficeContactEntity contact, final Record rec) { private static boolean endsWithWord(final String value, final String... endings) {
contacts.put(rec.getInteger("contact_id"), contact); final var lowerCaseValue = value.toLowerCase();
for( String ending: endings ) {
if (lowerCaseValue.endsWith(" " + ending.toLowerCase())) {
return true;
}
}
return false;
}
private void verifyContainsOnly(final String roles, final String... allowedRoles) {
final var givenRolesSet = stream(roles.replace(" ", "").split(",")).collect(Collectors.toSet());
final var allowedRolesSet = stream(allowedRoles).collect(Collectors.toSet());
final var unexpectedRolesSet = new HashSet<>(givenRolesSet);
unexpectedRolesSet.removeAll(allowedRolesSet);
assertThat(unexpectedRolesSet).isEmpty();
}
private HsOfficeContactEntity initContact(final HsOfficeContactEntity contact, final Record contactRecord) {
contact.setLabel(toLabel( contact.setLabel(toLabel(
rec.getString("salut"), contactRecord.getString("salut"),
rec.getString("title"), contactRecord.getString("title"),
rec.getString("first_name"), contactRecord.getString("first_name"),
rec.getString("last_name"), contactRecord.getString("last_name"),
rec.getString("firma"))); contactRecord.getString("firma")));
contact.setEmailAddresses(rec.getString("email")); contact.setEmailAddresses(contactRecord.getString("email"));
contact.setPostalAddress(toAddress(rec)); contact.setPostalAddress(toAddress(contactRecord));
contact.setPhoneNumbers(toPhoneNumbers(rec)); contact.setPhoneNumbers(toPhoneNumbers(contactRecord));
contacts.put(contactRecord.getInteger("contact_id"), contact);
return contact; return contact;
} }
private <E> String toFormattedString(final Map<Integer, E> map) {
if ( map.isEmpty() ) {
return "{}";
}
return "{\n" +
map.keySet().stream()
.map(id -> " " + id + "=" + map.get(id).toString())
.collect(Collectors.joining(",\n")) +
"\n}\n";
}
private String[] trimAll(final String[] record) { private String[] trimAll(final String[] record) {
for (int i = 0; i < record.length; ++i) { for (int i = 0; i < record.length; ++i) {
if (record[i] != null) { if (record[i] != null) {
@ -932,6 +982,7 @@ class Record {
} }
class OrderedDependedTestsExtension implements TestWatcher, BeforeEachCallback { class OrderedDependedTestsExtension implements TestWatcher, BeforeEachCallback {
private static boolean previousTestsPassed = true; private static boolean previousTestsPassed = true;
public void testAborted(ExtensionContext context, Throwable cause) { public void testAborted(ExtensionContext context, Throwable cause) {

View File

@ -1,9 +1,9 @@
member_asset_id; bp_id; date; action; amount; comment member_asset_id; bp_id; date; action; amount; comment
30000; 7; 2000-12-06; PAYMENT; 1280.00; for subscription A 30000; 17; 2000-12-06; PAYMENT; 1280.00; for subscription A
31000; 10; 2000-12-06; PAYMENT; 128.00; for subscription B 31000; 20; 2000-12-06; PAYMENT; 128.00; for subscription B
32000; 7; 2005-01-10; PAYMENT; 2560.00; for subscription C 32000; 17; 2005-01-10; PAYMENT; 2560.00; for subscription C
33001; 7; 2005-01-10; HANDOVER; -512.00; for transfer to 10 33001; 17; 2005-01-10; HANDOVER; -512.00; for transfer to 10
33002; 10; 2005-01-10; ADOPTION; 512.00; for transfer from 7 33002; 20; 2005-01-10; ADOPTION; 512.00; for transfer from 7
34001; 10; 2016-12-31; CLEARING; -8.00; for cancellation D 34001; 20; 2016-12-31; CLEARING; -8.00; for cancellation D
34002; 10; 2016-12-31; PAYBACK; -100.00; for cancellation D 34002; 20; 2016-12-31; PAYBACK; -100.00; for cancellation D
34003; 10; 2016-12-31; LOSS; -20.00; for cancellation D 34003; 20; 2016-12-31; LOSS; -20.00; for cancellation D

1 member_asset_id bp_id date action amount comment
2 30000 7 17 2000-12-06 PAYMENT 1280.00 for subscription A
3 31000 10 20 2000-12-06 PAYMENT 128.00 for subscription B
4 32000 7 17 2005-01-10 PAYMENT 2560.00 for subscription C
5 33001 7 17 2005-01-10 HANDOVER -512.00 for transfer to 10
6 33002 10 20 2005-01-10 ADOPTION 512.00 for transfer from 7
7 34001 10 20 2016-12-31 CLEARING -8.00 for cancellation D
8 34002 10 20 2016-12-31 PAYBACK -100.00 for cancellation D
9 34003 10 20 2016-12-31 LOSS -20.00 for cancellation D

View File

@ -1,4 +1,4 @@
bp_id;member_id;member_code;member_since;member_until;member_role;author_contract;nondisc_contract;free;exempt_vat;indicator_vat;uid_vat bp_id;member_id;member_code;member_since;member_until;member_role;author_contract;nondisc_contract;free;exempt_vat;indicator_vat;uid_vat
7;10007;hsh00-mih;2000-12-06;;Aufsichtsrat;2006-10-15;2001-10-15;false;false;NET;DE-VAT-007 17;10017;hsh00-mih;2000-12-06;;Aufsichtsrat;2006-10-15;2001-10-15;false;false;NET;DE-VAT-007
10;10010;hsh00-xyz;2000-12-06;2015-12-31;;;;false;false;GROSS; 20;10020;hsh00-xyz;2000-12-06;2015-12-31;;;;false;false;GROSS;
12;11012;hsh00-xxx;2021-04-01;;;;;true;true;GROSS; 22;11022;hsh00-xxx;2021-04-01;;;;;true;true;GROSS;

1 bp_id member_id member_code member_since member_until member_role author_contract nondisc_contract free exempt_vat indicator_vat uid_vat
2 7 17 10007 10017 hsh00-mih 2000-12-06 Aufsichtsrat 2006-10-15 2001-10-15 false false NET DE-VAT-007
3 10 20 10010 10020 hsh00-xyz 2000-12-06 2015-12-31 false false GROSS
4 12 22 11012 11022 hsh00-xxx 2021-04-01 true true GROSS

View File

@ -1,12 +1,12 @@
contact_id; bp_id; salut; first_name; last_name; title; firma; co; street; zipcode;city; country; phone_private; phone_office; phone_mobile; fax; email; roles contact_id; bp_id; salut; first_name; last_name; title; firma; co; street; zipcode;city; country; phone_private; phone_office; phone_mobile; fax; email; roles
# eine natürliche Person # eine natürliche Person
1101; 7; Herr; Michael; Mellies; ; ; ; Kleine Freiheit 50; 26524; Hage; DE; ; +49 4931 123456; +49 1522 123456;; mih@example.org; partner,billing,operation 1101; 17; Herr; Michael; Mellies; ; ; ; Kleine Freiheit 50; 26524; Hage; DE; ; +49 4931 123456; +49 1522 123456;; mih@example.org; partner,billing,operation
# eine juristische Person mit drei separaten Ansprechpartnern # eine juristische Person mit drei separaten Ansprechpartnern
1201; 10; Frau; Jenny; Meyer-Billing; Dr.; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 7777777; +49 30 1111111; ; +49 30 2222222; jm-billing@example.org; billing 1201; 20; Frau; Jenny; Meyer-Billing; Dr.; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 7777777; +49 30 1111111; ; +49 30 2222222; jm-billing@example.org; billing
1202; 10; Herr; Andrew; Meyer-Operation; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 3333333; ; +49 30 4444444; am-operation@example.org; operation 1202; 20; Herr; Andrew; Meyer-Operation; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 3333333; ; +49 30 4444444; am-operation@example.org; operation
1203; 10; Herr; Philip; Meyer-Contract; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; pm-partner@example.org; partner,contractual 1203; 20; Herr; Philip; Meyer-Contract; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; pm-partner@example.org; partner,contractual
# eine juristische Person mit nur einem Ansprechpartner # eine juristische Person mit nur einem Ansprechpartner
1301; 12; ; Petra; Schmidt; ; Test PS;; ; ; ; ; ; ; ; ; ps@example.com; partner,billing,contractual,operation 1301; 22; ; Petra; Schmidt; ; Test PS;; ; ; ; ; ; ; ; ; ps@example.com; partner,billing,contractual,operation

1 contact_id; bp_id; salut; first_name; last_name; title; firma; co; street; zipcode;city; country; phone_private; phone_office; phone_mobile; fax; email; roles
2 # eine natürliche Person
3 1101; 7; Herr; Michael; Mellies; ; ; ; Kleine Freiheit 50; 26524; Hage; DE; ; +49 4931 123456; +49 1522 123456;; mih@example.org; partner,billing,operation 1101; 17; Herr; Michael; Mellies; ; ; ; Kleine Freiheit 50; 26524; Hage; DE; ; +49 4931 123456; +49 1522 123456;; mih@example.org; partner,billing,operation
4 # eine juristische Person mit drei separaten Ansprechpartnern
5 1201; 10; Frau; Jenny; Meyer-Billing; Dr.; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 7777777; +49 30 1111111; ; +49 30 2222222; jm-billing@example.org; billing 1201; 20; Frau; Jenny; Meyer-Billing; Dr.; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 7777777; +49 30 1111111; ; +49 30 2222222; jm-billing@example.org; billing
6 1202; 10; Herr; Andrew; Meyer-Operation; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 3333333; ; +49 30 4444444; am-operation@example.org; operation 1202; 20; Herr; Andrew; Meyer-Operation; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 3333333; ; +49 30 4444444; am-operation@example.org; operation
7 1203; 10; Herr; Philip; Meyer-Contract; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; pm-partner@example.org; partner,contractual 1203; 20; Herr; Philip; Meyer-Contract; ; JM e.K.;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; pm-partner@example.org; partner,contractual
8 # eine juristische Person mit nur einem Ansprechpartner
9 1301; 12; ; Petra; Schmidt; ; Test PS;; ; ; ; ; ; ; ; ; ps@example.com; partner,billing,contractual,operation 1301; 22; ; Petra; Schmidt; ; Test PS;; ; ; ; ; ; ; ; ; ps@example.com; partner,billing,contractual,operation
10
11
12

View File

@ -1,3 +1,3 @@
sepa_mandat_id; bp_id; bank_customer; bank_name; bank_iban; bank_bic; mandat_ref; mandat_signed; mandat_since; mandat_until; mandat_used sepa_mandat_id; bp_id; bank_customer; bank_name; bank_iban; bank_bic; mandat_ref; mandat_signed; mandat_since; mandat_until; mandat_used
234234; 7; Michael Mellies; ING Bank AG; DE37500105177419788228; INGDDEFFXXX; MH12345; 2004-06-12; 2004-06-15; ; 2022-10-20 234234; 17; Michael Mellies; ING Bank AG; DE37500105177419788228; INGDDEFFXXX; MH12345; 2004-06-12; 2004-06-15; ; 2022-10-20
235662; 10; JM e.K.; ING Bank AG; DE49500105174516484892; INGDDEFFXXX; JM33344; 2005-06-28; 2005-07-01; ; 2016-01-18 235662; 20; JM e.K.; ING Bank AG; DE49500105174516484892; INGDDEFFXXX; JM33344; 2005-06-28; 2005-07-01; ; 2016-01-18

1 sepa_mandat_id bp_id bank_customer bank_name bank_iban bank_bic mandat_ref mandat_signed mandat_since mandat_until mandat_used
2 234234 7 17 Michael Mellies ING Bank AG DE37500105177419788228 INGDDEFFXXX MH12345 2004-06-12 2004-06-15 2022-10-20
3 235662 10 20 JM e.K. ING Bank AG DE49500105174516484892 INGDDEFFXXX JM33344 2005-06-28 2005-07-01 2016-01-18

View File

@ -1,5 +1,5 @@
member_share_id;bp_id; date; action; quantity; comment member_share_id;bp_id; date; action; quantity; comment
33443; 7; 2000-12-06; SUBSCRIPTION; 20; initial share subscription 33443; 17; 2000-12-06; SUBSCRIPTION; 20; initial share subscription
33451; 10; 2000-12-06; SUBSCRIPTION; 2; initial share subscription 33451; 20; 2000-12-06; SUBSCRIPTION; 2; initial share subscription
33701; 7; 2005-01-10; SUBSCRIPTION; 40; increase 33701; 17; 2005-01-10; SUBSCRIPTION; 40; increase
33810; 10; 2016-12-31; UNSUBSCRIPTION; 22; membership ended 33810; 20; 2016-12-31; UNSUBSCRIPTION; 22; membership ended

1 member_share_id bp_id date action quantity comment
2 33443 7 17 2000-12-06 SUBSCRIPTION 20 initial share subscription
3 33451 10 20 2000-12-06 SUBSCRIPTION 2 initial share subscription
4 33701 7 17 2005-01-10 SUBSCRIPTION 40 increase
5 33810 10 20 2016-12-31 UNSUBSCRIPTION 22 membership ended