From 4f7bd04f1195d5cd9afdb2ea2dcfec0c9ec3eaf6 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Tue, 4 Feb 2025 09:45:52 +0100 Subject: [PATCH] remove OfficeDataImport --- .aliases | 11 +- .run/ImportOfficeData.run.xml | 103 -- Jenkinsfile | 4 +- build.gradle | 17 +- .../hs/migration/BaseOfficeDataImport.java | 1313 ----------------- .../hs/migration/ImportOfficeData.java | 74 - 6 files changed, 10 insertions(+), 1512 deletions(-) delete mode 100644 .run/ImportOfficeData.run.xml delete mode 100644 src/test/java/net/hostsharing/hsadminng/hs/migration/BaseOfficeDataImport.java delete mode 100644 src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java diff --git a/.aliases b/.aliases index d135bfa6..a6b52477 100644 --- a/.aliases +++ b/.aliases @@ -1,4 +1,4 @@ -# For using the alias gw-importOfficeData or gw-importHostingAssets, +# For using the alias gw-importHostingAssets, # copy the file .tc-environment to .environment (ignored by git) # and amend them according to your external DB. @@ -71,7 +71,6 @@ function importLegacyData() { ./gradlew $target --rerun fi } -alias gw-importOfficeData='importLegacyData importOfficeData' alias gw-importHostingAssets='importLegacyData importHostingAssets' alias podman-start='systemctl --user enable --now podman.socket && systemctl --user status podman.socket && ls -la /run/user/$UID/podman/podman.sock' @@ -92,8 +91,8 @@ alias fp='grep -r '@Accepts' src | sed -e 's/^.*@/@/g' | sort -u | wc -l' alias gw-spotless='./gradlew spotlessApply -x pitest -x test -x :processResources' alias gw-check='. .aliases; . .tc-environment; gw test check -x pitest' -# HOWTO: run all 'normal' tests (no scenario+import-tests): `gw-test` -# You can also mention specific targets: `gw-test importOfficeData`. +# HOWTO: run all 'normal' tests (by default without scenario+import-tests): `gw-test` +# You can also mention specific targets: `gw-test importHostingAssets`, in that case only these tests are executed. # This will always use the environment from `.tc-environment`. # # HOWTO: re-run tests even if no changed can be detected: `gw-test --rerun` @@ -123,7 +122,7 @@ function _gwTest() { time (_gwTest1 unitTest "$@" && _gwTest1 officeIntegrationTest bookingIntegrationTest hostingIntegrationTest "$@" && _gwTest1 scenarioTest "$@" && - _gwTest1 importOfficeData importHostingAssets "$@"); + _gwTest1 importHostingAssets "$@"); elif [ $# -eq 0 ] || [[ $1 == -* ]]; then time _gwTest1 test "$@"; else @@ -137,7 +136,7 @@ alias howto=bin/howto alias cas-curl=bin/cas-curl # etc/docker-compose.yml limits CPUs+MEM and includes a PostgreSQL config for analysing slow queries -alias gw-importOfficeData-in-docker-compose=' +alias gw-importHostingAssets-in-docker-compose=' docker-compose -f etc/docker-compose.yml down && docker-compose -f etc/docker-compose.yml up -d && sleep 10 && time gw-importHostingAssets' diff --git a/.run/ImportOfficeData.run.xml b/.run/ImportOfficeData.run.xml deleted file mode 100644 index ee6f13c0..00000000 --- a/.run/ImportOfficeData.run.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - false - true - - - - false - true - - - - - - - - - false - true - - - - false - true - - - - - - - - - false - true - - - - false - true - - - diff --git a/Jenkinsfile b/Jenkinsfile index 5e41139b..19bdd93c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -55,9 +55,9 @@ pipeline { sh './gradlew bookingIntegrationTest hostingIntegrationTest --no-daemon' } } - stage('Import-Tests') { + stage('Test-Imports') { steps { - sh './gradlew importOfficeData importHostingAssets --no-daemon' + sh './gradlew importHostingAssets --no-daemon' } } stage ('Scenario-Tests') { diff --git a/build.gradle b/build.gradle index 3f400c41..f3a12160 100644 --- a/build.gradle +++ b/build.gradle @@ -263,7 +263,7 @@ test { 'net.hostsharing.hsadminng.**.generated.**', ] useJUnitPlatform { - excludeTags 'importOfficeData', 'importHostingAssets', 'scenarioTest' + excludeTags 'importHostingAssets', 'scenarioTest' } } @@ -338,7 +338,7 @@ jacocoTestCoverageVerification { // HOWTO: run all unit-tests which don't need a database: gw-test unitTest tasks.register('unitTest', Test) { useJUnitPlatform { - excludeTags 'importOfficeData', 'importHostingAssets', 'scenarioTest', 'generalIntegrationTest', + excludeTags 'importHostingAssets', 'scenarioTest', 'generalIntegrationTest', 'officeIntegrationTest', 'bookingIntegrationTest', 'hostingIntegrationTest' } @@ -396,17 +396,6 @@ tasks.register('hostingIntegrationTest', Test) { mustRunAfter spotlessJava } -tasks.register('importOfficeData', Test) { - useJUnitPlatform { - includeTags 'importOfficeData' - } - - group 'verification' - description 'run the import jobs as tests' - - mustRunAfter spotlessJava -} - tasks.register('importHostingAssets', Test) { useJUnitPlatform { includeTags 'importHostingAssets' @@ -439,7 +428,7 @@ pitest { ] targetTests = ['net.hostsharing.hsadminng.**.*UnitTest', 'net.hostsharing.hsadminng.**.*RestTest'] - excludedTestClasses = ['**AcceptanceTest*', '**IntegrationTest*', '**ImportOfficeData', '**ImportHostingAssets'] + excludedTestClasses = ['**AcceptanceTest*', '**IntegrationTest*', '**ImportHostingAssets'] pitestVersion = '1.17.0' junit5PluginVersion = '1.1.0' diff --git a/src/test/java/net/hostsharing/hsadminng/hs/migration/BaseOfficeDataImport.java b/src/test/java/net/hostsharing/hsadminng/hs/migration/BaseOfficeDataImport.java deleted file mode 100644 index b8266f0e..00000000 --- a/src/test/java/net/hostsharing/hsadminng/hs/migration/BaseOfficeDataImport.java +++ /dev/null @@ -1,1313 +0,0 @@ -package net.hostsharing.hsadminng.hs.migration; - -import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity; -import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; -import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionEntity; -import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionType; -import net.hostsharing.hsadminng.hs.office.coopshares.HsOfficeCoopSharesTransactionEntity; -import net.hostsharing.hsadminng.hs.office.coopshares.HsOfficeCoopSharesTransactionType; -import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity; -import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity; -import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipStatus; -import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerDetailsEntity; -import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealEntity; -import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity; -import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType; -import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelation; -import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity; -import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType; -import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; - -import java.io.Reader; -import java.time.LocalDate; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static java.util.Arrays.stream; -import static java.util.Optional.ofNullable; -import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange; -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNotBlank; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; -import static org.assertj.core.api.Fail.fail; - -/// Actual import of office data tables without config, for use as superclas of ImportOfficeData and ImportHostingAssets. -public abstract class BaseOfficeDataImport extends CsvDataImport { - - private static final String[] SUBSCRIBER_ROLES = new String[] { - "subscriber:operations-discussion", - "subscriber:operations-announce", - "subscriber:generalversammlung", - "subscriber:members-announce", - "subscriber:members-discussion", - "subscriber:customers-announce" - }; - private static final String[] KNOWN_ROLES = ArrayUtils.addAll( - new String[] { "partner", "vip-contact", "ex-partner", "billing", "contractual", "operation", "silent" }, - SUBSCRIBER_ROLES); - - // at least as the number of lines in business_partners.csv from test-data, but less than real data partner count - public static final int MAX_NUMBER_OF_TEST_DATA_PARTNERS = 100; - public static final int DELIBERATELY_BROKEN_BUSINESS_PARTNER_ID = 199; - - static int INITIAL_RELATION_ID = 2000000; - static int relationId = INITIAL_RELATION_ID; - - private static final List IGNORE_BUSINESS_PARTNERS = Arrays.asList( - -1 - ); - - private static final List IGNORE_CONTACTS = Arrays.asList( - -1 - ); - - private static final Map PERSON_TYPES_BY_CONTACT = Map.of( - 90072, HsOfficePersonType.NATURAL_PERSON, - 90641, HsOfficePersonType.LEGAL_PERSON, - 90368, HsOfficePersonType.LEGAL_PERSON, - 90564, HsOfficePersonType.NATURAL_PERSON, - -1, HsOfficePersonType.LEGAL_PERSON - ); - - static Map distinctPersons = new WriteOnceMap<>(); - - static Map contacts = new WriteOnceMap<>(); - static Map persons = new WriteOnceMap<>(); - static Map partners = new WriteOnceMap<>(); - static Map debitors = new WriteOnceMap<>(); - static Map memberships = new WriteOnceMap<>(); - - static Map relations = new WriteOnceMap<>(); - static Map sepaMandates = new WriteOnceMap<>(); - static Map bankAccounts = new WriteOnceMap<>(); - static Map coopShares = new WriteOnceMap<>(); - static Map coopAssets = new WriteOnceMap<>(); - - protected static void reset() { - contacts.clear(); - persons.clear(); - partners.clear(); - debitors.clear(); - memberships.clear(); - relations.clear(); - sepaMandates.clear(); - bankAccounts.clear(); - coopShares.clear(); - coopAssets.clear(); - relationId = INITIAL_RELATION_ID; - } - - @BeforeAll - static void resetOfficeImports() { - reset(); - } - - @Test - @Order(1) - void verifyInitialDatabaseHasNoTestData() { - assertThat((Integer) em.createNativeQuery( - "select count(*) from hs_office.contact", - Integer.class) - .getSingleResult()).isEqualTo(0); - assertThat((Integer) em.createNativeQuery( - """ - SELECT count(*) FROM information_schema.tables - WHERE table_schema = 'rbactest' AND table_name = 'customer' - """, - Integer.class) - .getSingleResult()).isEqualTo(0); - } - - @Test - @Order(1010) - void importBusinessPartners() { - - try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/office/business_partners.csv")) { - final var lines = readAllLines(reader); - importBusinessPartners(justHeader(lines), withoutHeader(lines)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Test - @Order(1019) - void verifyBusinessPartners() { - assumeThatWeAreImportingControlledTestData(); - - // no contacts yet => mostly null values - assertThat(toJsonFormattedString(partners)).isEqualToIgnoringWhitespace(""" - { - 100=partner(P-10003: null null, null), - 120=partner(P-10020: null null, null), - 122=partner(P-11022: null null, null), - 132=partner(P-10152: null null, null), - 190=partner(P-19090: null null, null), - 199=partner(P-19999: null null, null), - 213=partner(P-10000: null null, null), - 541=partner(P-11018: null null, null), - 542=partner(P-11019: null null, null) - } - """); - assertThat(toJsonFormattedString(contacts)).isEqualTo("{}"); - assertThat(toJsonFormattedString(debitors)).isEqualToIgnoringWhitespace(""" - { - 100=debitor(D-1000300: rel(anchor='null null, null', type='DEBITOR'), mim), - 120=debitor(D-1002000: rel(anchor='null null, null', type='DEBITOR'), xyz), - 122=debitor(D-1102200: rel(anchor='null null, null', type='DEBITOR'), xxx), - 132=debitor(D-1015200: rel(anchor='null null, null', type='DEBITOR'), rar), - 190=debitor(D-1909000: rel(anchor='null null, null', type='DEBITOR'), yyy), - 199=debitor(D-1999900: rel(anchor='null null, null', type='DEBITOR'), zzz), - 213=debitor(D-1000000: rel(anchor='null null, null', type='DEBITOR'), hsh), - 541=debitor(D-1101800: rel(anchor='null null, null', type='DEBITOR'), wws), - 542=debitor(D-1101900: rel(anchor='null null, null', type='DEBITOR'), dph) - } - """); - assertThat(toJsonFormattedString(memberships)).isEqualToIgnoringWhitespace(""" - { - 100=Membership(M-1000300, P-10003, [2000-12-06,), ACTIVE), - 120=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN), - 122=Membership(M-1102200, P-11022, [2021-04-01,), ACTIVE), - 132=Membership(M-1015200, P-10152, [2003-07-12,), ACTIVE), - 541=Membership(M-1101800, P-11018, [2021-05-17,), ACTIVE), - 542=Membership(M-1101900, P-11019, [2021-05-25,), ACTIVE) - } - """); - } - - @Test - @Order(1020) - void importContacts() { - try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/office/contacts.csv")) { - final var lines = readAllLines(reader); - importContacts(justHeader(lines), withoutHeader(lines)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Test - @Order(1029) - void verifyContacts() { - assumeThatWeAreImportingControlledTestData(); - - assertThat(toJsonFormattedString(partners)).isEqualToIgnoringWhitespace(""" - { - 100=partner(P-10003: ?? Michael Mellis, Michael Mellis, Herr Michael Mellis), - 120=partner(P-10020: LP JM GmbH, JM GmbH, Herr Philip Meyer-Contract), - 122=partner(P-11022: ?? Test PS, Test PS, Petra Schmidt), - 132=partner(P-10152: ?? Ragnar IT-Beratung, Ragnar IT-Beratung, Herr Ragnar Richter), - 190=partner(P-19090: NP Camus, Cecilia, Frau Cecilia Camus), - 199=partner(P-19999: null null, null), - 213=partner(P-10000: LP Hostsharing e.G., Hostsharing e.G., Hostmaster Hostsharing), - 541=partner(P-11018: ?? Wasserwerk Südholstein, Wasserwerk Südholstein, Frau Christiane Milberg), - 542=partner(P-11019: ?? Das Perfekte Haus, Das Perfekte Haus, Herr Richard Wiese) - } - """); - assertThat(toJsonFormattedString(contacts)).isEqualToIgnoringWhitespace(""" - { - 100=contact(caption='Michael Mellis, Herr Michael Mellis', emailAddresses='{"main": "michael@Mellis.example.org"}'), - 1200=contact(caption='JM e.K.', emailAddresses='{"main": "jm-ex-partner@example.org"}'), - 1201=contact(caption='JM GmbH, Frau Dr. Jenny Meyer-Billing', emailAddresses='{"main": "jm-billing@example.org"}'), - 1202=contact(caption='JM GmbH, Herr Andrew Meyer-Operation', emailAddresses='{"main": "am-operation@example.org"}'), - 1203=contact(caption='JM GmbH, Herr Philip Meyer-Contract', emailAddresses='{"main": "pm-partner@example.org"}'), - 1204=contact(caption='JM GmbH, Frau Tammy Meyer-VIP', emailAddresses='{"main": "tm-vip@example.org"}'), - 1301=contact(caption='Test PS, Petra Schmidt', emailAddresses='{"main": "ps@example.com"}'), - 132=contact(caption='Ragnar IT-Beratung, Herr Ragnar Richter', emailAddresses='{"main": "hostsharing@ragnar-richter.de"}'), - 1401=contact(caption='Frau Frauke Fanninga', emailAddresses='{"main": "ff@example.org"}'), - 1501=contact(caption='Frau Cecilia Camus', emailAddresses='{"main": "cc@example.org"}'), - 212=contact(caption='Hostsharing e.G., Hostmaster Hostsharing', emailAddresses='{"main": "hostmaster@hostsharing.net"}'), - 90436=contact(caption='Wasserwerk Südholstein, Frau Christiane Milberg', emailAddresses='{"main": "rechnung@ww-sholst.example.org"}'), - 90437=contact(caption='Das Perfekte Haus, Herr Richard Wiese', emailAddresses='{"main": "admin@das-perfekte-haus.example.org"}'), - 90438=contact(caption='Wasswerwerk Südholstein, Herr Karim Metzger', emailAddresses='{"main": "karim.metzger@ww-sholst.example.org"}'), - 90590=contact(caption='Das Perfekte Haus, Herr Inhaber R. Wiese', emailAddresses='{"main": "515217@kkemail.example.org"}'), - 90629=contact(caption='Ragnar Richter', emailAddresses='{"main": "mail@ragnar-richter..example.org"}'), - 90677=contact(caption='Eike Henning', emailAddresses='{"main": "hostsharing@eike-henning..example.org"}'), - 90698=contact(caption='Jan Henning', emailAddresses='{"main": "mail@jan-henning.example.org"}'), - 90699=contact(caption='Jan Henning', emailAddresses='{"main": "lists@jan-henning.example.org"}') - } - """); - assertThat(toJsonFormattedString(persons)).isEqualToIgnoringWhitespace(""" - { - 100=person(personType='??', tradeName='Michael Mellis', salutation='Herr', familyName='Mellis', givenName='Michael'), - 1200=person(personType='LP', tradeName='JM e.K.'), - 1201=person(personType='LP', tradeName='JM GmbH', salutation='Frau', title='Dr.', familyName='Meyer-Billing', givenName='Jenny'), - 1202=person(personType='LP', tradeName='JM GmbH', salutation='Herr', familyName='Meyer-Operation', givenName='Andrew'), - 1203=person(personType='LP', tradeName='JM GmbH', salutation='Herr', familyName='Meyer-Contract', givenName='Philip'), - 1204=person(personType='LP', tradeName='JM GmbH', salutation='Frau', familyName='Meyer-VIP', givenName='Tammy'), - 1301=person(personType='??', tradeName='Test PS', familyName='Schmidt', givenName='Petra'), - 132=person(personType='??', tradeName='Ragnar IT-Beratung', salutation='Herr', familyName='Richter', givenName='Ragnar'), - 1401=person(personType='NP', salutation='Frau', familyName='Fanninga', givenName='Frauke'), - 1501=person(personType='NP', salutation='Frau', familyName='Camus', givenName='Cecilia'), - 212=person(personType='LP', tradeName='Hostsharing e.G.', salutation='Firma', familyName='Hostsharing', givenName='Hostmaster'), - 90436=person(personType='??', tradeName='Wasserwerk Südholstein', salutation='Frau', familyName='Milberg', givenName='Christiane'), - 90437=person(personType='??', tradeName='Das Perfekte Haus', salutation='Herr', familyName='Wiese', givenName='Richard'), - 90438=person(personType='??', tradeName='Wasswerwerk Südholstein', salutation='Herr', familyName='Metzger', givenName='Karim'), - 90590=person(personType='??', tradeName='Das Perfekte Haus', salutation='Herr', familyName='Wiese', givenName='Inhaber R.'), - 90629=person(personType='NP', familyName='Richter', givenName='Ragnar'), - 90677=person(personType='NP', familyName='Henning', givenName='Eike'), - 90698=person(personType='NP', familyName='Henning', givenName='Jan'), - 90699=person(personType='NP', familyName='Henning', givenName='Jan') - } - """); - assertThat(toJsonFormattedString(debitors)).isEqualToIgnoringWhitespace(""" - { - 100=debitor(D-1000300: rel(anchor='?? Michael Mellis', type='DEBITOR', holder='?? Michael Mellis'), mim), - 120=debitor(D-1002000: rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH'), xyz), - 122=debitor(D-1102200: rel(anchor='?? Test PS', type='DEBITOR', holder='?? Test PS'), xxx), - 132=debitor(D-1015200: rel(anchor='?? Ragnar IT-Beratung', type='DEBITOR', holder='?? Ragnar IT-Beratung'), rar), - 190=debitor(D-1909000: rel(anchor='NP Camus, Cecilia', type='DEBITOR', holder='NP Camus, Cecilia'), yyy), - 199=debitor(D-1999900: rel(anchor='null null, null', type='DEBITOR'), zzz), - 213=debitor(D-1000000: rel(anchor='LP Hostsharing e.G.', type='DEBITOR', holder='LP Hostsharing e.G.'), hsh), - 541=debitor(D-1101800: rel(anchor='?? Wasserwerk Südholstein', type='DEBITOR', holder='?? Wasserwerk Südholstein'), wws), - 542=debitor(D-1101900: rel(anchor='?? Das Perfekte Haus', type='DEBITOR', holder='?? Das Perfekte Haus'), dph) - } - """); - assertThat(toJsonFormattedString(memberships)).isEqualToIgnoringWhitespace(""" - { - 100=Membership(M-1000300, P-10003, [2000-12-06,), ACTIVE), - 120=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN), - 122=Membership(M-1102200, P-11022, [2021-04-01,), ACTIVE), - 132=Membership(M-1015200, P-10152, [2003-07-12,), ACTIVE), - 541=Membership(M-1101800, P-11018, [2021-05-17,), ACTIVE), - 542=Membership(M-1101900, P-11019, [2021-05-25,), ACTIVE) - } - """); - assertThat(toJsonFormattedString(relations)).isEqualToIgnoringWhitespace(""" - { - 2000000=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Michael Mellis', contact='Michael Mellis, Herr Michael Mellis'), - 2000001=rel(anchor='?? Michael Mellis', type='DEBITOR', holder='?? Michael Mellis', contact='Michael Mellis, Herr Michael Mellis'), - 2000002=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Ragnar IT-Beratung', contact='Ragnar IT-Beratung, Herr Ragnar Richter'), - 2000003=rel(anchor='?? Ragnar IT-Beratung', type='DEBITOR', holder='?? Ragnar IT-Beratung', contact='Ragnar IT-Beratung, Herr Ragnar Richter'), - 2000004=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='LP Hostsharing e.G.', contact='Hostsharing e.G., Hostmaster Hostsharing'), - 2000005=rel(anchor='LP Hostsharing e.G.', type='DEBITOR', holder='LP Hostsharing e.G.', contact='Hostsharing e.G., Hostmaster Hostsharing'), - 2000006=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Wasserwerk Südholstein', contact='Wasserwerk Südholstein, Frau Christiane Milberg'), - 2000007=rel(anchor='?? Wasserwerk Südholstein', type='DEBITOR', holder='?? Wasserwerk Südholstein', contact='Wasserwerk Südholstein, Frau Christiane Milberg'), - 2000008=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Das Perfekte Haus', contact='Das Perfekte Haus, Herr Richard Wiese'), - 2000009=rel(anchor='?? Das Perfekte Haus', type='DEBITOR', holder='?? Das Perfekte Haus', contact='Das Perfekte Haus, Herr Inhaber R. Wiese'), - 2000010=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='LP JM GmbH', contact='JM GmbH, Herr Philip Meyer-Contract'), - 2000011=rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH', contact='JM GmbH, Frau Dr. Jenny Meyer-Billing'), - 2000012=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Test PS', contact='Test PS, Petra Schmidt'), - 2000013=rel(anchor='?? Test PS', type='DEBITOR', holder='?? Test PS', contact='Test PS, Petra Schmidt'), - 2000014=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus'), - 2000015=rel(anchor='NP Camus, Cecilia', type='DEBITOR', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus'), - 2000016=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='null null, null'), - 2000017=rel(anchor='null null, null', type='DEBITOR'), - 2000018=rel(anchor='LP Hostsharing e.G.', type='OPERATIONS_ALERT', holder='LP Hostsharing e.G.', contact='Hostsharing e.G., Hostmaster Hostsharing'), - 2000019=rel(anchor='LP Hostsharing e.G.', type='OPERATIONS', holder='LP Hostsharing e.G.', contact='Hostsharing e.G., Hostmaster Hostsharing'), - 2000020=rel(anchor='LP Hostsharing e.G.', type='REPRESENTATIVE', holder='LP Hostsharing e.G.', contact='Hostsharing e.G., Hostmaster Hostsharing'), - 2000021=rel(anchor='?? Michael Mellis', type='OPERATIONS_ALERT', holder='?? Michael Mellis', contact='Michael Mellis, Herr Michael Mellis'), - 2000022=rel(anchor='?? Michael Mellis', type='OPERATIONS', holder='?? Michael Mellis', contact='Michael Mellis, Herr Michael Mellis'), - 2000023=rel(anchor='?? Michael Mellis', type='REPRESENTATIVE', holder='?? Michael Mellis', contact='Michael Mellis, Herr Michael Mellis'), - 2000024=rel(anchor='?? Michael Mellis', type='SUBSCRIBER', mark='operations-discussion', holder='?? Michael Mellis', contact='Michael Mellis, Herr Michael Mellis'), - 2000025=rel(anchor='?? Michael Mellis', type='SUBSCRIBER', mark='operations-announce', holder='?? Michael Mellis', contact='Michael Mellis, Herr Michael Mellis'), - 2000026=rel(anchor='?? Michael Mellis', type='SUBSCRIBER', mark='generalversammlung', holder='?? Michael Mellis', contact='Michael Mellis, Herr Michael Mellis'), - 2000027=rel(anchor='?? Michael Mellis', type='SUBSCRIBER', mark='members-announce', holder='?? Michael Mellis', contact='Michael Mellis, Herr Michael Mellis'), - 2000028=rel(anchor='?? Michael Mellis', type='SUBSCRIBER', mark='members-discussion', holder='?? Michael Mellis', contact='Michael Mellis, Herr Michael Mellis'), - 2000029=rel(anchor='?? Ragnar IT-Beratung', type='OPERATIONS_ALERT', holder='?? Ragnar IT-Beratung', contact='Ragnar IT-Beratung, Herr Ragnar Richter'), - 2000030=rel(anchor='?? Ragnar IT-Beratung', type='OPERATIONS', holder='?? Ragnar IT-Beratung', contact='Ragnar IT-Beratung, Herr Ragnar Richter'), - 2000031=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='operations-discussion', holder='?? Ragnar IT-Beratung', contact='Ragnar IT-Beratung, Herr Ragnar Richter'), - 2000032=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='operations-announce', holder='?? Ragnar IT-Beratung', contact='Ragnar IT-Beratung, Herr Ragnar Richter'), - 2000033=rel(anchor='LP JM GmbH', type='EX_PARTNER', holder='LP JM e.K.', contact='JM e.K.'), - 2000034=rel(anchor='LP JM GmbH', type='OPERATIONS_ALERT', holder='LP JM GmbH', contact='JM GmbH, Herr Andrew Meyer-Operation'), - 2000035=rel(anchor='LP JM GmbH', type='OPERATIONS', holder='LP JM GmbH', contact='JM GmbH, Herr Andrew Meyer-Operation'), - 2000036=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='JM GmbH, Herr Andrew Meyer-Operation'), - 2000037=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='operations-announce', holder='LP JM GmbH', contact='JM GmbH, Herr Andrew Meyer-Operation'), - 2000038=rel(anchor='LP JM GmbH', type='REPRESENTATIVE', holder='LP JM GmbH', contact='JM GmbH, Herr Philip Meyer-Contract'), - 2000039=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='members-announce', holder='LP JM GmbH', contact='JM GmbH, Herr Philip Meyer-Contract'), - 2000040=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='customers-announce', holder='LP JM GmbH', contact='JM GmbH, Herr Philip Meyer-Contract'), - 2000041=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='JM GmbH, Frau Tammy Meyer-VIP'), - 2000042=rel(anchor='?? Test PS', type='OPERATIONS_ALERT', holder='?? Test PS', contact='Test PS, Petra Schmidt'), - 2000043=rel(anchor='?? Test PS', type='OPERATIONS', holder='?? Test PS', contact='Test PS, Petra Schmidt'), - 2000044=rel(anchor='?? Test PS', type='REPRESENTATIVE', holder='?? Test PS', contact='Test PS, Petra Schmidt'), - 2000045=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='operations-announce', holder='NP Fanninga, Frauke', contact='Frau Frauke Fanninga'), - 2000046=rel(anchor='NP Camus, Cecilia', type='OPERATIONS_ALERT', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus'), - 2000047=rel(anchor='NP Camus, Cecilia', type='OPERATIONS', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus'), - 2000048=rel(anchor='NP Camus, Cecilia', type='REPRESENTATIVE', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus'), - 2000049=rel(anchor='?? Wasserwerk Südholstein', type='REPRESENTATIVE', holder='?? Wasserwerk Südholstein', contact='Wasserwerk Südholstein, Frau Christiane Milberg'), - 2000050=rel(anchor='?? Wasserwerk Südholstein', type='SUBSCRIBER', mark='generalversammlung', holder='?? Wasserwerk Südholstein', contact='Wasserwerk Südholstein, Frau Christiane Milberg'), - 2000051=rel(anchor='?? Wasserwerk Südholstein', type='SUBSCRIBER', mark='members-announce', holder='?? Wasserwerk Südholstein', contact='Wasserwerk Südholstein, Frau Christiane Milberg'), - 2000052=rel(anchor='?? Wasserwerk Südholstein', type='SUBSCRIBER', mark='members-discussion', holder='?? Wasserwerk Südholstein', contact='Wasserwerk Südholstein, Frau Christiane Milberg'), - 2000053=rel(anchor='?? Das Perfekte Haus', type='OPERATIONS_ALERT', holder='?? Das Perfekte Haus', contact='Das Perfekte Haus, Herr Richard Wiese'), - 2000054=rel(anchor='?? Das Perfekte Haus', type='OPERATIONS', holder='?? Das Perfekte Haus', contact='Das Perfekte Haus, Herr Richard Wiese'), - 2000055=rel(anchor='?? Das Perfekte Haus', type='REPRESENTATIVE', holder='?? Das Perfekte Haus', contact='Das Perfekte Haus, Herr Richard Wiese'), - 2000056=rel(anchor='?? Das Perfekte Haus', type='SUBSCRIBER', mark='operations-discussion', holder='?? Das Perfekte Haus', contact='Das Perfekte Haus, Herr Richard Wiese'), - 2000057=rel(anchor='?? Das Perfekte Haus', type='SUBSCRIBER', mark='operations-announce', holder='?? Das Perfekte Haus', contact='Das Perfekte Haus, Herr Richard Wiese'), - 2000058=rel(anchor='?? Das Perfekte Haus', type='SUBSCRIBER', mark='generalversammlung', holder='?? Das Perfekte Haus', contact='Das Perfekte Haus, Herr Richard Wiese'), - 2000059=rel(anchor='?? Das Perfekte Haus', type='SUBSCRIBER', mark='members-announce', holder='?? Das Perfekte Haus', contact='Das Perfekte Haus, Herr Richard Wiese'), - 2000060=rel(anchor='?? Das Perfekte Haus', type='SUBSCRIBER', mark='members-discussion', holder='?? Das Perfekte Haus', contact='Das Perfekte Haus, Herr Richard Wiese'), - 2000061=rel(anchor='?? Wasserwerk Südholstein', type='OPERATIONS_ALERT', holder='?? Wasswerwerk Südholstein', contact='Wasswerwerk Südholstein, Herr Karim Metzger'), - 2000062=rel(anchor='?? Wasserwerk Südholstein', type='OPERATIONS', holder='?? Wasswerwerk Südholstein', contact='Wasswerwerk Südholstein, Herr Karim Metzger'), - 2000063=rel(anchor='?? Wasserwerk Südholstein', type='SUBSCRIBER', mark='operations-discussion', holder='?? Wasswerwerk Südholstein', contact='Wasswerwerk Südholstein, Herr Karim Metzger'), - 2000064=rel(anchor='?? Wasserwerk Südholstein', type='SUBSCRIBER', mark='operations-announce', holder='?? Wasswerwerk Südholstein', contact='Wasswerwerk Südholstein, Herr Karim Metzger'), - 2000065=rel(anchor='?? Ragnar IT-Beratung', type='REPRESENTATIVE', holder='NP Richter, Ragnar', contact='Ragnar Richter'), - 2000066=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='generalversammlung', holder='NP Richter, Ragnar', contact='Ragnar Richter'), - 2000067=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='members-announce', holder='NP Richter, Ragnar', contact='Ragnar Richter'), - 2000068=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='members-discussion', holder='NP Richter, Ragnar', contact='Ragnar Richter'), - 2000069=rel(anchor='?? Ragnar IT-Beratung', type='OPERATIONS_ALERT', holder='NP Henning, Eike', contact='Eike Henning'), - 2000070=rel(anchor='?? Ragnar IT-Beratung', type='OPERATIONS', holder='NP Henning, Eike', contact='Eike Henning'), - 2000071=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='operations-discussion', holder='NP Henning, Eike', contact='Eike Henning'), - 2000072=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='operations-announce', holder='NP Henning, Eike', contact='Eike Henning'), - 2000073=rel(anchor='?? Ragnar IT-Beratung', type='OPERATIONS_ALERT', holder='NP Henning, Jan', contact='Jan Henning'), - 2000074=rel(anchor='?? Ragnar IT-Beratung', type='OPERATIONS', holder='NP Henning, Jan', contact='Jan Henning'), - 2000075=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='operations-announce', holder='NP Henning, Jan', contact='Jan Henning') - } - """); - } - - @Test - @Order(1030) - void importSepaMandates() { - try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/office/sepa_mandates.csv")) { - final var lines = readAllLines(reader); - importSepaMandates(justHeader(lines), withoutHeader(lines)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Test - @Order(1039) - void verifySepaMandates() { - assumeThatWeAreImportingControlledTestData(); - - assertThat(toJsonFormattedString(bankAccounts)).isEqualToIgnoringWhitespace(""" - { - 132=bankAccount(DE37500105177419788228: holder='Michael Mellis', bic='GENODEF1HH2'), - 234234=bankAccount(DE37500105177419788228: holder='Michael Mellis', bic='INGDDEFFXXX'), - 235600=bankAccount(DE02300209000106531065: holder='JM e.K.', bic='CMCIDEDD'), - 235662=bankAccount(DE49500105174516484892: holder='JM GmbH', bic='INGDDEFFXXX'), - 30=bankAccount(DE02300209000106531065: holder='Ragnar Richter', bic='GENODEM1GLS'), - 386=bankAccount(DE49500105174516484892: holder='Wasserwerk Suedholstein', bic='NOLADE21WHO'), - 387=bankAccount(DE89370400440532013000: holder='Richard Wiese Das Perfekte Haus', bic='COBADEFFXXX') - } - """); - assertThat(toJsonFormattedString(sepaMandates)).isEqualToIgnoringWhitespace(""" - { - 132=SEPA-Mandate(DE37500105177419788228, HS-10003-20140801, 2013-12-01, [2013-12-01,)), - 234234=SEPA-Mandate(DE37500105177419788228, MH12345, 2004-06-12, [2004-06-15,)), - 235600=SEPA-Mandate(DE02300209000106531065, JM33344, 2004-01-15, [2004-01-20,2005-06-28)), - 235662=SEPA-Mandate(DE49500105174516484892, JM33344, 2005-06-28, [2005-07-01,)), - 30=SEPA-Mandate(DE02300209000106531065, HS-10152-20140801, 2013-12-01, [2013-12-01,2016-02-16)), - 386=SEPA-Mandate(DE49500105174516484892, HS-11018-20210512, 2021-05-12, [2021-05-17,)), - 387=SEPA-Mandate(DE89370400440532013000, HS-11019-20210519, 2021-05-19, [2021-05-25,)) - } - """); - } - - @Test - @Order(1040) - void importCoopShares() { - try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/office/share_transactions.csv")) { - final var lines = readAllLines(reader); - importCoopShares(justHeader(lines), withoutHeader(lines)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Test - @Order(1041) - void verifyCoopShares() { - assumeThatWeAreImportingControlledTestData(); - - assertThat(toJsonFormattedString(coopShares)).isEqualToIgnoringWhitespace(""" - { - 241=CoopShareTransaction(M-1000300: 2011-12-05, SUBSCRIPTION, 16, 1000300), - 279=CoopShareTransaction(M-1015200: 2013-10-21, SUBSCRIPTION, 1, 1015200), - 33451=CoopShareTransaction(M-1002000: 2000-12-06, SUBSCRIPTION, 2, 1002000, initial share subscription), - 33701=CoopShareTransaction(M-1000300: 2005-01-10, SUBSCRIPTION, 40, 1000300, increase), - 33810=CoopShareTransaction(M-1002000: 2016-12-31, CANCELLATION, 22, 1002000, membership ended), - 3=CoopShareTransaction(M-1000300: 2000-12-06, SUBSCRIPTION, 80, 1000300, initial share subscription), - 523=CoopShareTransaction(M-1000300: 2020-12-08, SUBSCRIPTION, 96, 1000300, Kapitalerhoehung), - 562=CoopShareTransaction(M-1101800: 2021-05-17, SUBSCRIPTION, 4, 1101800, Beitritt), - 563=CoopShareTransaction(M-1101900: 2021-05-25, SUBSCRIPTION, 1, 1101900, Beitritt), - 721=CoopShareTransaction(M-1000300: 2023-10-10, SUBSCRIPTION, 96, 1000300, Kapitalerhoehung), - 90=CoopShareTransaction(M-1015200: 2003-07-12, SUBSCRIPTION, 1, 1015200) - } - """); - } - - @Test - @Order(1050) - void importCoopAssets() { - try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/office/asset_transactions.csv")) { - final var lines = readAllLines(reader); - importCoopAssets(justHeader(lines), withoutHeader(lines)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Test - @Order(1059) - void verifyCoopAssets() { - assumeThatWeAreImportingControlledTestData(); - - assertThat(toJsonFormattedString(coopAssets)).isEqualToIgnoringWhitespace(""" - { - 1093=CoopAssetsTransaction(M-1000300: 2023-10-05, DEPOSIT, 3072, 1000300, Kapitalerhoehung - Ueberweisung), - 1094=CoopAssetsTransaction(M-1000300: 2023-10-06, DEPOSIT, 3072, 1000300, Kapitalerhoehung - Ueberweisung), - 31000=CoopAssetsTransaction(M-1002000: 2000-12-06, DEPOSIT, 128.00, 1002000, for subscription B), - 32000=CoopAssetsTransaction(M-1000300: 2005-01-10, DEPOSIT, 2560.00, 1000300, for subscription C), - 33001=CoopAssetsTransaction(M-1000300: 2005-01-10, TRANSFER, -512.00, 1000300, for transfer to 10, M-1002000:ADO:+512.00), - 33002=CoopAssetsTransaction(M-1002000: 2005-01-10, ADOPTION, 512.00, 1002000, for transfer from 7), - 34001=CoopAssetsTransaction(M-1002000: 2016-12-31, CLEARING, -8.00, 1002000, for cancellation D), - 34002=CoopAssetsTransaction(M-1002000: 2016-12-31, DISBURSAL, -100.00, 1002000, for cancellation D), - 34003=CoopAssetsTransaction(M-1002000: 2016-12-31, LOSS, -20.00, 1002000, for cancellation D), - 35001=CoopAssetsTransaction(M-1909000: 2024-01-15, DEPOSIT, 128.00, 1909000, for subscription E), - 35002=CoopAssetsTransaction(M-1909000: 2024-01-20, REVERSAL, -128.00, 1909000, chargeback for subscription E, M-1909000:DEP:+128.00), - 358=CoopAssetsTransaction(M-1000300: 2000-12-06, DEPOSIT, 5120, 1000300, for subscription A), - 442=CoopAssetsTransaction(M-1015200: 2003-07-07, DEPOSIT, 64, 1015200), - 577=CoopAssetsTransaction(M-1000300: 2011-12-12, DEPOSIT, 1024, 1000300), - 632=CoopAssetsTransaction(M-1015200: 2013-10-21, DEPOSIT, 64, 1015200), - 885=CoopAssetsTransaction(M-1000300: 2020-12-15, DEPOSIT, 6144, 1000300, Einzahlung), - 924=CoopAssetsTransaction(M-1101800: 2021-05-21, DEPOSIT, 256, 1101800, Beitritt - Lastschrift), - 925=CoopAssetsTransaction(M-1101900: 2021-05-31, DEPOSIT, 64, 1101900, Beitritt - Lastschrift) - } - """); - } - - @Test - @Order(1099) - void verifyMemberships() { - assumeThatWeAreImportingControlledTestData(); - - assertThat(toJsonFormattedString(memberships)).isEqualToIgnoringWhitespace(""" - { - 100=Membership(M-1000300, P-10003, [2000-12-06,), ACTIVE), - 120=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN), - 122=Membership(M-1102200, P-11022, [2021-04-01,), ACTIVE), - 132=Membership(M-1015200, P-10152, [2003-07-12,), ACTIVE), - 190=Membership(M-1909000, P-19090, empty, INVALID), - 541=Membership(M-1101800, P-11018, [2021-05-17,), ACTIVE), - 542=Membership(M-1101900, P-11019, [2021-05-25,), ACTIVE) - } - """); - } - - @Test - @Order(2000) - void verifyAllPartnersHavePersons() { - partners.forEach((id, p) -> { - final var partnerRel = p.getPartnerRel(); - assertThat(partnerRel).describedAs("partner " + id + " without partnerRel").isNotNull(); - if (id != DELIBERATELY_BROKEN_BUSINESS_PARTNER_ID) { - logError(() -> { - assertThat(partnerRel.getContact()).describedAs("partner " + id + " without partnerRel.contact") - .isNotNull(); - assertThat(partnerRel.getContact().getCaption()).describedAs( - "partner " + id + " without valid partnerRel.contact").isNotNull(); - }); - logError(() -> { - assertThat(partnerRel.getHolder()).describedAs("partner " + id + " without partnerRel.relHolder") - .isNotNull(); - assertThat(partnerRel.getHolder().getPersonType()).describedAs( - "partner " + id + " without valid partnerRel.relHolder").isNotNull(); - }); - } - }); - } - - @Test - @Order(3001) - void removeSelfRepresentativeRelations() { - - // this happens if a natural person is marked as 'contractual' for itself - final var idsToRemove = new HashSet(); - relations.forEach((id, r) -> { - if (r.getType() == HsOfficeRelationType.REPRESENTATIVE && r.getHolder() == r.getAnchor()) { - idsToRemove.add(id); - } - }); - - // remove self-representatives - idsToRemove.forEach(id -> { - System.out.println("removing self representative relation: " + relations.get(id).toString()); - relations.remove(id); - }); - } - - @Test - @Order(3002) - void removeEmptyRelations() { - - // avoid a error when persisting the deliberately invalid partner entry #99 - final var idsToRemove = new HashSet(); - relations.forEach((id, r) -> { - if (r.getContact() == null || r.getContact().getCaption() == null || - r.getHolder() == null || r.getHolder().getPersonType() == null) { - idsToRemove.add(id); - } - }); - - // expected relations created from partner #99 + Hostsharing eG itself - idsToRemove.forEach(id -> { - System.out.println("removing unused relation: " + relations.get(id).toString()); - relations.remove(id); - }); - } - - @Test - @Order(3003) - void removeEmptyPartners() { - - // avoid a error when persisting the deliberately invalid partner entry #99 - final var idsToRemove = new HashSet(); - partners.forEach((id, r) -> { - final var partnerRole = r.getPartnerRel(); - - // such a record is in test data to test error messages - if (partnerRole.getContact() == null || partnerRole.getContact().getCaption() == null || - partnerRole.getHolder() == null | partnerRole.getHolder().getPersonType() == null) { - idsToRemove.add(id); - } - }); - - // expected partners created from partner #99 + Hostsharing eG itself - idsToRemove.forEach(id -> { - System.out.println("removing unused partner: " + partners.get(id).toString()); - partners.remove(id); - }); - } - - @Test - @Order(3004) - void removeEmptyDebitors() { - - // avoid a error when persisting the deliberately invalid partner entry #99 - final var idsToRemove = new HashSet(); - debitors.forEach((id, d) -> { - final var debitorRel = d.getDebitorRel(); - if (debitorRel.getContact() == null || debitorRel.getContact().getCaption() == null || - debitorRel.getAnchor() == null || debitorRel.getAnchor().getPersonType() == null || - debitorRel.getHolder() == null || debitorRel.getHolder().getPersonType() == null) { - idsToRemove.add(id); - } - }); - idsToRemove.forEach(id -> debitors.remove(id)); - - assumeThatWeAreImportingControlledTestData(); - assertThat(idsToRemove.size()).isEqualTo(1); // only from partner #99 - } - - @Test - @Order(3005) - void removeEmptyPersons() { - // avoid a error when persisting the deliberately invalid partner entry #99 - final var idsToRemove = new HashSet(); - persons.forEach((id, p) -> { - if (p.getPersonType() == null || - (p.getFamilyName() == null && p.getGivenName() == null && p.getTradeName() == null)) { - idsToRemove.add(id); - } - }); - idsToRemove.forEach(id -> persons.remove(id)); - - assumeThatWeAreImportingControlledTestData(); - assertThat(idsToRemove.size()).isEqualTo(0); - } - - @Test - @Order(9000) - @ContinueOnFailure - void logCollectedErrorsBeforePersist() { - assertNoErrors(); - } - - @Test - @Order(9010) - void persistOfficeEntities() { - - System.out.println("PERSISTING office data to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'"); - makeSureThatTheImportAdminUserExists(); - - assertEmptyTable("hs_office.contact"); - jpaAttempt.transacted(() -> { - context(rbacSuperuser); - contacts.forEach(this::persist); - updateLegacyIds(contacts, "hs_office.contact_legacy_id", "contact_id"); - }).assertSuccessful(); - - jpaAttempt.transacted(() -> { - context(rbacSuperuser); - persons.forEach(this::persist); - }).assertSuccessful(); - - jpaAttempt.transacted(() -> { - context(rbacSuperuser); - relations.forEach(this::persist); - }).assertSuccessful(); - - System.out.println("persisting " + partners.size() + " partners"); - assertEmptyTable("hs_office.partner"); - jpaAttempt.transacted(() -> { - context(rbacSuperuser); - partners.forEach((id, partner) -> { - // TODO: this is ugly and I don't know why it's suddenly necessary - partner.getPartnerRel().setAnchor(em.merge(partner.getPartnerRel().getAnchor())); - partner.getPartnerRel().setHolder(em.merge(partner.getPartnerRel().getHolder())); - partner.getPartnerRel().setContact(em.merge(partner.getPartnerRel().getContact())); - partner.setPartnerRel(em.merge(partner.getPartnerRel())); - em.persist(partner); - }); - updateLegacyIds(partners, "hs_office.partner_legacy_id", "bp_id"); - }).assertSuccessful(); - - jpaAttempt.transacted(() -> { - context(rbacSuperuser); - debitors.forEach((id, debitor) -> { - debitor.setDebitorRel(em.merge(debitor.getDebitorRel())); - persist(id, debitor); - }); - }).assertSuccessful(); - - jpaAttempt.transacted(() -> { - context(rbacSuperuser); - memberships.forEach(this::persist); - }).assertSuccessful(); - - jpaAttempt.transacted(() -> { - context(rbacSuperuser); - bankAccounts.forEach(this::persist); - }).assertSuccessful(); - - jpaAttempt.transacted(() -> { - context(rbacSuperuser); - sepaMandates.forEach(this::persist); - updateLegacyIds(sepaMandates, "hs_office.sepamandate_legacy_id", "sepa_mandate_id"); - }).assertSuccessful(); - - jpaAttempt.transacted(() -> { - context(rbacSuperuser); - coopShares.forEach(this::persist); - updateLegacyIds(coopShares, "hs_office.coopsharetx_legacy_id", "member_share_id"); - - }).assertSuccessful(); - - jpaAttempt.transacted(() -> { - context(rbacSuperuser); - coopAssets.forEach(this::persist); - updateLegacyIds(coopAssets, "hs_office.coopassettx_legacy_id", "member_asset_id"); - }).assertSuccessful(); - - } - private void assertEmptyTable(final String qualifiedTableName) { - assertThat((Integer) em.createNativeQuery( - "select count(*) from " + qualifiedTableName, - Integer.class) - .getSingleResult()).describedAs("expected empty " + qualifiedTableName).isEqualTo(0); - } - - @Test - @Order(9190) - void verifyMembershipsActuallyPersisted() { - final var biCount = (Integer) em.createNativeQuery("select count(*) from hs_office.membership", Integer.class) - .getSingleResult(); - assertThat(biCount).isGreaterThan(isImportingControlledTestData() ? 5 : 300); - } - - private static boolean isImportingControlledTestData() { - return partners.size() <= MAX_NUMBER_OF_TEST_DATA_PARTNERS; - } - - private static void assumeThatWeAreImportingControlledTestData() { - assumeThat(partners.size()).isLessThanOrEqualTo(MAX_NUMBER_OF_TEST_DATA_PARTNERS); - } - - @Test - @Order(9999) - @ContinueOnFailure - void logCollectedErrors() { - this.assertNoErrors(); - } - - private void importBusinessPartners(final String[] header, final List records) { - - final var columns = new Columns(header); - - records.stream() - .map(this::trimAll) - .map(row -> new Record(columns, row)) - .forEach(rec -> { - final Integer bpId = rec.getInteger("bp_id"); - if (IGNORE_BUSINESS_PARTNERS.contains(bpId)) { - return; - } - - final var person = HsOfficePersonRealEntity.builder().build(); - - final var partnerRel = addRelation( - HsOfficeRelationType.PARTNER, - null, // is set after contacts when the person for 'Hostsharing eG' is known - person, - null // is set during contacts import depending on assigned roles - ); - - final var partner = HsOfficePartnerRealEntity.builder() - .partnerNumber(rec.getInteger("member_id")) - .details(HsOfficePartnerDetailsEntity.builder().build()) - .partnerRel(partnerRel) - .build(); - partners.put(bpId, partner); - - final var debitorRel = addRelation( - HsOfficeRelationType.DEBITOR, partnerRel.getHolder(), // partner person - null, // will be set in contacts import - null // will beset in contacts import - ); - - final var debitor = HsOfficeDebitorEntity.builder() - .debitorNumberSuffix("00") - .partner(partner) - .debitorRel(debitorRel) - .defaultPrefix(rec.getString("member_code").replace("hsh00-", "")) - .billable(rec.isEmpty("free") || rec.getString("free").equals("f")) - .vatReverseCharge(rec.getBoolean("exempt_vat")) - .vatBusiness("GROSS".equals(rec.getString("indicator_vat"))) // TODO: remove - .vatId(rec.getString("uid_vat")) - .build(); - debitors.put(bpId, debitor); - - if (isNotBlank(rec.getString("member_since"))) { - assertThat(rec.getInteger("member_id")).isEqualTo(partner.getPartnerNumber()); - final var membership = HsOfficeMembershipEntity.builder() - .partner(partner) - .memberNumberSuffix("00") - .validity(toPostgresDateRange( - rec.getLocalDate("member_since"), - rec.getLocalDate("member_until"))) - .membershipFeeBillable(rec.isEmpty("member_role")) - .status( - isBlank(rec.getString("member_until")) - ? HsOfficeMembershipStatus.ACTIVE - : HsOfficeMembershipStatus.UNKNOWN) - .build(); - memberships.put(bpId, membership); - } - }); - } - - private void importCoopShares(final String[] header, final List records) { - - final var columns = new Columns(header); - - records.stream() - .map(this::trimAll) - .map(row -> new Record(columns, row)) - .forEach(rec -> { - final var bpId = rec.getInteger("bp_id"); - if (IGNORE_BUSINESS_PARTNERS.contains(bpId)) { - return; - } - - final var member = ofNullable(memberships.get(bpId)) - .orElseGet(() -> createOnDemandMembership(bpId)); - - final var shareTransaction = HsOfficeCoopSharesTransactionEntity.builder() - .membership(member) - .valueDate(rec.getLocalDate("date")) - .transactionType( - "SUBSCRIPTION".equals(rec.getString("action")) - ? HsOfficeCoopSharesTransactionType.SUBSCRIPTION - : "UNSUBSCRIPTION".equals(rec.getString("action")) - ? HsOfficeCoopSharesTransactionType.CANCELLATION - : HsOfficeCoopSharesTransactionType.REVERSAL - ) - .shareCount(rec.getInteger("quantity")) - .comment(rec.getString("comment")) - .reference(member.getMemberNumber().toString()) - .build(); - - if (shareTransaction.getTransactionType() == HsOfficeCoopSharesTransactionType.REVERSAL) { - final var negativeValue = -shareTransaction.getShareCount(); - final var revertedShareTx = coopShares.values().stream().filter(a -> - a.getTransactionType() != HsOfficeCoopSharesTransactionType.REVERSAL && - a.getMembership() == shareTransaction.getMembership() && - a.getShareCount() == negativeValue) - .findAny() - .orElseThrow(() -> new IllegalStateException( - "cannot determine share reverse entry for reversal " + shareTransaction)); - shareTransaction.setRevertedShareTx(revertedShareTx); - } - coopShares.put(rec.getInteger("member_share_id"), shareTransaction); - }); - } - - private void importCoopAssets(final String[] header, final List records) { - - final var columns = new Columns(header); - - records.stream() - .map(this::trimAll) - .map(row -> new Record(columns, row)) - .forEach(rec -> { - final var bpId = rec.getInteger("bp_id"); - - if (this.IGNORE_BUSINESS_PARTNERS.contains(bpId)) { - return; - } - - final var member = ofNullable(memberships.get(bpId)) - .orElseGet(() -> createOnDemandMembership(bpId)); - - final var assetTypeMapping = new HashMap() { - - { - put("ADJUSTMENT", HsOfficeCoopAssetsTransactionType.REVERSAL); - put("HANDOVER", HsOfficeCoopAssetsTransactionType.TRANSFER); - put("ADOPTION", HsOfficeCoopAssetsTransactionType.ADOPTION); - put("LOSS", HsOfficeCoopAssetsTransactionType.LOSS); - put("CLEARING", HsOfficeCoopAssetsTransactionType.CLEARING); - put("PRESCRIPTION", HsOfficeCoopAssetsTransactionType.LIMITATION); - put("PAYBACK", HsOfficeCoopAssetsTransactionType.DISBURSAL); - put("PAYMENT", HsOfficeCoopAssetsTransactionType.DEPOSIT); - } - - public HsOfficeCoopAssetsTransactionType get(final String key) { - final var value = super.get(key); - if (value != null) { - return value; - } - throw new IllegalStateException("no mapping value found for: " + key); - } - }; - - final var assetTransaction = HsOfficeCoopAssetsTransactionEntity.builder() - .membership(member) - .valueDate(rec.getLocalDate("date")) - .transactionType(assetTypeMapping.get(rec.getString("action"))) - .assetValue(rec.getBigDecimal("amount")) - .comment(rec.getString("comment")) - .reference(member.getMemberNumber().toString()) - .build(); - coopAssets.put(rec.getInteger("member_asset_id"), assetTransaction); - }); - - coopAssets.entrySet().forEach(entry -> { - final var legacyId = entry.getKey(); - final var assetTransaction = entry.getValue(); - if (assetTransaction.getTransactionType() == HsOfficeCoopAssetsTransactionType.REVERSAL) { - connectToRelatedRevertedAssetTx(legacyId, assetTransaction); - } - if (assetTransaction.getTransactionType() == HsOfficeCoopAssetsTransactionType.TRANSFER) { - connectToRelatedAdoptionAssetTx(legacyId, assetTransaction); - } - }); - } - - private static void connectToRelatedRevertedAssetTx( - final int legacyId, - final HsOfficeCoopAssetsTransactionEntity assetTransaction) { - final var negativeValue = assetTransaction.getAssetValue().negate(); - final var revertedAssetTx = coopAssets.values().stream().filter(a -> - a.getTransactionType() != HsOfficeCoopAssetsTransactionType.REVERSAL && - a.getMembership() == assetTransaction.getMembership() && - a.getAssetValue().equals(negativeValue)) - .findAny() - .orElseThrow(() -> new IllegalStateException( - "cannot determine asset reverse entry for reversal " + assetTransaction)); - assetTransaction.setRevertedAssetTx(revertedAssetTx); - //revertedAssetTx.setAssetReversalTx(assetTransaction); - } - - private static void connectToRelatedAdoptionAssetTx( - final int legacyId, - final HsOfficeCoopAssetsTransactionEntity assetTransaction) { - final var negativeValue = assetTransaction.getAssetValue().negate(); - final var adoptionAssetTx = coopAssets.values().stream().filter(a -> - a.getTransactionType() == HsOfficeCoopAssetsTransactionType.ADOPTION && - (!a.getValueDate().equals(LocalDate.of(2014, 12, 31)) || a.getComment() - .contains(Integer.toString(assetTransaction.getMembership().getMemberNumber() / 100))) && - a.getMembership() != assetTransaction.getMembership() && - a.getValueDate().equals(assetTransaction.getValueDate()) && - a.getAssetValue().equals(negativeValue)) - .findAny() - .orElseThrow(() -> new IllegalStateException( - "cannot determine asset adoption entry for reversal " + assetTransaction)); - assetTransaction.setAdoptionAssetTx(adoptionAssetTx); - //adoptionAssetTx.setAssetTransferTx(assetTransaction); - } - - private static HsOfficeMembershipEntity createOnDemandMembership(final Integer bpId) { - final var onDemandMembership = HsOfficeMembershipEntity.builder() - .memberNumberSuffix("00") - .membershipFeeBillable(false) - .partner(partners.get(bpId)) - .status(HsOfficeMembershipStatus.INVALID) - .build(); - memberships.put(bpId, onDemandMembership); - return onDemandMembership; - } - - private void importSepaMandates(final String[] header, final List records) { - - final var columns = new Columns(header); - - records.stream() - .map(this::trimAll) - .map(row -> new Record(columns, row)) - .forEach(rec -> { - final var debitor = debitors.get(rec.getInteger("bp_id")); - - if (this.IGNORE_BUSINESS_PARTNERS.contains(rec.getInteger("bp_id"))) { - return; - } - - final var sepaMandate = HsOfficeSepaMandateEntity.builder() - .debitor(debitor) - .bankAccount(HsOfficeBankAccountEntity.builder() - .holder(rec.getString("bank_customer")) - // .bankName(rec.get("bank_name")) // not supported - .iban(rec.getString("bank_iban")) - .bic(rec.getString("bank_bic")) - .build()) - .reference(rec.getString("mandat_ref")) - .agreement(LocalDate.parse(rec.getString("mandat_signed"))) - .validity(toPostgresDateRange( - rec.getLocalDate("mandat_since"), - rec.getLocalDate("mandat_until"))) - .build(); - - sepaMandates.put(rec.getInteger("sepa_mandat_id"), sepaMandate); - bankAccounts.put(rec.getInteger("sepa_mandat_id"), sepaMandate.getBankAccount()); - }); - } - - private void importContacts(final String[] header, final List records) { - - final var columns = new Columns(header); - - records.stream() - .map(this::trimAll) - .map(row -> new Record(columns, row)) - .forEach(rec -> { - final var contactId = rec.getInteger("contact_id"); - final var bpId = rec.getInteger("bp_id"); - - if (IGNORE_CONTACTS.contains(contactId)) { - return; - } - if (IGNORE_BUSINESS_PARTNERS.contains(bpId)) { - return; - } - - if (rec.getString("roles").isBlank()) { - fail("empty roles assignment not allowed for contact_id: " + contactId); - } - - final var partner = partners.get(bpId); - final var debitor = debitors.get(bpId); - - final var partnerPerson = partner.getPartnerRel().getHolder(); - if (containsPartnerRel(rec)) { - partner.getPartnerRel().setHolder(addPerson(partnerPerson, rec)); - } - - HsOfficePersonRealEntity contactPerson = partnerPerson; - if (!StringUtils.equals(rec.getString("firma"), partnerPerson.getTradeName()) || - partnerPerson.getPersonType() != determinePersonType(rec) || - !StringUtils.equals(rec.getString("title"), partnerPerson.getTitle()) || - !StringUtils.equals(rec.getString("salut"), partnerPerson.getSalutation()) || - !StringUtils.equals(rec.getString("first_name"), partnerPerson.getGivenName()) || - !StringUtils.equals(rec.getString("last_name"), partnerPerson.getFamilyName())) { - contactPerson = addPerson(HsOfficePersonRealEntity.builder().build(), rec); - } - - final var contact = HsOfficeContactRealEntity.builder().build(); - initContact(contact, rec); - - if (containsPartnerRel(rec)) { - assertThat(partner.getPartnerRel().getContact()).isNull(); - partner.getPartnerRel().setContact(contact); - } - if (containsRole(rec, "billing")) { - assertThat(debitor.getDebitorRel().getContact()).isNull(); - debitor.getDebitorRel().setHolder(contactPerson); - debitor.getDebitorRel().setContact(contact); - } - if (containsRole(rec, "operation")) { - addRelation(HsOfficeRelationType.OPERATIONS_ALERT, partnerPerson, contactPerson, contact); - addRelation(HsOfficeRelationType.OPERATIONS, partnerPerson, contactPerson, contact); - } - if (containsRole(rec, "silent")) { - addRelation(HsOfficeRelationType.OPERATIONS, partnerPerson, contactPerson, contact); - } - if (containsRole(rec, "contractual")) { - addRelation(HsOfficeRelationType.REPRESENTATIVE, partnerPerson, contactPerson, contact); - } - if (containsRole(rec, "ex-partner")) { - addRelation(HsOfficeRelationType.EX_PARTNER, partnerPerson, contactPerson, contact); - } - if (containsRole(rec, "vip-contact")) { - addRelation(HsOfficeRelationType.VIP_CONTACT, partnerPerson, contactPerson, contact); - } - for (String subscriberRole : SUBSCRIBER_ROLES) { - if (containsRole(rec, subscriberRole)) { - addRelation(HsOfficeRelationType.SUBSCRIBER, partnerPerson, contactPerson, contact) - .setMark(subscriberRole.split(":")[1]) - ; - } - } - verifyContainsOnlyKnownRoles(rec.getString("roles")); - }); - - distinctAnchorAndHolderPersons(); - assertNoMissingContractualRelations(); - useHostsharingAsPartnerAnchor(); - } - - private void distinctAnchorAndHolderPersons() { - relations.values().forEach(rel -> { - rel.setAnchor(distinctPerson(rel.getAnchor())); - rel.setHolder(distinctPerson(rel.getHolder())); - }); - } - - private static void assertNoMissingContractualRelations() { - final var contractualMissing = new HashSet(); - partners.forEach((id, partner) -> { - final var partnerPerson = partner.getPartnerRel().getHolder(); - if (relations.values().stream() - .filter(rel -> rel.getAnchor() == partnerPerson && rel.getType() == HsOfficeRelationType.REPRESENTATIVE) - .findFirst().isEmpty()) { - contractualMissing.add(partner.getPartnerNumber()); - } - }); - if (isImportingControlledTestData()) { - assertThat(contractualMissing).containsOnly(19999); // deliberately wrong partner entry - } else { - assertThat(contractualMissing).as("partners without contractual contact found").isEmpty(); - } - } - - private static void useHostsharingAsPartnerAnchor() { - final var mandant = persons.values().stream() - .filter(p -> p.getTradeName().startsWith("Hostsharing e")) - .findFirst() - .orElseThrow(); - relations.values().stream() - .filter(r -> r.getType() == HsOfficeRelationType.PARTNER) - .forEach(r -> r.setAnchor(mandant)); - } - - private static boolean containsRole(final Record rec, final String role) { - final var roles = rec.getString("roles"); - return ("," + roles + ",").contains("," + role + ","); - } - - private static boolean containsPartnerRel(final Record rec) { - return containsRole(rec, "partner"); - } - - private static HsOfficeRelationRealEntity addRelation( - final HsOfficeRelationType type, - final HsOfficePersonRealEntity anchor, - final HsOfficePersonRealEntity holder, - final HsOfficeContactRealEntity contact) { - final var rel = HsOfficeRelationRealEntity.builder() - .anchor(anchor) - .holder(holder) - .contact(contact) - .type(type) - .build(); - relations.put(relationId++, rel); - return rel; - } - - private HsOfficePersonRealEntity addPerson(final HsOfficePersonRealEntity person, final Record contactRecord) { - person.setSalutation(contactRecord.getString("salut")); - person.setTitle(contactRecord.getString("title")); - person.setGivenName(contactRecord.getString("first_name")); - person.setFamilyName(contactRecord.getString("last_name")); - person.setTradeName(contactRecord.getString("firma")); - person.setPersonType(determinePersonType(contactRecord)); - - persons.put(contactRecord.getInteger("contact_id"), distinctPerson(person)); - return person; - } - - // Makes sure, that for identical person-data always the same HsOfficePersonRealEntity is used. - // Such can come from multiple legacy contacts with different contact data for the same person in different confexts. - private HsOfficePersonRealEntity distinctPerson(final HsOfficePersonRealEntity person) { - if (person == null) { - return null; - } - - final var personKey = ( - person.getPersonType() + "|" + - person.getSalutation() + "|" + - person.getTradeName() + "|" + - person.getTitle() + "|" + - person.getGivenName() + "|" + - person.getFamilyName() - ).toLowerCase(); - - if (!distinctPersons.containsKey(personKey)) { - distinctPersons.put(personKey, person); - } - return distinctPersons.get(personKey); - } - - private static HsOfficePersonType determinePersonType(final Record contactRecord) { - String roles = contactRecord.getString("roles"); - String familyName = contactRecord.getString("last_name"); - String givenName = contactRecord.getString("first_name"); - String tradeName = contactRecord.getString("firma"); - - if (PERSON_TYPES_BY_CONTACT.containsKey(contactRecord.getInteger("contact_id"))) { - return PERSON_TYPES_BY_CONTACT.get(contactRecord.getInteger("contact_id")); - } - - if (tradeName.isBlank() || tradeName.startsWith("verstorben")) { - return HsOfficePersonType.NATURAL_PERSON; - } else - // contractual && !partner with a firm and a natural person name - // should actually be split up into two persons - // but the legacy database consists such records - - if (endsWithWord(tradeName, "OHG", "GbR", "KG", "UG", "PartGmbB", "mbB")) { - return HsOfficePersonType.INCORPORATED_FIRM; // Personengesellschaft. Gesellschafter haften persönlich. - } else if (containsWord(tradeName, "e.K.", "e.G.", "eG", "gGmbH", "GmbH", "mbH", "AG", "e.V.", "eV", "e.V") - || tradeName.toLowerCase().contains("haftungsbeschränkt") - || tradeName.toLowerCase().contains("stiftung") - || tradeName.toLowerCase().contains("stichting") - || tradeName.toLowerCase().contains("foundation") - || tradeName.toLowerCase().contains("schule") - || tradeName.toLowerCase().contains("verein") - || tradeName.toLowerCase().contains("gewerkschaft") - || tradeName.toLowerCase().contains("gesellschaft") - || tradeName.toLowerCase().contains("kirche") - || tradeName.toLowerCase().contains("fraktion") - || tradeName.toLowerCase().contains("landkreis") - || tradeName.toLowerCase().contains("behörde") - || tradeName.toLowerCase().contains("bundesamt") - || tradeName.toLowerCase().contains("bezirksamt") - ) { - return HsOfficePersonType.LEGAL_PERSON; // Haftungsbeschränkt - } else if (roles.contains("contractual") && !roles.contains("partner") && - !familyName.isBlank() && !givenName.isBlank()) { - // REPRESENTATIVES are always natural persons - return HsOfficePersonType.NATURAL_PERSON; - } else { - return HsOfficePersonType.UNKNOWN_PERSON_TYPE; - } - } - - private static boolean endsWithWord(final String value, final String... endings) { - final var lowerCaseValue = value.toLowerCase(); - for (String ending : endings) { - if (lowerCaseValue.endsWith(" " + ending.toLowerCase())) { - return true; - } - } - return false; - } - - private static boolean containsWord(final String value, final String... endings) { - final var lowerCaseValue = value.toLowerCase(); - for (String ending : endings) { - if (lowerCaseValue.equals(ending.toLowerCase()) || - lowerCaseValue.startsWith(ending.toLowerCase() + " ") || - lowerCaseValue.contains(" " + ending.toLowerCase() + " ") || - lowerCaseValue.endsWith(" " + ending.toLowerCase())) { - return true; - } - } - return false; - } - - private void verifyContainsOnlyKnownRoles(final String roles) { - final var allowedRolesSet = stream(KNOWN_ROLES).collect(Collectors.toSet()); - final var givenRolesSet = stream(roles.replace(" ", "").split(",")).collect(Collectors.toSet()); - final var unexpectedRolesSet = new HashSet<>(givenRolesSet); - unexpectedRolesSet.removeAll(allowedRolesSet); - assertThat(unexpectedRolesSet).isEmpty(); - } - - private HsOfficeContactRealEntity initContact(final HsOfficeContactRealEntity contact, final Record contactRecord) { - - contact.setCaption(toCaption( - contactRecord.getString("firma"), - contactRecord.getString("salut"), - contactRecord.getString("title"), - contactRecord.getString("first_name"), - contactRecord.getString("last_name") - )); - contact.putEmailAddresses(Map.of("main", contactRecord.getString("email"))); - contact.putPostalAddress(toAddress(contactRecord)); - contact.putPhoneNumbers(toPhoneNumbers(contactRecord)); - - contacts.put(contactRecord.getInteger("contact_id"), contact); - return contact; - } - - private Map toPhoneNumbers(final Record rec) { - final var phoneNumbers = new LinkedHashMap(); - if (isNotBlank(rec.getString("phone_private"))) - phoneNumbers.put("phone_private", rec.getString("phone_private")); - if (isNotBlank(rec.getString("phone_office"))) - phoneNumbers.put("phone_office", rec.getString("phone_office")); - if (isNotBlank(rec.getString("phone_mobile"))) - phoneNumbers.put("phone_mobile", rec.getString("phone_mobile")); - if (isNotBlank(rec.getString("fax"))) - phoneNumbers.put("fax", rec.getString("fax")); - return phoneNumbers; - } - - private Map toAddress(final Record rec) { - final var result = new LinkedHashMap(); - final var name = toName( - rec.getString("salut"), - rec.getString("title"), - rec.getString("first_name"), - rec.getString("last_name")); - if (isNotBlank(name)) - result.put("name", name); - if (isNotBlank(rec.getString("firma"))) - result.put("firm", name); - - List.of("co", "street", "zipcode", "city", "country").forEach(key -> { - if (isNotBlank(rec.getString(key))) - result.put(key, rec.getString(key)); - }); - return result; - } - - private String toCaption( - final String firm, - final String salut, - final String title, - final String firstName, - final String lastName) { - final var result = new StringBuilder(); - if (isNotBlank(salut) && !salut.equals("Firma")) - result.append((isBlank(result) ? "" : " ") + salut); - if (isNotBlank(title)) - result.append((isBlank(result) ? "" : " ") + title); - if (isNotBlank(firstName)) - result.append((isBlank(result) ? "" : " ") + firstName); - if (isNotBlank(lastName)) - result.append((isBlank(result) ? "" : " ") + lastName); - - if (isNotBlank(firm)) { - return isBlank(result) ? firm : firm + ", " + result; - } - return result.toString(); - } - - private String toName(final String salut, final String title, final String firstName, final String lastName) { - return toCaption(null, salut, title, firstName, lastName); - } -} diff --git a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java deleted file mode 100644 index 49ecc5f8..00000000 --- a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java +++ /dev/null @@ -1,74 +0,0 @@ -package net.hostsharing.hsadminng.hs.migration; - -import net.hostsharing.hsadminng.context.Context; -import net.hostsharing.hsadminng.rbac.test.JpaAttempt; -import org.junit.jupiter.api.*; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ActiveProfiles; - -import java.io.File; - -/* - * This 'test' includes the complete legacy 'office' data import. - * - * There is no code in 'main' because the import is not needed a normal runtime. - * There is some test data in Java resources to verify the data conversion. - * For a real import a main method will be added later - * which reads CSV files from the file system. - * - * When run on a Hostsharing database, it needs the following settings (hsh99_... just examples). - * - * In a real Hostsharing environment, these are created via (the old) hsadmin: - - CREATE USER hsh99_admin WITH PASSWORD 'password'; - CREATE DATABASE hsh99_hsadminng ENCODING 'UTF8' TEMPLATE template0; - REVOKE ALL ON DATABASE hsh99_hsadminng FROM public; -- why does hsadmin do that? - ALTER DATABASE hsh99_hsadminng OWNER TO hsh99_admin; - - CREATE USER hsh99_restricted WITH PASSWORD 'password'; - - \c hsh99_hsadminng - - GRANT ALL PRIVILEGES ON SCHEMA public to hsh99_admin; - - * Additionally, we need these settings (because the Hostsharing DB-Admin has no CREATE right): - - CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; - - -- maybe something like that is needed for the 2nd user - -- GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to hsh99_restricted; - - * Then copy the file .tc-environment to a file named .environment (excluded from git) and fill in your specific values. - - * To finally import the office data, run: - * - * gw-importOfficeTables # comes from .aliases file and uses .environment - */ -@Tag("importOfficeData") -@DataJpaTest(properties = { - "spring.datasource.url=${HSADMINNG_POSTGRES_JDBC_URL:jdbc:tc:postgresql:15.5-bookworm:///importOfficeDataTC}", - "spring.datasource.username=${HSADMINNG_POSTGRES_ADMIN_USERNAME:ADMIN}", - "spring.datasource.password=${HSADMINNG_POSTGRES_ADMIN_PASSWORD:password}", - "hsadminng.superuser=${HSADMINNG_SUPERUSER:import-superuser@hostsharing.net}", - "spring.liquibase.contexts=only-office,without-test-data" -}) -@ActiveProfiles("without-test-data") -@DirtiesContext -@Import({ Context.class, JpaAttempt.class }) -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -@ExtendWith(OrderedDependedTestsExtension.class) -public class ImportOfficeData extends BaseOfficeDataImport { - - @Value("${spring.datasource.url}") - private String jdbcUrl; - - @Test - @Order(9999) - public void dumpOfficeData() { - PostgresTestcontainer.dump(jdbcUrl, new File("build/db/released-only-office-schema-with-import-test-data.sql")); - } -}