hosting-asset-data-migration (#79)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: #79 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
parent
c191af2ea1
commit
4d27a98c9a
32
.aliases
32
.aliases
@ -1,4 +1,4 @@
|
||||
# For using the alias import-office-tables,
|
||||
# For using the alias gw-importOfficeData or gw-importHostingAssets,
|
||||
# copy the file .tc-environment to .environment (ignored by git)
|
||||
# and amend them according to your external DB.
|
||||
|
||||
@ -42,19 +42,29 @@ postgresAutodoc () {
|
||||
}
|
||||
alias postgres-autodoc=postgresAutodoc
|
||||
|
||||
function importOfficeData() {
|
||||
source .tc-environment
|
||||
|
||||
if [ -f .environment ]; then
|
||||
source .environment
|
||||
fi
|
||||
function importLegacyData() {
|
||||
export target=$1
|
||||
if [ -z "$target" ]; then
|
||||
echo "importLegacyData needs target argument, but none was given" >&2
|
||||
else
|
||||
source .tc-environment
|
||||
|
||||
echo "using environment (with ending ';' for use in IntelliJ IDEA):"
|
||||
set | grep ^HSADMINNG_ | sed 's/$/;/'
|
||||
if [ -f .environment ]; then
|
||||
source .environment
|
||||
fi
|
||||
|
||||
./gradlew importOfficeData --rerun
|
||||
echo "using environment (with ending ';' for use in IntelliJ IDEA):"
|
||||
echo "--- BEGIN: ---"
|
||||
set | grep ^HSADMINNG_ | sed 's/$/;/'
|
||||
echo "---- END. ----"
|
||||
echo
|
||||
|
||||
echo ./gradlew $target --rerun
|
||||
./gradlew $target --rerun
|
||||
fi
|
||||
}
|
||||
alias gw-importOfficeData=importOfficeData
|
||||
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'
|
||||
alias podman-stop='systemctl --user disable --now podman.socket && systemctl --user status podman.socket && ls -la /run/user/$UID/podman/podman.sock'
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -136,4 +136,9 @@ Desktop.ini
|
||||
# ESLint
|
||||
######################
|
||||
.eslintcache
|
||||
|
||||
######################
|
||||
# Project Related
|
||||
######################
|
||||
/.environment*
|
||||
/src/test/resources/migration-prod/*
|
||||
|
12
build.gradle
12
build.gradle
@ -318,7 +318,7 @@ jacocoTestCoverageVerification {
|
||||
|
||||
tasks.register('importOfficeData', Test) {
|
||||
useJUnitPlatform {
|
||||
includeTags 'import'
|
||||
includeTags 'importOfficeData'
|
||||
}
|
||||
|
||||
group 'verification'
|
||||
@ -327,6 +327,16 @@ tasks.register('importOfficeData', Test) {
|
||||
mustRunAfter spotlessJava
|
||||
}
|
||||
|
||||
tasks.register('importHostingAssets', Test) {
|
||||
useJUnitPlatform {
|
||||
includeTags 'importHostingAssets'
|
||||
}
|
||||
|
||||
group 'verification'
|
||||
description 'run the import jobs as tests'
|
||||
|
||||
mustRunAfter spotlessJava
|
||||
}
|
||||
|
||||
// pitest mutation testing
|
||||
pitest {
|
||||
|
@ -18,7 +18,7 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
|
||||
// a partial HsOfficeDebitorEntity to reduce the number of SQL queries to load the entity
|
||||
@Entity
|
||||
@Table(name = "hs_booking_debitor_rv")
|
||||
@Table(name = "hs_booking_debitor_xv")
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
|
@ -184,7 +184,9 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject, Propertie
|
||||
}
|
||||
|
||||
public HsBookingProjectEntity getRelatedProject() {
|
||||
return project != null ? project : parentItem.getRelatedProject();
|
||||
return project != null ? project
|
||||
: parentItem != null ? parentItem.getRelatedProject()
|
||||
: null; // can be the case for technical assets like IP-numbers
|
||||
}
|
||||
|
||||
public static RbacView rbac() {
|
||||
|
@ -22,6 +22,10 @@ public class HsBookingItemEntityValidator extends HsEntityValidator<HsBookingIte
|
||||
|
||||
@Override
|
||||
public List<String> validateEntity(final HsBookingItemEntity bookingItem) {
|
||||
// TODO.impl: HsBookingItemType could do this similar to HsHostingAssetType
|
||||
if ( bookingItem.getParentItem() == null && bookingItem.getProject() == null) {
|
||||
return List.of(bookingItem + ".'parentItem' or .'project' expected to be set, but both are null");
|
||||
}
|
||||
return enrich(prefix(bookingItem.toShortString(), "resources"), super.validateProperties(bookingItem));
|
||||
}
|
||||
|
||||
|
@ -11,11 +11,12 @@ class HsCloudServerBookingItemValidator extends HsBookingItemEntityValidator {
|
||||
// @formatter:off
|
||||
booleanProperty("active") .withDefault(true),
|
||||
|
||||
integerProperty("CPUs") .min( 1) .max( 32) .required(),
|
||||
integerProperty("RAM").unit("GB") .min( 1) .max( 128) .required(),
|
||||
integerProperty("SSD").unit("GB") .min( 0) .max( 1000) .step(25).required(), // (1)
|
||||
integerProperty("HDD").unit("GB") .min( 0) .max( 4000) .step(250).withDefault(0),
|
||||
integerProperty("Traffic").unit("GB") .min(250) .max(10000) .step(250).required(),
|
||||
integerProperty("CPU") .min( 1) .max( 32) .required(),
|
||||
integerProperty("RAM").unit("GB") .min( 1) .max( 8192) .required(),
|
||||
integerProperty("SSD").unit("GB") .min( 25) .max( 1000) .step(25).requiresAtLeastOneOf("SDD", "HDD"),
|
||||
integerProperty("HDD").unit("GB") .min(250) .max( 4000) .step(250).requiresAtLeastOneOf("SSD", "HDD"),
|
||||
integerProperty("Traffic").unit("GB") .min(250) .max(10000) .step(250).requiresAtMaxOneOf("Bandwidth", "Traffic"),
|
||||
integerProperty("Bandwidth").unit("GB") .min(250) .max(10000) .step(250).requiresAtMaxOneOf("Bandwidth", "Traffic"), // TODO.spec
|
||||
|
||||
enumerationProperty("SLA-Infrastructure").values("BASIC", "EXT8H", "EXT4H", "EXT2H").optional()
|
||||
// @formatter:on
|
||||
|
@ -10,11 +10,12 @@ class HsManagedServerBookingItemValidator extends HsBookingItemEntityValidator {
|
||||
|
||||
HsManagedServerBookingItemValidator() {
|
||||
super(
|
||||
integerProperty("CPUs").min(1).max(32).required(),
|
||||
integerProperty("CPU").min(1).max(32).required(),
|
||||
integerProperty("RAM").unit("GB").min(1).max(128).required(),
|
||||
integerProperty("SSD").unit("GB").min(25).max(1000).step(25).required().asTotalLimit().withThreshold(200),
|
||||
integerProperty("HDD").unit("GB").min(0).max(4000).step(250).withDefault(0).asTotalLimit().withThreshold(200),
|
||||
integerProperty("Traffic").unit("GB").min(250).max(10000).step(250).required().asTotalLimit().withThreshold(200),
|
||||
integerProperty("SSD").unit("GB").min(25).max(2000).step(25).requiresAtLeastOneOf("SSD", "HDD").asTotalLimit().withThreshold(200),
|
||||
integerProperty("HDD").unit("GB").min(250).max(10000).step(250).requiresAtLeastOneOf("SSD", "HDD").asTotalLimit().withThreshold(200),
|
||||
integerProperty("Traffic").unit("GB").min(250).max(64000).step(250).requiresAtMaxOneOf("Bandwidth", "Traffic").asTotalLimit().withThreshold(200),
|
||||
integerProperty("Bandwidth").unit("GB").min(250).max(64000).step(250).requiresAtMaxOneOf("Bandwidth", "Traffic").asTotalLimit().withThreshold(200), // TODO.spec
|
||||
enumerationProperty("SLA-Platform").values("BASIC", "EXT8H", "EXT4H", "EXT2H").withDefault("BASIC"),
|
||||
booleanProperty("SLA-EMail").falseIf("SLA-Platform", "BASIC").withDefault(false),
|
||||
booleanProperty("SLA-Maria").falseIf("SLA-Platform", "BASIC").optional(),
|
||||
|
@ -23,16 +23,17 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
|
||||
|
||||
public HsManagedWebspaceBookingItemValidator() {
|
||||
super(
|
||||
integerProperty("SSD").unit("GB").min(1).max(100).step(1).required(),
|
||||
integerProperty("HDD").unit("GB").min(0).max(250).step(10).optional(),
|
||||
integerProperty("Traffic").unit("GB").min(10).max(1000).step(10).required(),
|
||||
integerProperty("SSD").unit("GB").min(1).max(2000).step(1).required(),
|
||||
integerProperty("HDD").unit("GB").min(0).max(10000).step(10).optional(),
|
||||
integerProperty("Traffic").unit("GB").min(10).max(64000).step(10).requiresAtMaxOneOf("Bandwidth", "Traffic"),
|
||||
integerProperty("Bandwidth").unit("GB").min(10).max(1000).step(10).requiresAtMaxOneOf("Bandwidth", "Traffic"), // TODO.spec
|
||||
integerProperty("Multi").min(1).max(100).step(1).withDefault(1)
|
||||
.eachComprising( 25, unixUsers())
|
||||
.eachComprising( 5, databaseUsers())
|
||||
.eachComprising( 5, databases())
|
||||
.eachComprising(250, eMailAddresses()),
|
||||
integerProperty("Daemons").min(0).max(10).withDefault(0),
|
||||
booleanProperty("Online Office Server").optional(),
|
||||
integerProperty("Daemons").min(0).max(16).withDefault(0),
|
||||
booleanProperty("Online Office Server").optional(), // TODO.impl: shorten to "Office"
|
||||
enumerationProperty("SLA-Platform").values("BASIC", "EXT24H").withDefault("BASIC")
|
||||
);
|
||||
}
|
||||
|
@ -7,15 +7,16 @@ class HsPrivateCloudBookingItemValidator extends HsBookingItemEntityValidator {
|
||||
HsPrivateCloudBookingItemValidator() {
|
||||
super(
|
||||
// @formatter:off
|
||||
integerProperty("CPUs") .min( 1).max( 128).required().asTotalLimit(),
|
||||
integerProperty("CPU") .min( 1).max( 128).required().asTotalLimit(),
|
||||
integerProperty("RAM").unit("GB") .min( 1).max( 512).required().asTotalLimit(),
|
||||
integerProperty("SSD").unit("GB") .min( 25).max( 4000).step(25).required().asTotalLimit(),
|
||||
integerProperty("HDD").unit("GB") .min( 0).max(16000).step(250).withDefault(0).asTotalLimit(),
|
||||
integerProperty("Traffic").unit("GB") .min(250).max(40000).step(250).required().asTotalLimit(),
|
||||
integerProperty("SSD").unit("GB") .min( 25).max( 4000).step(25).requiresAtLeastOneOf("SSD", "HDD").asTotalLimit(),
|
||||
integerProperty("HDD").unit("GB") .min(250).max(16000).step(250).requiresAtLeastOneOf("SSD", "HDD").asTotalLimit(),
|
||||
integerProperty("Traffic").unit("GB") .min(250).max(64000).step(250).requiresAtMaxOneOf("Bandwidth", "Traffic").asTotalLimit(),
|
||||
integerProperty("Bandwidth").unit("GB") .min(250).max(64000).step(250).requiresAtMaxOneOf("Bandwidth", "Traffic").asTotalLimit(), // TODO.spec
|
||||
|
||||
// Alternatively we could specify it similarly to "Multi" option but exclusively counting:
|
||||
// integerProperty("Resource-Points") .min(4).max(100).required()
|
||||
// .each("CPUs").countsAs(64)
|
||||
// .each("CPU").countsAs(64)
|
||||
// .each("RAM").countsAs(64)
|
||||
// .each("SSD").countsAs(18)
|
||||
// .each("HDD").countsAs(2)
|
||||
|
@ -8,6 +8,7 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
|
||||
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
||||
import net.hostsharing.hsadminng.hs.validation.PropertiesProvider;
|
||||
import net.hostsharing.hsadminng.mapper.PatchableMapWrapper;
|
||||
@ -38,6 +39,7 @@ import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
@ -108,7 +110,7 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Properti
|
||||
private HsOfficeContactEntity alarmContact;
|
||||
|
||||
@OneToMany(cascade = CascadeType.REFRESH, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name="parentassetuuid", referencedColumnName="uuid")
|
||||
@JoinColumn(name = "parentassetuuid", referencedColumnName = "uuid")
|
||||
private List<HsHostingAssetEntity> subHostingAssets;
|
||||
|
||||
@Column(name = "identifier")
|
||||
@ -134,12 +136,20 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Properti
|
||||
this.isLoaded = true;
|
||||
}
|
||||
|
||||
public HsBookingProjectEntity getRelatedProject() {
|
||||
return Optional.ofNullable(bookingItem)
|
||||
.map(HsBookingItemEntity::getRelatedProject)
|
||||
.orElseGet(() -> Optional.ofNullable(parentAsset)
|
||||
.map(HsHostingAssetEntity::getRelatedProject)
|
||||
.orElse(null));
|
||||
}
|
||||
|
||||
public PatchableMapWrapper<Object> getConfig() {
|
||||
return PatchableMapWrapper.of(configWrapper, (newWrapper) -> {configWrapper = newWrapper; }, config );
|
||||
return PatchableMapWrapper.of(configWrapper, (newWrapper) -> {configWrapper = newWrapper;}, config);
|
||||
}
|
||||
|
||||
public void putConfig(Map<String, Object> newConfig) {
|
||||
PatchableMapWrapper.of(configWrapper, (newWrapper) -> {configWrapper = newWrapper; }, config).assign(newConfig);
|
||||
PatchableMapWrapper.of(configWrapper, (newWrapper) -> {configWrapper = newWrapper;}, config).assign(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -150,20 +160,19 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Properti
|
||||
@Override
|
||||
public Object getContextValue(final String propName) {
|
||||
final var v = config.get(propName);
|
||||
if (v!= null) {
|
||||
if (v != null) {
|
||||
return v;
|
||||
}
|
||||
|
||||
if (bookingItem!=null) {
|
||||
if (bookingItem != null) {
|
||||
return bookingItem.getResources().get(propName);
|
||||
}
|
||||
if (parentAsset!=null && parentAsset.getBookingItem()!=null) {
|
||||
if (parentAsset != null && parentAsset.getBookingItem() != null) {
|
||||
return parentAsset.getBookingItem().getResources().get(propName);
|
||||
}
|
||||
return emptyMap();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return stringify.apply(this);
|
||||
@ -182,9 +191,9 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Properti
|
||||
.toRole(GLOBAL, ADMIN).grantPermission(INSERT) // TODO.impl: Why is this necessary to insert test data?
|
||||
|
||||
.importEntityAlias("bookingItem", HsBookingItemEntity.class, usingDefaultCase(),
|
||||
dependsOnColumn("bookingItemUuid"),
|
||||
directlyFetchedByDependsOnColumn(),
|
||||
NULLABLE)
|
||||
dependsOnColumn("bookingItemUuid"),
|
||||
directlyFetchedByDependsOnColumn(),
|
||||
NULLABLE)
|
||||
|
||||
.importEntityAlias("parentAsset", HsHostingAssetEntity.class, usingDefaultCase(),
|
||||
dependsOnColumn("parentAssetUuid"),
|
||||
@ -202,7 +211,8 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Properti
|
||||
directlyFetchedByDependsOnColumn(),
|
||||
NULLABLE)
|
||||
|
||||
.switchOnColumn("type",
|
||||
.switchOnColumn(
|
||||
"type",
|
||||
inCaseOf("DOMAIN_SETUP", then -> {
|
||||
then.toRole(GLOBAL, GUEST).grantPermission(INSERT);
|
||||
})
|
||||
@ -231,7 +241,14 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Properti
|
||||
with.permission(SELECT);
|
||||
})
|
||||
|
||||
.limitDiagramTo("asset", "bookingItem", "bookingItem.debitorRel", "parentAsset", "assignedToAsset", "alarmContact", "global");
|
||||
.limitDiagramTo(
|
||||
"asset",
|
||||
"bookingItem",
|
||||
"bookingItem.debitorRel",
|
||||
"parentAsset",
|
||||
"assignedToAsset",
|
||||
"alarmContact",
|
||||
"global");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
@ -18,7 +18,7 @@ class HsManagedWebspaceHostingAssetValidator extends HostingAssetEntityValidator
|
||||
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
||||
final var prefixPattern =
|
||||
!assetEntity.isLoaded()
|
||||
? assetEntity.getParentAsset().getBookingItem().getProject().getDebitor().getDefaultPrefix()
|
||||
? assetEntity.getRelatedProject().getDebitor().getDefaultPrefix()
|
||||
: "[a-z][a-z0-9][a-z0-9]";
|
||||
return Pattern.compile("^" + prefixPattern + "[0-9][0-9]$");
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ public class HsOfficeMembershipEntity implements RbacObject, Stringifyable {
|
||||
|
||||
private static Stringify<HsOfficeMembershipEntity> stringify = stringify(HsOfficeMembershipEntity.class)
|
||||
.withProp(e -> MEMBER_NUMBER_TAG + e.getMemberNumber())
|
||||
.withProp(e -> e.getPartner().toShortString())
|
||||
.withProp(HsOfficeMembershipEntity::getPartner)
|
||||
.withProp(e -> e.getValidity().asString())
|
||||
.withProp(HsOfficeMembershipEntity::getStatus)
|
||||
.quotedValues(false);
|
||||
|
@ -13,10 +13,12 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
@ -30,7 +32,7 @@ import static org.apache.commons.lang3.ObjectUtils.isArray;
|
||||
public abstract class ValidatableProperty<P extends ValidatableProperty<?, ?>, T> {
|
||||
|
||||
protected static final String[] KEY_ORDER_HEAD = Array.of("propertyName");
|
||||
protected static final String[] KEY_ORDER_TAIL = Array.of("required", "defaultValue", "readOnly", "writeOnly", "computed", "isTotalsValidator", "thresholdPercentage");
|
||||
protected static final String[] KEY_ORDER_TAIL = Array.of("required", "requiresAtLeastOneOf", "requiresAtMaxOneOf", "defaultValue", "readOnly", "writeOnly", "computed", "isTotalsValidator", "thresholdPercentage");
|
||||
protected static final String[] KEY_ORDER = Array.join(KEY_ORDER_HEAD, KEY_ORDER_TAIL);
|
||||
|
||||
final Class<T> type;
|
||||
@ -40,6 +42,8 @@ public abstract class ValidatableProperty<P extends ValidatableProperty<?, ?>, T
|
||||
private final String[] keyOrder;
|
||||
|
||||
private Boolean required;
|
||||
private Set<String> requiresAtLeastOneOf;
|
||||
private Set<String> requiresAtMaxOneOf;
|
||||
private T defaultValue;
|
||||
|
||||
@JsonIgnore
|
||||
@ -100,9 +104,19 @@ protected void setDeferredInit(final Function<ValidatableProperty<?, ?>[], T[]>
|
||||
return self();
|
||||
}
|
||||
|
||||
public ValidatableProperty<P, T> optional() {
|
||||
public P optional() {
|
||||
required = FALSE;
|
||||
return this;
|
||||
return self();
|
||||
}
|
||||
|
||||
public P requiresAtLeastOneOf(final String... propNames) {
|
||||
requiresAtLeastOneOf = new LinkedHashSet<>(List.of(propNames));
|
||||
return self();
|
||||
}
|
||||
|
||||
public P requiresAtMaxOneOf(final String... propNames) {
|
||||
requiresAtMaxOneOf = new LinkedHashSet<>(List.of(propNames));
|
||||
return self();
|
||||
}
|
||||
|
||||
public P withDefault(final T value) {
|
||||
@ -172,28 +186,57 @@ protected void setDeferredInit(final Function<ValidatableProperty<?, ?>[], T[]>
|
||||
final var result = new ArrayList<String>();
|
||||
final var props = propsProvider.directProps();
|
||||
final var propValue = props.get(propertyName);
|
||||
|
||||
if (propValue == null) {
|
||||
if (required) {
|
||||
if (required == TRUE) {
|
||||
result.add(propertyName + "' is required but missing");
|
||||
}
|
||||
validateRequiresAtLeastOneOf(result, propsProvider);
|
||||
}
|
||||
if (propValue != null){
|
||||
validateRequiresAtMaxOneOf(result, propsProvider);
|
||||
|
||||
if ( type.isInstance(propValue)) {
|
||||
//noinspection unchecked
|
||||
validate(result, (T) propValue, propsProvider);
|
||||
} else {
|
||||
result.add(propertyName + "' is expected to be of type " + type.getSimpleName() + ", " +
|
||||
"but is of type " + propValue.getClass().getSimpleName() + "");
|
||||
"but is of type " + propValue.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void validateRequiresAtLeastOneOf(final ArrayList<String> result, final PropertiesProvider propsProvider) {
|
||||
if (requiresAtLeastOneOf != null ) {
|
||||
final var allPropNames = propsProvider.directProps().keySet();
|
||||
final var entriesWithValue = allPropNames.stream()
|
||||
.filter(name -> requiresAtLeastOneOf.contains(name))
|
||||
.count();
|
||||
if (entriesWithValue == 0) {
|
||||
result.add(propertyName + "' is required once in group " + requiresAtLeastOneOf + " but missing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRequiresAtMaxOneOf(final ArrayList<String> result, final PropertiesProvider propsProvider) {
|
||||
if (requiresAtMaxOneOf != null) {
|
||||
final var allPropNames = propsProvider.directProps().keySet();
|
||||
final var entriesWithValue = allPropNames.stream()
|
||||
.filter(name -> requiresAtMaxOneOf.contains(name))
|
||||
.count();
|
||||
if (entriesWithValue > 1) {
|
||||
result.add(propertyName + "' is required at max once in group " + requiresAtMaxOneOf
|
||||
+ " but multiple properties are set");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void validate(final List<String> result, final T propValue, final PropertiesProvider propProvider);
|
||||
|
||||
public void verifyConsistency(final Map.Entry<? extends Enum<?>, ?> typeDef) {
|
||||
if (required == null ) {
|
||||
throw new IllegalStateException(typeDef.getKey() + "[" + propertyName + "] not fully initialized, please call either .required() or .optional()" );
|
||||
if (required == null && requiresAtLeastOneOf == null && requiresAtMaxOneOf == null) {
|
||||
throw new IllegalStateException(typeDef.getKey() + "[" + propertyName + "] not fully initialized, please call either .required(), .optional(), .withDefault(...), .requiresAtLeastOneOf(...) or .requiresAtMaxOneOf(...)" );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,12 @@
|
||||
--changeset hs-booking-debitor-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
|
||||
create view hs_booking_debitor_rv as
|
||||
create view hs_booking_debitor_xv as
|
||||
select debitor.uuid,
|
||||
debitor.version,
|
||||
(partner.partnerNumber::varchar || debitor.debitorNumberSuffix)::numeric as debitorNumber,
|
||||
debitor.defaultPrefix
|
||||
from hs_office_debitor_rv debitor
|
||||
from hs_office_debitor debitor
|
||||
-- RBAC for debitor is sufficient, for faster access we are bypassing RBAC for the join tables
|
||||
join hs_office_relation debitorRel on debitor.debitorReluUid=debitorRel.uuid
|
||||
join hs_office_relation partnerRel on partnerRel.holderUuid=debitorRel.anchorUuid
|
||||
|
@ -33,11 +33,11 @@ begin
|
||||
managedServerUuid := uuid_generate_v4();
|
||||
insert
|
||||
into hs_booking_item (uuid, projectuuid, type, parentitemuuid, caption, validity, resources)
|
||||
values (privateCloudUuid, relatedProject.uuid, 'PRIVATE_CLOUD', null, 'some PrivateCloud', daterange('20240401', null, '[]'), '{ "CPUs": 10, "RAM": 32, "SSD": 4000, "HDD": 10000, "Traffic": 2000 }'::jsonb),
|
||||
(uuid_generate_v4(), null, 'MANAGED_SERVER', privateCloudUuid, 'some ManagedServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 2, "RAM": 4, "SSD": 500, "Traffic": 500 }'::jsonb),
|
||||
(uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'test CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 2, "RAM": 4, "SSD": 750, "Traffic": 500 }'::jsonb),
|
||||
(uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'prod CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 4, "RAM": 16, "SSD": 1000, "Traffic": 500 }'::jsonb),
|
||||
(managedServerUuid, relatedProject.uuid, 'MANAGED_SERVER', null, 'separate ManagedServer', daterange('20221001', null, '[]'), '{ "CPUs": 2, "RAM": 8, "SSD": 500, "Traffic": 500 }'::jsonb),
|
||||
values (privateCloudUuid, relatedProject.uuid, 'PRIVATE_CLOUD', null, 'some PrivateCloud', daterange('20240401', null, '[]'), '{ "CPU": 10, "RAM": 32, "SSD": 4000, "HDD": 10000, "Traffic": 2000 }'::jsonb),
|
||||
(uuid_generate_v4(), null, 'MANAGED_SERVER', privateCloudUuid, 'some ManagedServer', daterange('20230115', '20240415', '[)'), '{ "CPU": 2, "RAM": 4, "SSD": 500, "Traffic": 500 }'::jsonb),
|
||||
(uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'test CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPU": 2, "RAM": 4, "SSD": 750, "Traffic": 500 }'::jsonb),
|
||||
(uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'prod CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPU": 4, "RAM": 16, "SSD": 1000, "Traffic": 500 }'::jsonb),
|
||||
(managedServerUuid, relatedProject.uuid, 'MANAGED_SERVER', null, 'separate ManagedServer', daterange('20221001', null, '[]'), '{ "CPU": 2, "RAM": 8, "SSD": 500, "Traffic": 500 }'::jsonb),
|
||||
(uuid_generate_v4(), null, 'MANAGED_WEBSPACE', managedServerUuid, 'some ManagedWebspace', daterange('20221001', null, '[]'), '{ "SSD": 50, "Traffic": 20, "Daemons": 2, "Multi": 4 }'::jsonb),
|
||||
(uuid_generate_v4(), relatedProject.uuid, 'MANAGED_WEBSPACE', null, 'separate ManagedWebspace', daterange('20221001', null, '[]'), '{ "SSD": 100, "Traffic": 50, "Daemons": 0, "Multi": 1 }'::jsonb);
|
||||
end; $$;
|
||||
|
@ -42,7 +42,7 @@ create table if not exists hs_hosting_asset
|
||||
alarmContactUuid uuid null references hs_office_contact(uuid) initially deferred,
|
||||
|
||||
constraint chk_hs_hosting_asset_has_booking_item_or_parent_asset
|
||||
check (bookingItemUuid is not null or parentAssetUuid is not null or type='DOMAIN_SETUP')
|
||||
check (bookingItemUuid is not null or parentAssetUuid is not null or type in ('DOMAIN_SETUP', 'IPV4_NUMBER', 'IPV6_NUMBER'))
|
||||
);
|
||||
--//
|
||||
|
||||
|
@ -51,7 +51,7 @@ public class ArchitectureTest {
|
||||
"..hs.office.coopshares",
|
||||
"..hs.office.debitor",
|
||||
"..hs.office.membership",
|
||||
"..hs.office.migration",
|
||||
"..hs.migration",
|
||||
"..hs.office.partner",
|
||||
"..hs.office.person",
|
||||
"..hs.office.relation",
|
||||
@ -156,6 +156,7 @@ public class ArchitectureTest {
|
||||
"..hs.office.(*)..",
|
||||
"..hs.booking.(*)..",
|
||||
"..hs.hosting.(*)..",
|
||||
"..hs.migration",
|
||||
"..rbac.rbacgrant" // TODO.test: just because of RbacGrantsDiagramServiceIntegrationTest
|
||||
);
|
||||
|
||||
@ -167,7 +168,8 @@ public class ArchitectureTest {
|
||||
.resideInAnyPackage(
|
||||
"..hs.booking.(*)..",
|
||||
"..hs.hosting.(*)..",
|
||||
"..hs.validation" // TODO.impl: Some Validators need to be refactored to booking package.
|
||||
"..hs.validation", // TODO.impl: Some Validators need to be refactored to booking package.
|
||||
"..hs.migration.."
|
||||
);
|
||||
|
||||
@ArchTest
|
||||
@ -177,7 +179,8 @@ public class ArchitectureTest {
|
||||
.should().onlyBeAccessed().byClassesThat()
|
||||
.resideInAnyPackage(
|
||||
"..hs.hosting.(*)..",
|
||||
"..hs.booking.(*).." // TODO.impl: fix this cyclic dependency
|
||||
"..hs.booking.(*)..", // TODO.impl: fix this cyclic dependency
|
||||
"..hs.migration.."
|
||||
);
|
||||
|
||||
@ArchTest
|
||||
@ -189,7 +192,7 @@ public class ArchitectureTest {
|
||||
"..hs.office.bankaccount..",
|
||||
"..hs.office.sepamandate..",
|
||||
"..hs.office.debitor..",
|
||||
"..hs.office.migration..");
|
||||
"..hs.migration..");
|
||||
|
||||
@ArchTest
|
||||
@SuppressWarnings("unused")
|
||||
@ -199,7 +202,7 @@ public class ArchitectureTest {
|
||||
.resideInAnyPackage(
|
||||
"..hs.office.sepamandate..",
|
||||
"..hs.office.debitor..",
|
||||
"..hs.office.migration..");
|
||||
"..hs.migration..");
|
||||
|
||||
@ArchTest
|
||||
@SuppressWarnings("unused")
|
||||
@ -212,7 +215,7 @@ public class ArchitectureTest {
|
||||
"..hs.office.partner..",
|
||||
"..hs.office.debitor..",
|
||||
"..hs.office.membership..",
|
||||
"..hs.office.migration..",
|
||||
"..hs.migration..",
|
||||
"..hs.hosting.asset.."
|
||||
);
|
||||
|
||||
@ -227,7 +230,7 @@ public class ArchitectureTest {
|
||||
"..hs.office.partner..",
|
||||
"..hs.office.debitor..",
|
||||
"..hs.office.membership..",
|
||||
"..hs.office.migration..")
|
||||
"..hs.migration..")
|
||||
.orShould().haveNameNotMatching(".*Test$");
|
||||
|
||||
|
||||
@ -239,7 +242,7 @@ public class ArchitectureTest {
|
||||
.resideInAnyPackage(
|
||||
"..hs.office.relation..",
|
||||
"..hs.office.partner..",
|
||||
"..hs.office.migration..")
|
||||
"..hs.migration..")
|
||||
.orShould().haveNameNotMatching(".*Test$");
|
||||
|
||||
@ArchTest
|
||||
@ -251,7 +254,7 @@ public class ArchitectureTest {
|
||||
"..hs.office.partner..",
|
||||
"..hs.office.debitor..",
|
||||
"..hs.office.membership..",
|
||||
"..hs.office.migration..")
|
||||
"..hs.migration..")
|
||||
.orShould().haveNameNotMatching(".*Test$");
|
||||
|
||||
@ArchTest
|
||||
@ -263,7 +266,7 @@ public class ArchitectureTest {
|
||||
"..hs.office.membership..",
|
||||
"..hs.office.coopassets..",
|
||||
"..hs.office.coopshares..",
|
||||
"..hs.office.migration..");
|
||||
"..hs.migration..");
|
||||
|
||||
@ArchTest
|
||||
@SuppressWarnings("unused")
|
||||
@ -272,7 +275,7 @@ public class ArchitectureTest {
|
||||
.should().onlyBeAccessed().byClassesThat()
|
||||
.resideInAnyPackage(
|
||||
"..hs.office.coopassets..",
|
||||
"..hs.office.migration..");
|
||||
"..hs.migration..");
|
||||
|
||||
@ArchTest
|
||||
@SuppressWarnings("unused")
|
||||
@ -281,14 +284,14 @@ public class ArchitectureTest {
|
||||
.should().onlyBeAccessed().byClassesThat()
|
||||
.resideInAnyPackage(
|
||||
"..hs.office.coopshares..",
|
||||
"..hs.office.migration..");
|
||||
"..hs.migration..");
|
||||
|
||||
@ArchTest
|
||||
@SuppressWarnings("unused")
|
||||
public static final ArchRule hsOfficeMigrationPackageRule = classes()
|
||||
.that().resideInAPackage("..hs.office.migration..")
|
||||
.that().resideInAPackage("..hs.migration..")
|
||||
.should().onlyBeAccessed().byClassesThat()
|
||||
.resideInAnyPackage("..hs.office.migration..");
|
||||
.resideInAnyPackage("..hs.migration..");
|
||||
|
||||
@ArchTest
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -101,7 +101,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"resources": {
|
||||
"RAM": 8,
|
||||
"SSD": 500,
|
||||
"CPUs": 2,
|
||||
"CPU": 2,
|
||||
"Traffic": 500
|
||||
}
|
||||
},
|
||||
@ -114,7 +114,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"HDD": 10000,
|
||||
"RAM": 32,
|
||||
"SSD": 4000,
|
||||
"CPUs": 10,
|
||||
"CPU": 10,
|
||||
"Traffic": 2000
|
||||
}
|
||||
}
|
||||
@ -148,7 +148,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"type": "MANAGED_SERVER",
|
||||
"caption": "some new booking",
|
||||
"validTo": "{validTo}",
|
||||
"resources": { "CPUs": 12, "RAM": 4, "SSD": 100, "Traffic": 250 }
|
||||
"resources": { "CPU": 12, "RAM": 4, "SSD": 100, "Traffic": 250 }
|
||||
}
|
||||
"""
|
||||
.replace("{projectUuid}", givenProject.getUuid().toString())
|
||||
@ -166,7 +166,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"caption": "some new booking",
|
||||
"validFrom": "{today}",
|
||||
"validTo": "{todayPlus1Month}",
|
||||
"resources": { "CPUs": 12, "SSD": 100, "Traffic": 250 }
|
||||
"resources": { "CPU": 12, "SSD": 100, "Traffic": 250 }
|
||||
}
|
||||
"""
|
||||
.replace("{today}", LocalDate.now().toString())
|
||||
@ -267,7 +267,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"resources": {
|
||||
"RAM": 8,
|
||||
"SSD": 500,
|
||||
"CPUs": 2,
|
||||
"CPU": 2,
|
||||
"Traffic": 500
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ class HsBookingItemControllerRestTest {
|
||||
"caption": "some new booking",
|
||||
"validTo": "{validTo}",
|
||||
"garbage": "should not be accepted",
|
||||
"resources": { "CPUs": 12, "RAM": 4, "SSD": 100, "Traffic": 250 }
|
||||
"resources": { "CPU": 12, "RAM": 4, "SSD": 100, "Traffic": 250 }
|
||||
}
|
||||
"""
|
||||
.replace("{projectUuid}", givenProjectUuid.toString())
|
||||
@ -108,7 +108,7 @@ class HsBookingItemControllerRestTest {
|
||||
"caption": "some new booking",
|
||||
"validFrom": "{today}",
|
||||
"validTo": "{todayPlus1Month}",
|
||||
"resources": { "CPUs": 12, "SSD": 100, "Traffic": 250 }
|
||||
"resources": { "CPU": 12, "SSD": 100, "Traffic": 250 }
|
||||
}
|
||||
"""
|
||||
.replace("{today}", LocalDate.now().toString())
|
||||
@ -141,7 +141,7 @@ class HsBookingItemControllerRestTest {
|
||||
"type": "MANAGED_SERVER",
|
||||
"caption": "some new booking",
|
||||
"validFrom": "{validFrom}",
|
||||
"resources": { "CPUs": 12, "RAM": 4, "SSD": 100, "Traffic": 250 }
|
||||
"resources": { "CPU": 12, "RAM": 4, "SSD": 100, "Traffic": 250 }
|
||||
}
|
||||
"""
|
||||
.replace("{projectUuid}", givenProjectUuid.toString())
|
||||
@ -159,7 +159,7 @@ class HsBookingItemControllerRestTest {
|
||||
"caption": "some new booking",
|
||||
"validFrom": "{today}",
|
||||
"validTo": null,
|
||||
"resources": { "CPUs": 12, "SSD": 100, "Traffic": 250 }
|
||||
"resources": { "CPU": 12, "SSD": 100, "Traffic": 250 }
|
||||
}
|
||||
"""
|
||||
.replace("{today}", LocalDate.now().toString())
|
||||
|
@ -25,7 +25,7 @@ class HsBookingItemEntityUnitTest {
|
||||
.type(HsBookingItemType.CLOUD_SERVER)
|
||||
.caption("some caption")
|
||||
.resources(Map.ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("SSD-storage", 512),
|
||||
entry("HDD-storage", 2048)))
|
||||
.validity(toPostgresDateRange(GIVEN_VALID_FROM, GIVEN_VALID_TO))
|
||||
@ -53,7 +53,7 @@ class HsBookingItemEntityUnitTest {
|
||||
void toStringContainsAllPropertiesAndResourcesSortedByKey() {
|
||||
final var result = givenBookingItem.toString();
|
||||
|
||||
assertThat(result).isEqualToIgnoringWhitespace("HsBookingItemEntity(D-1234500:test project, CLOUD_SERVER, [2020-01-01,2031-01-01), some caption, { \"CPUs\": 2, \"HDD-storage\": 2048, \"SSD-storage\": 512 })");
|
||||
assertThat(result).isEqualToIgnoringWhitespace("HsBookingItemEntity(D-1234500:test project, CLOUD_SERVER, [2020-01-01,2031-01-01), some caption, { \"CPU\": 2, \"HDD-storage\": 2048, \"SSD-storage\": 512 })");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -171,8 +171,8 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
|
||||
allTheseBookingItemsAreReturned(
|
||||
result,
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_WEBSPACE, [2022-10-01,), separate ManagedWebspace, { Daemons: 0, Multi: 1, SSD: 100, Traffic: 50 } )",
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SSD: 500, Traffic: 500 } )",
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 } )");
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPU: 2, RAM: 8, SSD: 500, Traffic: 500 } )",
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPU: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 } )");
|
||||
assertThat(result.stream().filter(bi -> bi.getRelatedHostingAsset()!=null).findAny())
|
||||
.as("at least one relatedProject expected, but none found => fetching relatedProject does not work")
|
||||
.isNotEmpty();
|
||||
@ -194,8 +194,8 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
|
||||
exactlyTheseBookingItemsAreReturned(
|
||||
result,
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_WEBSPACE, [2022-10-01,), separate ManagedWebspace, { Daemons: 0, Multi: 1, SSD: 100, Traffic: 50 } )",
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SSD: 500, Traffic: 500 } )",
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 } )");
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPU: 2, RAM: 8, SSD: 500, Traffic: 500 } )",
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPU: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 } )");
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
|
||||
final var result = jpaAttempt.transacted(() -> {
|
||||
context("superuser-alex@hostsharing.net");
|
||||
final var foundBookingItem = em.find(HsBookingItemEntity.class, givenBookingItemUuid);
|
||||
foundBookingItem.getResources().put("CPUs", 2);
|
||||
foundBookingItem.getResources().put("CPU", 2);
|
||||
foundBookingItem.getResources().remove("SSD-storage");
|
||||
foundBookingItem.getResources().put("HSD-storage", 2048);
|
||||
foundBookingItem.setValidity(Range.closedOpen(
|
||||
@ -336,7 +336,7 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
|
||||
.validity(Range.closedOpen(
|
||||
LocalDate.parse("2020-01-01"), LocalDate.parse("2023-01-01")))
|
||||
.resources(Map.ofEntries(
|
||||
entry("CPUs", 1),
|
||||
entry("CPU", 1),
|
||||
entry("SSD-storage", 256)))
|
||||
.build();
|
||||
|
||||
|
@ -17,7 +17,7 @@ public class TestHsBookingItem {
|
||||
.type(HsBookingItemType.CLOUD_SERVER)
|
||||
.caption("test cloud server booking item")
|
||||
.resources(Map.ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 4),
|
||||
entry("SSD", 50),
|
||||
entry("Traffic", 250)
|
||||
@ -30,7 +30,7 @@ public class TestHsBookingItem {
|
||||
.type(HsBookingItemType.MANAGED_SERVER)
|
||||
.caption("test project booking item")
|
||||
.resources(Map.ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 4),
|
||||
entry("SSD", 50),
|
||||
entry("Traffic", 250)
|
||||
|
@ -38,7 +38,7 @@ class HsBookingItemEntityValidatorUnitTest {
|
||||
// then
|
||||
assertThat(result).isInstanceOf(ValidationException.class)
|
||||
.hasMessageContaining(
|
||||
"'D-12345:test project:Test-Server.resources.CPUs' is required but missing",
|
||||
"'D-12345:test project:Test-Server.resources.CPU' is required but missing",
|
||||
"'D-12345:test project:Test-Server.resources.RAM' is required but missing",
|
||||
"'D-12345:test project:Test-Server.resources.SSD' is required but missing",
|
||||
"'D-12345:test project:Test-Server.resources.Traffic' is required but missing");
|
||||
|
@ -33,7 +33,7 @@ class HsCloudServerBookingItemValidatorUnitTest {
|
||||
.project(project)
|
||||
.caption("Test-Server")
|
||||
.resources(Map.ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 25),
|
||||
entry("SSD", 25),
|
||||
entry("Traffic", 250),
|
||||
@ -56,11 +56,12 @@ class HsCloudServerBookingItemValidatorUnitTest {
|
||||
// then
|
||||
assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder(
|
||||
"{type=boolean, propertyName=active, defaultValue=true}",
|
||||
"{type=integer, propertyName=CPUs, min=1, max=32, required=true}",
|
||||
"{type=integer, propertyName=RAM, unit=GB, min=1, max=128, required=true}",
|
||||
"{type=integer, propertyName=SSD, unit=GB, min=0, max=1000, step=25, required=true}",
|
||||
"{type=integer, propertyName=HDD, unit=GB, min=0, max=4000, step=250, defaultValue=0}",
|
||||
"{type=integer, propertyName=Traffic, unit=GB, min=250, max=10000, step=250, required=true}",
|
||||
"{type=integer, propertyName=CPU, min=1, max=32, required=true}",
|
||||
"{type=integer, propertyName=RAM, unit=GB, min=1, max=8192, required=true}",
|
||||
"{type=integer, propertyName=SSD, unit=GB, min=25, max=1000, step=25, requiresAtLeastOneOf=[SDD, HDD]}",
|
||||
"{type=integer, propertyName=HDD, unit=GB, min=250, max=4000, step=250, requiresAtLeastOneOf=[SSD, HDD]}",
|
||||
"{type=integer, propertyName=Traffic, unit=GB, min=250, max=10000, step=250, requiresAtMaxOneOf=[Bandwidth, Traffic]}",
|
||||
"{type=integer, propertyName=Bandwidth, unit=GB, min=250, max=10000, step=250, requiresAtMaxOneOf=[Bandwidth, Traffic]}",
|
||||
"{type=enumeration, propertyName=SLA-Infrastructure, values=[BASIC, EXT8H, EXT4H, EXT2H]}");
|
||||
}
|
||||
|
||||
@ -71,7 +72,7 @@ class HsCloudServerBookingItemValidatorUnitTest {
|
||||
.type(CLOUD_SERVER)
|
||||
.caption("Test Cloud-Server")
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 10),
|
||||
entry("SSD", 50),
|
||||
entry("Traffic", 2500)
|
||||
@ -81,7 +82,7 @@ class HsCloudServerBookingItemValidatorUnitTest {
|
||||
.type(MANAGED_SERVER)
|
||||
.caption("Test Managed-Server")
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 3),
|
||||
entry("CPU", 3),
|
||||
entry("RAM", 20),
|
||||
entry("SSD", 100),
|
||||
entry("Traffic", 3000)
|
||||
@ -92,7 +93,7 @@ class HsCloudServerBookingItemValidatorUnitTest {
|
||||
.project(project)
|
||||
.caption("Test Cloud")
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 4),
|
||||
entry("CPU", 4),
|
||||
entry("RAM", 20),
|
||||
entry("SSD", 100),
|
||||
entry("Traffic", 5000)
|
||||
@ -110,7 +111,7 @@ class HsCloudServerBookingItemValidatorUnitTest {
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'D-12345:Test-Project:Test Cloud.resources.CPUs' maximum total is 4, but actual total CPUs is 5",
|
||||
"'D-12345:Test-Project:Test Cloud.resources.CPU' maximum total is 4, but actual total CPU is 5",
|
||||
"'D-12345:Test-Project:Test Cloud.resources.RAM' maximum total is 20 GB, but actual total RAM is 30 GB",
|
||||
"'D-12345:Test-Project:Test Cloud.resources.SSD' maximum total is 100 GB, but actual total SSD is 150 GB",
|
||||
"'D-12345:Test-Project:Test Cloud.resources.Traffic' maximum total is 5000 GB, but actual total Traffic is 5500 GB"
|
||||
|
@ -40,7 +40,7 @@ class HsManagedServerBookingItemValidatorUnitTest {
|
||||
.type(MANAGED_SERVER)
|
||||
.project(project)
|
||||
.resources(Map.ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 25),
|
||||
entry("SSD", 25),
|
||||
entry("Traffic", 250),
|
||||
@ -63,11 +63,12 @@ class HsManagedServerBookingItemValidatorUnitTest {
|
||||
|
||||
// then
|
||||
assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder(
|
||||
"{type=integer, propertyName=CPUs, min=1, max=32, required=true}",
|
||||
"{type=integer, propertyName=CPU, min=1, max=32, required=true}",
|
||||
"{type=integer, propertyName=RAM, unit=GB, min=1, max=128, required=true}",
|
||||
"{type=integer, propertyName=SSD, unit=GB, min=25, max=1000, step=25, required=true, isTotalsValidator=true, thresholdPercentage=200}",
|
||||
"{type=integer, propertyName=HDD, unit=GB, min=0, max=4000, step=250, defaultValue=0, isTotalsValidator=true, thresholdPercentage=200}",
|
||||
"{type=integer, propertyName=Traffic, unit=GB, min=250, max=10000, step=250, required=true, isTotalsValidator=true, thresholdPercentage=200}",
|
||||
"{type=integer, propertyName=SSD, unit=GB, min=25, max=2000, step=25, requiresAtLeastOneOf=[SSD, HDD], isTotalsValidator=true, thresholdPercentage=200}",
|
||||
"{type=integer, propertyName=HDD, unit=GB, min=250, max=10000, step=250, requiresAtLeastOneOf=[SSD, HDD], isTotalsValidator=true, thresholdPercentage=200}",
|
||||
"{type=integer, propertyName=Traffic, unit=GB, min=250, max=64000, step=250, requiresAtMaxOneOf=[Bandwidth, Traffic], isTotalsValidator=true, thresholdPercentage=200}",
|
||||
"{type=integer, propertyName=Bandwidth, unit=GB, min=250, max=64000, step=250, requiresAtMaxOneOf=[Bandwidth, Traffic], isTotalsValidator=true, thresholdPercentage=200}",
|
||||
"{type=enumeration, propertyName=SLA-Platform, values=[BASIC, EXT8H, EXT4H, EXT2H], defaultValue=BASIC}",
|
||||
"{type=boolean, propertyName=SLA-EMail}", // TODO.impl: falseIf-validation is missing in output
|
||||
"{type=boolean, propertyName=SLA-Maria}",
|
||||
@ -82,7 +83,7 @@ class HsManagedServerBookingItemValidatorUnitTest {
|
||||
final var subCloudServerBookingItemEntity = HsBookingItemEntity.builder()
|
||||
.type(CLOUD_SERVER)
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 10),
|
||||
entry("SSD", 50),
|
||||
entry("Traffic", 2500)
|
||||
@ -91,7 +92,7 @@ class HsManagedServerBookingItemValidatorUnitTest {
|
||||
final HsBookingItemEntity subManagedServerBookingItemEntity = HsBookingItemEntity.builder()
|
||||
.type(MANAGED_SERVER)
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 3),
|
||||
entry("CPU", 3),
|
||||
entry("RAM", 20),
|
||||
entry("SSD", 100),
|
||||
entry("Traffic", 3000)
|
||||
@ -101,7 +102,7 @@ class HsManagedServerBookingItemValidatorUnitTest {
|
||||
.type(PRIVATE_CLOUD)
|
||||
.project(project)
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 4),
|
||||
entry("CPU", 4),
|
||||
entry("RAM", 20),
|
||||
entry("SSD", 100),
|
||||
entry("Traffic", 5000)
|
||||
@ -120,7 +121,7 @@ class HsManagedServerBookingItemValidatorUnitTest {
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'D-12345:Test-Project:null.resources.CPUs' maximum total is 4, but actual total CPUs is 5",
|
||||
"'D-12345:Test-Project:null.resources.CPU' maximum total is 4, but actual total CPU is 5",
|
||||
"'D-12345:Test-Project:null.resources.RAM' maximum total is 20 GB, but actual total RAM is 30 GB",
|
||||
"'D-12345:Test-Project:null.resources.SSD' maximum total is 100 GB, but actual total SSD is 150 GB",
|
||||
"'D-12345:Test-Project:null.resources.Traffic' maximum total is 5000 GB, but actual total Traffic is 5500 GB"
|
||||
|
@ -29,7 +29,7 @@ class HsManagedWebspaceBookingItemValidatorUnitTest {
|
||||
.project(project)
|
||||
.caption("Test Managed-Webspace")
|
||||
.resources(Map.ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 25),
|
||||
entry("Traffic", 250),
|
||||
entry("SLA-EMail", true)
|
||||
@ -41,7 +41,7 @@ class HsManagedWebspaceBookingItemValidatorUnitTest {
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'D-12345:Test-Project:Test Managed-Webspace.resources.CPUs' is not expected but is set to '2'",
|
||||
"'D-12345:Test-Project:Test Managed-Webspace.resources.CPU' is not expected but is set to '2'",
|
||||
"'D-12345:Test-Project:Test Managed-Webspace.resources.RAM' is not expected but is set to '25'",
|
||||
"'D-12345:Test-Project:Test Managed-Webspace.resources.SSD' is required but missing",
|
||||
"'D-12345:Test-Project:Test Managed-Webspace.resources.SLA-EMail' is not expected but is set to 'true'"
|
||||
@ -55,11 +55,12 @@ class HsManagedWebspaceBookingItemValidatorUnitTest {
|
||||
|
||||
// then
|
||||
assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder(
|
||||
"{type=integer, propertyName=SSD, unit=GB, min=1, max=100, step=1, required=true}",
|
||||
"{type=integer, propertyName=HDD, unit=GB, min=0, max=250, step=10}",
|
||||
"{type=integer, propertyName=Traffic, unit=GB, min=10, max=1000, step=10, required=true}",
|
||||
"{type=integer, propertyName=SSD, unit=GB, min=1, max=2000, step=1, required=true}",
|
||||
"{type=integer, propertyName=HDD, unit=GB, min=0, max=10000, step=10}",
|
||||
"{type=integer, propertyName=Traffic, unit=GB, min=10, max=64000, step=10, requiresAtMaxOneOf=[Bandwidth, Traffic]}",
|
||||
"{type=integer, propertyName=Bandwidth, unit=GB, min=10, max=1000, step=10, requiresAtMaxOneOf=[Bandwidth, Traffic]}",
|
||||
"{type=integer, propertyName=Multi, min=1, max=100, step=1, defaultValue=1}",
|
||||
"{type=integer, propertyName=Daemons, min=0, max=10, defaultValue=0}",
|
||||
"{type=integer, propertyName=Daemons, min=0, max=16, defaultValue=0}",
|
||||
"{type=boolean, propertyName=Online Office Server}",
|
||||
"{type=enumeration, propertyName=SLA-Platform, values=[BASIC, EXT24H], defaultValue=BASIC}");
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import static java.util.Map.ofEntries;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.CLOUD_SERVER;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_SERVER;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.PRIVATE_CLOUD;
|
||||
import static net.hostsharing.hsadminng.hs.booking.project.TestHsBookingProject.TEST_PROJECT;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class HsPrivateCloudBookingItemValidatorUnitTest {
|
||||
@ -28,9 +29,10 @@ class HsPrivateCloudBookingItemValidatorUnitTest {
|
||||
// given
|
||||
final var privateCloudBookingItemEntity = HsBookingItemEntity.builder()
|
||||
.type(PRIVATE_CLOUD)
|
||||
.project(TEST_PROJECT)
|
||||
.caption("myPC")
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 4),
|
||||
entry("CPU", 4),
|
||||
entry("RAM", 20),
|
||||
entry("SSD", 100),
|
||||
entry("Traffic", 5000),
|
||||
@ -42,7 +44,7 @@ class HsPrivateCloudBookingItemValidatorUnitTest {
|
||||
.type(MANAGED_SERVER)
|
||||
.caption("myMS-1")
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 10),
|
||||
entry("SSD", 50),
|
||||
entry("Traffic", 2500),
|
||||
@ -54,7 +56,7 @@ class HsPrivateCloudBookingItemValidatorUnitTest {
|
||||
.type(CLOUD_SERVER)
|
||||
.caption("myMS-2")
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 10),
|
||||
entry("SSD", 50),
|
||||
entry("Traffic", 2500),
|
||||
@ -80,7 +82,7 @@ class HsPrivateCloudBookingItemValidatorUnitTest {
|
||||
.type(PRIVATE_CLOUD)
|
||||
.caption("myPC")
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 4),
|
||||
entry("CPU", 4),
|
||||
entry("RAM", 20),
|
||||
entry("SSD", 100),
|
||||
entry("Traffic", 5000),
|
||||
@ -92,7 +94,7 @@ class HsPrivateCloudBookingItemValidatorUnitTest {
|
||||
.type(MANAGED_SERVER)
|
||||
.caption("myMS-1")
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 3),
|
||||
entry("CPU", 3),
|
||||
entry("RAM", 20),
|
||||
entry("SSD", 100),
|
||||
entry("Traffic", 3000),
|
||||
@ -104,7 +106,7 @@ class HsPrivateCloudBookingItemValidatorUnitTest {
|
||||
.type(CLOUD_SERVER)
|
||||
.caption("myMS-2")
|
||||
.resources(ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 10),
|
||||
entry("SSD", 50),
|
||||
entry("Traffic", 2500),
|
||||
@ -124,7 +126,7 @@ class HsPrivateCloudBookingItemValidatorUnitTest {
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'D-12345:Test-Project:myPC.resources.CPUs' maximum total is 4, but actual total CPUs is 5",
|
||||
"'D-12345:Test-Project:myPC.resources.CPU' maximum total is 4, but actual total CPU is 5",
|
||||
"'D-12345:Test-Project:myPC.resources.RAM' maximum total is 20 GB, but actual total RAM is 30 GB",
|
||||
"'D-12345:Test-Project:myPC.resources.SSD' maximum total is 100 GB, but actual total SSD is 150 GB",
|
||||
"'D-12345:Test-Project:myPC.resources.Traffic' maximum total is 5000 GB, but actual total Traffic is 5500 GB",
|
||||
|
@ -702,7 +702,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var project = projectRepo.findByCaption(projectCaption).getFirst();
|
||||
final var resources = switch (bookingItemType) {
|
||||
case MANAGED_SERVER -> Map.<String, Object>ofEntries(entry("CPUs", 1),
|
||||
case MANAGED_SERVER -> Map.<String, Object>ofEntries(entry("CPU", 1),
|
||||
entry("RAM", 20),
|
||||
entry("SSD", 25),
|
||||
entry("Traffic", 250));
|
||||
|
@ -16,7 +16,7 @@ class HsHostingAssetEntityUnitTest {
|
||||
.identifier("vm1234")
|
||||
.caption("some managed asset")
|
||||
.config(Map.ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("SSD-storage", 512),
|
||||
entry("HDD-storage", 2048)))
|
||||
.build();
|
||||
@ -27,7 +27,7 @@ class HsHostingAssetEntityUnitTest {
|
||||
.identifier("xyz00")
|
||||
.caption("some managed webspace")
|
||||
.config(Map.ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("SSD-storage", 512),
|
||||
entry("HDD-storage", 2048)))
|
||||
.build();
|
||||
@ -58,7 +58,7 @@ class HsHostingAssetEntityUnitTest {
|
||||
void toStringContainsAllPropertiesAndResourcesSortedByKey() {
|
||||
|
||||
assertThat(givenWebspace.toString()).isEqualToIgnoringWhitespace(
|
||||
"HsHostingAssetEntity(MANAGED_WEBSPACE, xyz00, some managed webspace, MANAGED_SERVER:vm1234, D-1234500:test project:test cloud server booking item, { \"CPUs\": 2, \"HDD-storage\": 2048, \"SSD-storage\": 512 })");
|
||||
"HsHostingAssetEntity(MANAGED_WEBSPACE, xyz00, some managed webspace, MANAGED_SERVER:vm1234, D-1234500:test project:test cloud server booking item, { \"CPU\": 2, \"HDD-storage\": 2048, \"SSD-storage\": 512 })");
|
||||
|
||||
assertThat(givenUnixUser.toString()).isEqualToIgnoringWhitespace(
|
||||
"HsHostingAssetEntity(UNIX_USER, xyz00-web, some unix-user, MANAGED_WEBSPACE:xyz00, { \"HDD-hard-quota\": 512, \"HDD-soft-quota\": 256, \"SSD-hard-quota\": 256, \"SSD-soft-quota\": 128 })");
|
||||
|
@ -263,7 +263,7 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
|
||||
final var result = jpaAttempt.transacted(() -> {
|
||||
context("superuser-alex@hostsharing.net");
|
||||
final var foundAsset = em.find(HsHostingAssetEntity.class, givenAssetUuid);
|
||||
foundAsset.getConfig().put("CPUs", 2);
|
||||
foundAsset.getConfig().put("CPU", 2);
|
||||
foundAsset.getConfig().remove("SSD-storage");
|
||||
foundAsset.getConfig().put("HSD-storage", 2048);
|
||||
return toCleanup(assetRepo.save(foundAsset));
|
||||
@ -404,7 +404,7 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
|
||||
.identifier(identifier)
|
||||
.caption("some temp cloud asset")
|
||||
.config(Map.ofEntries(
|
||||
entry("CPUs", 1),
|
||||
entry("CPU", 1),
|
||||
entry("SSD-storage", 256)))
|
||||
.build();
|
||||
|
||||
|
@ -12,9 +12,9 @@ class HsHostingAssetTypeUnitTest {
|
||||
|
||||
assertThat(result).isEqualTo("""
|
||||
## HostingAsset Type Structure
|
||||
|
||||
|
||||
### Webspace+Server
|
||||
|
||||
|
||||
### Server+Webspace
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
@ -35,6 +35,12 @@ class HsHostingAssetTypeUnitTest {
|
||||
entity HA_IPV6_NUMBER
|
||||
}
|
||||
|
||||
package Webspace #99bcdb {
|
||||
entity HA_MANAGED_WEBSPACE
|
||||
entity HA_UNIX_USER
|
||||
entity HA_EMAIL_ALIAS
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
|
||||
@ -43,10 +49,16 @@ class HsHostingAssetTypeUnitTest {
|
||||
|
||||
HA_CLOUD_SERVER *==> BI_CLOUD_SERVER
|
||||
HA_MANAGED_SERVER *==> BI_MANAGED_SERVER
|
||||
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
|
||||
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
|
||||
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
|
||||
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
|
||||
HA_IPV4_NUMBER o..> HA_CLOUD_SERVER
|
||||
HA_IPV4_NUMBER o..> HA_MANAGED_SERVER
|
||||
HA_IPV4_NUMBER o..> HA_MANAGED_WEBSPACE
|
||||
HA_IPV6_NUMBER o..> HA_CLOUD_SERVER
|
||||
HA_IPV6_NUMBER o..> HA_MANAGED_SERVER
|
||||
HA_IPV6_NUMBER o..> HA_MANAGED_WEBSPACE
|
||||
|
||||
package Legend #white {
|
||||
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
|
||||
|
@ -22,7 +22,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest {
|
||||
.type(HsBookingItemType.MANAGED_SERVER)
|
||||
.caption("Test Managed-Server")
|
||||
.resources(Map.ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("CPU", 2),
|
||||
entry("RAM", 25),
|
||||
entry("SSD", 25),
|
||||
entry("Traffic", 250),
|
||||
@ -125,6 +125,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest {
|
||||
.type(MANAGED_WEBSPACE)
|
||||
.bookingItem(HsBookingItemEntity.builder()
|
||||
.type(HsBookingItemType.MANAGED_WEBSPACE)
|
||||
.project(TEST_PROJECT)
|
||||
.caption("some ManagedWebspace")
|
||||
.resources(Map.ofEntries(entry("SSD", 25), entry("Traffic", 250)))
|
||||
.build())
|
||||
|
@ -0,0 +1,312 @@
|
||||
package net.hostsharing.hsadminng.hs.migration;
|
||||
|
||||
import com.opencsv.CSVParserBuilder;
|
||||
import com.opencsv.CSVReader;
|
||||
import com.opencsv.CSVReaderBuilder;
|
||||
import net.hostsharing.hsadminng.rbac.context.ContextBasedTest;
|
||||
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
||||
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
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.Value;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.lang.Boolean.parseBoolean;
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||
|
||||
public class CsvDataImport extends ContextBasedTest {
|
||||
|
||||
public static final String TEST_DATA_MIGRATION_DATA_PATH = "migration";
|
||||
public static final String MIGRATION_DATA_PATH = ofNullable(System.getenv("HSADMINNG_MIGRATION_DATA_PATH"))
|
||||
.orElse(TEST_DATA_MIGRATION_DATA_PATH);
|
||||
|
||||
@Value("${spring.datasource.url}")
|
||||
protected String jdbcUrl;
|
||||
|
||||
@Value("${spring.datasource.username}")
|
||||
protected String postgresAdminUser;
|
||||
|
||||
@Value("${hsadminng.superuser}")
|
||||
protected String rbacSuperuser;
|
||||
|
||||
@PersistenceContext
|
||||
EntityManager em;
|
||||
|
||||
@Autowired
|
||||
TransactionTemplate txTemplate;
|
||||
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
@MockBean
|
||||
HttpServletRequest request;
|
||||
|
||||
private static final List<AssertionError> errors = new ArrayList<>();
|
||||
|
||||
public List<String[]> readAllLines(Reader reader) throws Exception {
|
||||
|
||||
final var parser = new CSVParserBuilder()
|
||||
.withSeparator(';')
|
||||
.withQuoteChar('"')
|
||||
.build();
|
||||
|
||||
final var filteredReader = skippingEmptyAndCommentLines(reader);
|
||||
try (CSVReader csvReader = new CSVReaderBuilder(filteredReader)
|
||||
.withCSVParser(parser)
|
||||
.build()) {
|
||||
return csvReader.readAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static Reader skippingEmptyAndCommentLines(Reader reader) throws IOException {
|
||||
try (var bufferedReader = new BufferedReader(reader);
|
||||
StringWriter writer = new StringWriter()) {
|
||||
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
if (!line.isBlank() && !line.startsWith("#")) {
|
||||
writer.write(line);
|
||||
writer.write("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return new StringReader(writer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected static String[] justHeader(final List<String[]> lines) {
|
||||
return stream(lines.getFirst()).map(String::trim).toArray(String[]::new);
|
||||
}
|
||||
|
||||
protected Reader resourceReader(@NotNull final String resourcePath) {
|
||||
return new InputStreamReader(requireNonNull(getClass().getClassLoader().getResourceAsStream(resourcePath)));
|
||||
}
|
||||
|
||||
protected List<String[]> withoutHeader(final List<String[]> records) {
|
||||
return records.subList(1, records.size());
|
||||
}
|
||||
|
||||
String[] trimAll(final String[] record) {
|
||||
for (int i = 0; i < record.length; ++i) {
|
||||
if (record[i] != null) {
|
||||
record[i] = record[i].trim();
|
||||
}
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
public <T extends RbacObject> T persist(final Integer id, final T entity) {
|
||||
try {
|
||||
final var asString = entity.toString();
|
||||
if ( asString.contains("'null null, null'") || asString.equals("person()")) {
|
||||
System.err.println("skipping to persist empty record-id " + id + " #" + entity.hashCode() + ": " + entity);
|
||||
return entity;
|
||||
}
|
||||
//System.out.println("persisting #" + entity.hashCode() + ": " + entity);
|
||||
em.persist(entity);
|
||||
// uncomment for debugging purposes
|
||||
// em.flush(); // makes it slow, but produces better error messages
|
||||
// System.out.println("persisted #" + entity.hashCode() + " as " + entity.getUuid());
|
||||
} catch (Exception exc) {
|
||||
System.err.println("failed to persist #" + entity.hashCode() + ": " + entity);
|
||||
System.err.println(exc);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
protected <E> String toFormattedString(final Map<Integer, E> map) {
|
||||
if ( map.isEmpty() ) {
|
||||
return "{}";
|
||||
}
|
||||
return "{\n" +
|
||||
map.keySet().stream()
|
||||
.map(id -> " " + id + "=" + map.get(id).toString())
|
||||
.map(e -> e.replaceAll("\n ", " ").replace("\n", ""))
|
||||
.sorted()
|
||||
.collect(Collectors.joining(",\n")) +
|
||||
"\n}\n";
|
||||
}
|
||||
|
||||
protected void deleteTestDataFromHsOfficeTables() {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
// TODO.perf: could we instead skip creating test-data based on an env var?
|
||||
em.createNativeQuery("delete from hs_hosting_asset where true").executeUpdate();
|
||||
em.createNativeQuery("delete from hs_booking_item where true").executeUpdate();
|
||||
em.createNativeQuery("delete from hs_booking_project 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_coopsharestransaction 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_sepamandate 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_bankaccount 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_relation where true").executeUpdate();
|
||||
em.createNativeQuery("delete from hs_office_contact where true").executeUpdate();
|
||||
em.createNativeQuery("delete from hs_office_person where true").executeUpdate();
|
||||
}).assertSuccessful();
|
||||
}
|
||||
|
||||
protected void resetHsOfficeSequences() {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
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 public.hs_office_coopsharestransaction_legacy_id_seq restart with 1000000000;")
|
||||
.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();
|
||||
});
|
||||
}
|
||||
|
||||
protected void deleteFromTestTables() {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
em.createNativeQuery("delete from test_domain where true").executeUpdate();
|
||||
em.createNativeQuery("delete from test_package where true").executeUpdate();
|
||||
em.createNativeQuery("delete from test_customer where true").executeUpdate();
|
||||
}).assertSuccessful();
|
||||
}
|
||||
|
||||
protected void deleteFromRbacTables() {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
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_context where true").executeUpdate();
|
||||
}).assertSuccessful();
|
||||
}
|
||||
|
||||
void logError(final Runnable assertion) {
|
||||
try {
|
||||
assertion.run();
|
||||
} catch (final AssertionError exc) {
|
||||
errors.add(exc);
|
||||
}
|
||||
}
|
||||
|
||||
void logErrors() {
|
||||
assumeThat(errors).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
class Columns {
|
||||
|
||||
private final List<String> columnNames;
|
||||
|
||||
public Columns(final String[] header) {
|
||||
columnNames = List.of(header);
|
||||
}
|
||||
|
||||
int indexOf(final String columnName) {
|
||||
int index = columnNames.indexOf(columnName);
|
||||
if (index < 0) {
|
||||
throw new RuntimeException("column name '" + columnName + "' not found in: " + columnNames);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
class Record {
|
||||
|
||||
private final Columns columns;
|
||||
private final String[] row;
|
||||
|
||||
public Record(final Columns columns, final String[] row) {
|
||||
this.columns = columns;
|
||||
this.row = row;
|
||||
}
|
||||
|
||||
String getString(final String columnName) {
|
||||
return row[columns.indexOf(columnName)];
|
||||
}
|
||||
|
||||
boolean isEmpty(final String columnName) {
|
||||
final String value = getString(columnName);
|
||||
return value == null || value.isBlank();
|
||||
}
|
||||
|
||||
boolean getBoolean(final String columnName) {
|
||||
final String value = getString(columnName);
|
||||
return isNotBlank(value) &&
|
||||
( parseBoolean(value.trim()) || value.trim().startsWith("t"));
|
||||
}
|
||||
|
||||
Integer getInteger(final String columnName) {
|
||||
final String value = getString(columnName);
|
||||
return isNotBlank(value) ? Integer.parseInt(value.trim()) : null;
|
||||
}
|
||||
|
||||
BigDecimal getBigDecimal(final String columnName) {
|
||||
final String value = getString(columnName);
|
||||
if (isNotBlank(value)) {
|
||||
return new BigDecimal(value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
LocalDate getLocalDate(final String columnName) {
|
||||
final String dateString = getString(columnName);
|
||||
if (isNotBlank(dateString)) {
|
||||
return LocalDate.parse(dateString);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class OrderedDependedTestsExtension implements TestWatcher, BeforeEachCallback {
|
||||
|
||||
private static boolean previousTestsPassed = true;
|
||||
|
||||
public void testFailed(ExtensionContext context, Throwable cause) {
|
||||
previousTestsPassed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeEach(final ExtensionContext extensionContext) {
|
||||
assumeThat(previousTestsPassed).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
class WriteOnceMap<K, V> extends TreeMap<K, V> {
|
||||
|
||||
@Override
|
||||
public V put(final K k, final V v) {
|
||||
assertThat(containsKey(k)).describedAs("overwriting " + get(k) + " index " + k + " with " + v).isFalse();
|
||||
return super.put(k, v);
|
||||
}
|
||||
}
|
@ -0,0 +1,620 @@
|
||||
package net.hostsharing.hsadminng.hs.migration;
|
||||
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorEntity;
|
||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
|
||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
|
||||
import net.hostsharing.hsadminng.hs.booking.item.validators.HsBookingItemEntityValidatorRegistry;
|
||||
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectEntity;
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntitySaveProcessor;
|
||||
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.annotation.Commit;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.IPV4_NUMBER;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
|
||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||
|
||||
/*
|
||||
* 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-importHostingAssets # comes from .aliases file and uses .environment
|
||||
*/
|
||||
@Tag("importHostingAssets")
|
||||
@DataJpaTest(properties = {
|
||||
"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.password=${HSADMINNG_POSTGRES_ADMIN_PASSWORD:password}",
|
||||
"hsadminng.superuser=${HSADMINNG_SUPERUSER:superuser-alex@hostsharing.net}"
|
||||
})
|
||||
@DirtiesContext
|
||||
@Import({ Context.class, JpaAttempt.class })
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@ExtendWith(OrderedDependedTestsExtension.class)
|
||||
public class ImportHostingAssets extends ImportOfficeData {
|
||||
|
||||
static final Integer IP_NUMBER_ID_OFFSET = 1000000;
|
||||
static final Integer HIVE_ID_OFFSET = 2000000;
|
||||
static final Integer PACKET_ID_OFFSET = 3000000;
|
||||
|
||||
record Hive(int hive_id, String hive_name, int inet_addr_id, AtomicReference<HsHostingAssetEntity> serverRef) {}
|
||||
|
||||
static Map<Integer, HsBookingProjectEntity> bookingProjects = new WriteOnceMap<>();
|
||||
static Map<Integer, HsBookingItemEntity> bookingItems = new WriteOnceMap<>();
|
||||
static Map<Integer, Hive> hives = new WriteOnceMap<>();
|
||||
static Map<Integer, HsHostingAssetEntity> hostingAssets = new WriteOnceMap<>(); // TODO.impl: separate maps for each type?
|
||||
|
||||
@Test
|
||||
@Order(11010)
|
||||
void createBookingProjects() {
|
||||
debitors.forEach((id, debitor) -> {
|
||||
bookingProjects.put(id, HsBookingProjectEntity.builder()
|
||||
.caption(debitor.getDefaultPrefix() + " default project")
|
||||
.debitor(em.find(HsBookingDebitorEntity.class, debitor.getUuid()))
|
||||
.build());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(12010)
|
||||
void importIpNumbers() {
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/hosting/inet_addr.csv")) {
|
||||
final var lines = readAllLines(reader);
|
||||
importIpNumbers(justHeader(lines), withoutHeader(lines));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(12019)
|
||||
void verifyIpNumbers() {
|
||||
assumeThatWeAreImportingControlledTestData();
|
||||
|
||||
// no contacts yet => mostly null values
|
||||
assertThat(firstOfEachType(5, IPV4_NUMBER)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
1000363=HsHostingAssetEntity(IPV4_NUMBER, 83.223.95.34),
|
||||
1000381=HsHostingAssetEntity(IPV4_NUMBER, 83.223.95.52),
|
||||
1000402=HsHostingAssetEntity(IPV4_NUMBER, 83.223.95.73),
|
||||
1000433=HsHostingAssetEntity(IPV4_NUMBER, 83.223.95.104),
|
||||
1000457=HsHostingAssetEntity(IPV4_NUMBER, 83.223.95.128)
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(12030)
|
||||
void importHives() {
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/hosting/hive.csv")) {
|
||||
final var lines = readAllLines(reader);
|
||||
importHives(justHeader(lines), withoutHeader(lines));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(12039)
|
||||
void verifyHives() {
|
||||
assumeThatWeAreImportingControlledTestData();
|
||||
|
||||
// no contacts yet => mostly null values
|
||||
assertThat(toFormattedString(first(5, hives))).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
2000001=Hive[hive_id=1, hive_name=h00, inet_addr_id=358, serverRef=null],
|
||||
2000002=Hive[hive_id=2, hive_name=h01, inet_addr_id=359, serverRef=null],
|
||||
2000004=Hive[hive_id=4, hive_name=h02, inet_addr_id=360, serverRef=null],
|
||||
2000007=Hive[hive_id=7, hive_name=h03, inet_addr_id=361, serverRef=null],
|
||||
2000013=Hive[hive_id=13, hive_name=h04, inet_addr_id=430, serverRef=null]
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(13000)
|
||||
void importPackets() {
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/hosting/packet.csv")) {
|
||||
final var lines = readAllLines(reader);
|
||||
importPackets(justHeader(lines), withoutHeader(lines));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(13009)
|
||||
void verifyPackets() {
|
||||
assumeThatWeAreImportingControlledTestData();
|
||||
|
||||
assertThat(firstOfEachType(3, CLOUD_SERVER, MANAGED_SERVER, MANAGED_WEBSPACE)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
3000630=HsHostingAssetEntity(MANAGED_WEBSPACE, hsh00, HA hsh00, MANAGED_SERVER:vm1050, D-1000000:hsh default project:BI hsh00),
|
||||
3000968=HsHostingAssetEntity(MANAGED_SERVER, vm1061, HA vm1061, D-1015200:rar default project:BI vm1061),
|
||||
3000978=HsHostingAssetEntity(MANAGED_SERVER, vm1050, HA vm1050, D-1000000:hsh default project:BI vm1050),
|
||||
3001061=HsHostingAssetEntity(MANAGED_SERVER, vm1068, HA vm1068, D-1000300:mim default project:BI vm1068),
|
||||
3001094=HsHostingAssetEntity(MANAGED_WEBSPACE, lug00, HA lug00, MANAGED_SERVER:vm1068, D-1000300:mim default project:BI lug00),
|
||||
3001112=HsHostingAssetEntity(MANAGED_WEBSPACE, mim00, HA mim00, MANAGED_SERVER:vm1068, D-1000300:mim default project:BI mim00),
|
||||
3023611=HsHostingAssetEntity(CLOUD_SERVER, vm2097, HA vm2097, D-1101800:wws default project:BI vm2097)
|
||||
}
|
||||
""");
|
||||
assertThat(firstOfEachType(
|
||||
3,
|
||||
HsBookingItemType.CLOUD_SERVER,
|
||||
HsBookingItemType.MANAGED_SERVER,
|
||||
HsBookingItemType.MANAGED_WEBSPACE)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
3000630=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_WEBSPACE, [2001-06-01,), BI hsh00),
|
||||
3000968=HsBookingItemEntity(D-1015200:rar default project, MANAGED_SERVER, [2013-04-01,), BI vm1061),
|
||||
3000978=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_SERVER, [2013-04-01,), BI vm1050),
|
||||
3001061=HsBookingItemEntity(D-1000300:mim default project, MANAGED_SERVER, [2013-08-19,), BI vm1068),
|
||||
3001094=HsBookingItemEntity(D-1000300:mim default project, MANAGED_WEBSPACE, [2013-09-10,), BI lug00),
|
||||
3001112=HsBookingItemEntity(D-1000300:mim default project, MANAGED_WEBSPACE, [2013-09-17,), BI mim00),
|
||||
3023611=HsBookingItemEntity(D-1101800:wws default project, CLOUD_SERVER, [2022-08-10,), BI vm2097)
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(13010)
|
||||
void importPacketComponents() {
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/hosting/packet_component.csv")) {
|
||||
final var lines = readAllLines(reader);
|
||||
importPacketComponents(justHeader(lines), withoutHeader(lines));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(13019)
|
||||
void verifyPacketComponents() {
|
||||
assumeThatWeAreImportingControlledTestData();
|
||||
|
||||
// no contacts yet => mostly null values
|
||||
assertThat(firstOfEachType(5, CLOUD_SERVER, MANAGED_SERVER, MANAGED_WEBSPACE))
|
||||
.isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
3000630=HsHostingAssetEntity(MANAGED_WEBSPACE, hsh00, HA hsh00, MANAGED_SERVER:vm1050, D-1000000:hsh default project:BI hsh00),
|
||||
3000968=HsHostingAssetEntity(MANAGED_SERVER, vm1061, HA vm1061, D-1015200:rar default project:BI vm1061),
|
||||
3000978=HsHostingAssetEntity(MANAGED_SERVER, vm1050, HA vm1050, D-1000000:hsh default project:BI vm1050),
|
||||
3001061=HsHostingAssetEntity(MANAGED_SERVER, vm1068, HA vm1068, D-1000300:mim default project:BI vm1068),
|
||||
3001094=HsHostingAssetEntity(MANAGED_WEBSPACE, lug00, HA lug00, MANAGED_SERVER:vm1068, D-1000300:mim default project:BI lug00),
|
||||
3001112=HsHostingAssetEntity(MANAGED_WEBSPACE, mim00, HA mim00, MANAGED_SERVER:vm1068, D-1000300:mim default project:BI mim00),
|
||||
3001447=HsHostingAssetEntity(MANAGED_SERVER, vm1093, HA vm1093, D-1000000:hsh default project:BI vm1093),
|
||||
3019959=HsHostingAssetEntity(MANAGED_WEBSPACE, dph00, HA dph00, MANAGED_SERVER:vm1093, D-1101900:dph default project:BI dph00),
|
||||
3023611=HsHostingAssetEntity(CLOUD_SERVER, vm2097, HA vm2097, D-1101800:wws default project:BI vm2097)
|
||||
}
|
||||
""");
|
||||
assertThat(firstOfEachType(
|
||||
5,
|
||||
HsBookingItemType.CLOUD_SERVER,
|
||||
HsBookingItemType.MANAGED_SERVER,
|
||||
HsBookingItemType.MANAGED_WEBSPACE))
|
||||
.isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
3000630=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_WEBSPACE, [2001-06-01,), BI hsh00, { "HDD": 10, "Multi": 25, "SLA-Platform": "EXT24H", "SSD": 16, "Traffic": 50}),
|
||||
3000968=HsBookingItemEntity(D-1015200:rar default project, MANAGED_SERVER, [2013-04-01,), BI vm1061, { "CPU": 6, "HDD": 250, "RAM": 14, "SLA-EMail": true, "SLA-Maria": true, "SLA-Office": true, "SLA-PgSQL": true, "SLA-Platform": "EXT4H", "SLA-Web": true, "SSD": 375, "Traffic": 250}),
|
||||
3000978=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_SERVER, [2013-04-01,), BI vm1050, { "CPU": 4, "HDD": 250, "RAM": 32, "SLA-EMail": true, "SLA-Maria": true, "SLA-Office": true, "SLA-PgSQL": true, "SLA-Platform": "EXT4H", "SLA-Web": true, "SSD": 150, "Traffic": 250}),
|
||||
3001061=HsBookingItemEntity(D-1000300:mim default project, MANAGED_SERVER, [2013-08-19,), BI vm1068, { "CPU": 2, "HDD": 250, "RAM": 4, "SLA-EMail": true, "SLA-Maria": true, "SLA-Office": true, "SLA-PgSQL": true, "SLA-Platform": "EXT2H", "SLA-Web": true, "Traffic": 250}),
|
||||
3001094=HsBookingItemEntity(D-1000300:mim default project, MANAGED_WEBSPACE, [2013-09-10,), BI lug00, { "Multi": 5, "SLA-Platform": "EXT24H", "SSD": 1, "Traffic": 10}),
|
||||
3001112=HsBookingItemEntity(D-1000300:mim default project, MANAGED_WEBSPACE, [2013-09-17,), BI mim00, { "Multi": 5, "SLA-Platform": "EXT24H", "SSD": 3, "Traffic": 20}),
|
||||
3001447=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_SERVER, [2014-11-28,), BI vm1093, { "CPU": 6, "HDD": 500, "RAM": 16, "SLA-EMail": true, "SLA-Maria": true, "SLA-Office": true, "SLA-PgSQL": true, "SLA-Platform": "EXT4H", "SLA-Web": true, "SSD": 300, "Traffic": 250}),
|
||||
3019959=HsBookingItemEntity(D-1101900:dph default project, MANAGED_WEBSPACE, [2021-06-02,), BI dph00, { "Multi": 1, "SLA-Platform": "EXT24H", "SSD": 25, "Traffic": 20}),
|
||||
3023611=HsBookingItemEntity(D-1101800:wws default project, CLOUD_SERVER, [2022-08-10,), BI vm2097, { "CPU": 8, "RAM": 12, "SLA-Infrastructure": "EXT4H", "SSD": 25, "Traffic": 250})
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(11400)
|
||||
void validateBookingItems() {
|
||||
bookingItems.forEach((id, bi) -> {
|
||||
try {
|
||||
HsBookingItemEntityValidatorRegistry.validated(bi);
|
||||
} catch (final Exception exc) {
|
||||
System.err.println("validation failed for id:" + id + "( " + bi + "): " + exc.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(11410)
|
||||
void validateHostingAssets() {
|
||||
hostingAssets.forEach((id, ha) -> {
|
||||
try {
|
||||
new HostingAssetEntitySaveProcessor(ha)
|
||||
.preprocessEntity()
|
||||
.validateEntity();
|
||||
} catch (final Exception exc) {
|
||||
System.err.println("validation failed for id:" + id + "( " + ha + "): " + exc.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(19000)
|
||||
@Commit
|
||||
void persistHostingAssetEntities() {
|
||||
|
||||
System.out.println("PERSISTING hosting-assets to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'");
|
||||
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
bookingProjects.forEach(this::persist);
|
||||
}).assertSuccessful();
|
||||
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
bookingItems.forEach(this::persistRecursively);
|
||||
}).assertSuccessful();
|
||||
|
||||
persistHostingAssetsOfType(CLOUD_SERVER);
|
||||
persistHostingAssetsOfType(MANAGED_SERVER);
|
||||
persistHostingAssetsOfType(MANAGED_WEBSPACE);
|
||||
persistHostingAssetsOfType(IPV4_NUMBER);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(99999)
|
||||
void logErrors() {
|
||||
super.logErrors();
|
||||
}
|
||||
|
||||
private void persistRecursively(final Integer key, final HsBookingItemEntity bi) {
|
||||
if (bi.getParentItem() != null) {
|
||||
persistRecursively(key, HsBookingItemEntityValidatorRegistry.validated(bi.getParentItem()));
|
||||
}
|
||||
persist(key, HsBookingItemEntityValidatorRegistry.validated(bi));
|
||||
}
|
||||
|
||||
private void persistHostingAssetsOfType(final HsHostingAssetType hsHostingAssetType) {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
hostingAssets.forEach((key, ha) -> {
|
||||
if (ha.getType() == hsHostingAssetType) {
|
||||
new HostingAssetEntitySaveProcessor(ha)
|
||||
.preprocessEntity()
|
||||
.validateEntity()
|
||||
.prepareForSave()
|
||||
.saveUsing(entity -> persist(key, entity))
|
||||
.validateContext();
|
||||
}
|
||||
}
|
||||
);
|
||||
}).assertSuccessful();
|
||||
}
|
||||
|
||||
private void importIpNumbers(final String[] header, final List<String[]> records) {
|
||||
final var columns = new Columns(header);
|
||||
records.stream()
|
||||
.map(this::trimAll)
|
||||
.map(row -> new Record(columns, row))
|
||||
.forEach(rec -> {
|
||||
final var ipNumber = HsHostingAssetEntity.builder()
|
||||
.type(IPV4_NUMBER)
|
||||
.identifier(rec.getString("inet_addr"))
|
||||
.caption(rec.getString("description"))
|
||||
.build();
|
||||
hostingAssets.put(IP_NUMBER_ID_OFFSET + rec.getInteger("inet_addr_id"), ipNumber);
|
||||
});
|
||||
}
|
||||
|
||||
private void importHives(final String[] header, final List<String[]> records) {
|
||||
final var columns = new Columns(header);
|
||||
records.stream()
|
||||
.map(this::trimAll)
|
||||
.map(row -> new Record(columns, row))
|
||||
.forEach(rec -> {
|
||||
final var hive_id = rec.getInteger("hive_id");
|
||||
final var hive = new Hive(
|
||||
hive_id,
|
||||
rec.getString("hive_name"),
|
||||
rec.getInteger("inet_addr_id"),
|
||||
new AtomicReference<>());
|
||||
hives.put(HIVE_ID_OFFSET + hive_id, hive);
|
||||
});
|
||||
}
|
||||
|
||||
private void importPackets(final String[] header, final List<String[]> records) {
|
||||
final var columns = new Columns(header);
|
||||
records.stream()
|
||||
.map(this::trimAll)
|
||||
.map(row -> new Record(columns, row))
|
||||
.forEach(rec -> {
|
||||
final var packet_id = rec.getInteger("packet_id");
|
||||
final var basepacket_code = rec.getString("basepacket_code");
|
||||
final var packet_name = rec.getString("packet_name");
|
||||
final var bp_id = rec.getInteger("bp_id");
|
||||
final var hive_id = rec.getInteger("hive_id");
|
||||
final var created = rec.getLocalDate("created");
|
||||
final var cancelled = rec.getLocalDate("cancelled");
|
||||
final var cur_inet_addr_id = rec.getInteger("cur_inet_addr_id");
|
||||
final var old_inet_addr_id = rec.getInteger("old_inet_addr_id");
|
||||
final var free = rec.getBoolean("free");
|
||||
|
||||
assertThat(old_inet_addr_id)
|
||||
.as("packet.old_inet_addr_id not supported, but is not null for " + packet_name)
|
||||
.isNull();
|
||||
|
||||
final var biType = determineBiType(basepacket_code);
|
||||
final var bookingItem = HsBookingItemEntity.builder()
|
||||
.type(biType)
|
||||
.caption("BI " + packet_name)
|
||||
.project(bookingProjects.get(bp_id))
|
||||
.validity(toPostgresDateRange(created, cancelled))
|
||||
.build();
|
||||
bookingItems.put(PACKET_ID_OFFSET + packet_id, bookingItem);
|
||||
final var haType = determineHaType(basepacket_code);
|
||||
|
||||
logError(() -> assertThat(!free || haType == MANAGED_WEBSPACE || bookingItem.getRelatedProject().getDebitor().getDefaultPrefix().equals("hsh"))
|
||||
.as("packet.free only supported for Hostsharing-Assets and ManagedWebspace in customer-ManagedServer, but is set for " + packet_name)
|
||||
.isTrue());
|
||||
|
||||
final var asset = HsHostingAssetEntity.builder()
|
||||
.isLoaded(haType == MANAGED_WEBSPACE) // this turns off identifier validation to accept former default prefixes
|
||||
.type(haType)
|
||||
.identifier(packet_name)
|
||||
.bookingItem(bookingItem)
|
||||
.caption("HA " + packet_name)
|
||||
.build();
|
||||
hostingAssets.put(PACKET_ID_OFFSET + packet_id, asset);
|
||||
if (haType == MANAGED_SERVER) {
|
||||
hive(hive_id).serverRef.set(asset);
|
||||
}
|
||||
|
||||
if (cur_inet_addr_id != null) {
|
||||
ipNumber(cur_inet_addr_id).setAssignedToAsset(asset);
|
||||
}
|
||||
});
|
||||
|
||||
// once we know all hosting assets, we can set the parentAsset for managed webspaces
|
||||
records.stream()
|
||||
.map(this::trimAll)
|
||||
.map(row -> new Record(columns, row))
|
||||
.forEach(rec -> {
|
||||
final var packet_id = rec.getInteger("packet_id");
|
||||
final var basepacket_code = rec.getString("basepacket_code");
|
||||
final var hive_id = rec.getInteger("hive_id");
|
||||
|
||||
final var haType = determineHaType(basepacket_code);
|
||||
if (haType == MANAGED_WEBSPACE) {
|
||||
final var managedWebspace = pac(packet_id);
|
||||
final var parentAsset = hive(hive_id).serverRef.get();
|
||||
managedWebspace.setParentAsset(parentAsset);
|
||||
managedWebspace.getBookingItem().setParentItem(parentAsset.getBookingItem());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void importPacketComponents(final String[] header, final List<String[]> records) {
|
||||
final var columns = new Columns(header);
|
||||
records.stream()
|
||||
.map(this::trimAll)
|
||||
.map(row -> new Record(columns, row))
|
||||
.forEach(rec -> {
|
||||
// final var packet_component_id = rec.getInteger("packet_component_id"); not needed
|
||||
final var packet_id = rec.getInteger("packet_id");
|
||||
final var quantity = rec.getInteger("quantity");
|
||||
final var basecomponent_code = rec.getString("basecomponent_code");
|
||||
// final var created = rec.getLocalDate("created"); TODO.spec: can we do without?
|
||||
// final var cancelled = rec.getLocalDate("cancelled"); TODO.spec: can we do without?
|
||||
Function<Integer, Object> convert = (v -> v);
|
||||
|
||||
final var asset = pac(packet_id);
|
||||
final var name = switch (basecomponent_code) {
|
||||
case "DAEMON" -> "Daemons";
|
||||
case "MULTI" -> "Multi";
|
||||
case "CPU" -> "CPU";
|
||||
case "RAM" -> returning("RAM", convert = v -> v/1024);
|
||||
case "QUOTA" -> returning("SSD", convert = v -> v/1024);
|
||||
case "STORAGE" -> returning("HDD", convert = v -> v/1024);
|
||||
case "TRAFFIC" -> "Traffic";
|
||||
case "OFFICE" -> returning("Online Office Server", convert = v -> v == 1);
|
||||
|
||||
case "SLABASIC" -> switch (asset.getType()) {
|
||||
case CLOUD_SERVER -> "SLA-Infrastructure";
|
||||
case MANAGED_SERVER -> "SLA-Platform";
|
||||
case MANAGED_WEBSPACE -> "SLA-Platform";
|
||||
default -> throw new IllegalArgumentException("SLABASIC not defined for " + asset.getType());
|
||||
};
|
||||
|
||||
case "SLAINFR2H" -> "SLA-Infrastructure";
|
||||
case "SLAINFR4H" -> "SLA-Infrastructure";
|
||||
case "SLAINFR8H" -> "SLA-Infrastructure";
|
||||
|
||||
case "SLAEXT24H" -> "SLA-Platform";
|
||||
|
||||
case "SLAPLAT2H" -> "SLA-Platform";
|
||||
case "SLAPLAT4H" -> "SLA-Platform";
|
||||
case "SLAPLAT8H" -> "SLA-Platform";
|
||||
|
||||
case "SLAWEB2H" -> "SLA-Web";
|
||||
case "SLAWEB4H" -> "SLA-Web";
|
||||
case "SLAWEB8H" -> "SLA-Web";
|
||||
|
||||
case "SLAMAIL2H" -> "SLA-EMail";
|
||||
case "SLAMAIL4H" -> "SLA-EMail";
|
||||
case "SLAMAIL8H" -> "SLA-EMail";
|
||||
|
||||
case "SLAMARIA2H" -> "SLA-Maria";
|
||||
case "SLAMARIA4H" -> "SLA-Maria";
|
||||
case "SLAMARIA8H" -> "SLA-Maria";
|
||||
|
||||
case "SLAPGSQL2H" -> "SLA-PgSQL";
|
||||
case "SLAPGSQL4H" -> "SLA-PgSQL";
|
||||
case "SLAPGSQL8H" -> "SLA-PgSQL";
|
||||
|
||||
case "SLAOFFIC2H" -> "SLA-Office";
|
||||
case "SLAOFFIC4H" -> "SLA-Office";
|
||||
case "SLAOFFIC8H" -> "SLA-Office";
|
||||
|
||||
case "BANDWIDTH" -> "Bandwidth";
|
||||
default -> throw new IllegalArgumentException("unknown basecomponent_code: " + basecomponent_code);
|
||||
};
|
||||
|
||||
if (name.equals("SLA-Infrastructure")) {
|
||||
final var slaValue = switch (basecomponent_code) {
|
||||
case "SLABASIC" -> "BASIC";
|
||||
case "SLAINFR2H" -> "EXT2H";
|
||||
case "SLAINFR4H" -> "EXT4H";
|
||||
case "SLAINFR8H" -> "EXT8H";
|
||||
default -> throw new IllegalArgumentException("unknown basecomponent_code: " + basecomponent_code);
|
||||
};
|
||||
asset.getBookingItem().getResources().put(name, slaValue);
|
||||
} else if (name.equals("SLA-Platform")) {
|
||||
final var slaValue = switch (basecomponent_code) {
|
||||
case "SLABASIC" -> "BASIC";
|
||||
case "SLAEXT24H" -> "EXT24H";
|
||||
case "SLAPLAT2H" -> "EXT2H";
|
||||
case "SLAPLAT4H" -> "EXT4H";
|
||||
case "SLAPLAT8H" -> "EXT8H";
|
||||
default -> throw new IllegalArgumentException("unknown basecomponent_code: " + basecomponent_code);
|
||||
};
|
||||
if ( ofNullable(asset.getBookingItem().getResources().get(name)).map("BASIC"::equals).orElse(true) ) {
|
||||
asset.getBookingItem().getResources().put(name, slaValue);
|
||||
}
|
||||
} else if (name.startsWith("SLA")) {
|
||||
asset.getBookingItem().getResources().put(name, true);
|
||||
} else if (quantity > 0) {
|
||||
asset.getBookingItem().getResources().put(name, convert.apply(quantity));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
<V> V returning(final V value, final Object... assignments) {
|
||||
return value;
|
||||
}
|
||||
|
||||
private static @NotNull HsBookingItemType determineBiType(final String basepacket_code) {
|
||||
return switch (basepacket_code) {
|
||||
case "SRV/CLD" -> HsBookingItemType.CLOUD_SERVER;
|
||||
case "SRV/MGD" -> HsBookingItemType.MANAGED_SERVER;
|
||||
case "PAC/WEB" -> HsBookingItemType.MANAGED_WEBSPACE;
|
||||
default -> throw new IllegalArgumentException(
|
||||
"unknown basepacket_code: " + basepacket_code);
|
||||
};
|
||||
}
|
||||
|
||||
private static @NotNull HsHostingAssetType determineHaType(final String basepacket_code) {
|
||||
return switch (basepacket_code) {
|
||||
case "SRV/CLD" -> CLOUD_SERVER;
|
||||
case "SRV/MGD" -> MANAGED_SERVER;
|
||||
case "PAC/WEB" -> MANAGED_WEBSPACE;
|
||||
default -> throw new IllegalArgumentException(
|
||||
"unknown basepacket_code: " + basepacket_code);
|
||||
};
|
||||
}
|
||||
|
||||
private static HsHostingAssetEntity ipNumber(final Integer inet_addr_id) {
|
||||
return inet_addr_id != null ? hostingAssets.get(IP_NUMBER_ID_OFFSET + inet_addr_id) : null;
|
||||
}
|
||||
|
||||
private static Hive hive(final Integer hive_id) {
|
||||
return hive_id != null ? hives.get(HIVE_ID_OFFSET + hive_id) : null;
|
||||
}
|
||||
|
||||
private static HsHostingAssetEntity pac(final Integer packet_id) {
|
||||
return packet_id != null ? hostingAssets.get(PACKET_ID_OFFSET + packet_id) : null;
|
||||
}
|
||||
|
||||
private String firstOfEachType(
|
||||
final int maxCount,
|
||||
final HsHostingAssetType... types) {
|
||||
return toFormattedString(stream(types)
|
||||
.flatMap(t ->
|
||||
hostingAssets.entrySet().stream()
|
||||
.filter(hae -> hae.getValue().getType() == t)
|
||||
.limit(maxCount)
|
||||
)
|
||||
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||
}
|
||||
|
||||
private String firstOfEachType(
|
||||
final int maxCount,
|
||||
final HsBookingItemType... types) {
|
||||
return toFormattedString(stream(types)
|
||||
.flatMap(t ->
|
||||
bookingItems.entrySet().stream()
|
||||
.filter(bie -> bie.getValue().getType() == t)
|
||||
.limit(maxCount)
|
||||
)
|
||||
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||
}
|
||||
|
||||
private Map<Integer, Object> first(
|
||||
final int maxCount,
|
||||
final Map<Integer, ?> entities) {
|
||||
return entities.entrySet().stream()
|
||||
.limit(maxCount)
|
||||
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assumeThatWeAreExplicitlyImportingOfficeData() {
|
||||
assumeThat(false).isTrue();
|
||||
}
|
||||
|
||||
protected static boolean isImportingControlledTestData() {
|
||||
return MIGRATION_DATA_PATH.equals(TEST_DATA_MIGRATION_DATA_PATH);
|
||||
}
|
||||
|
||||
protected static void assumeThatWeAreImportingControlledTestData() {
|
||||
assumeThat(isImportingControlledTestData()).isTrue();
|
||||
}
|
||||
}
|
@ -1,10 +1,6 @@
|
||||
package net.hostsharing.hsadminng.hs.office.migration;
|
||||
package net.hostsharing.hsadminng.hs.migration;
|
||||
|
||||
import com.opencsv.CSVParserBuilder;
|
||||
import com.opencsv.CSVReader;
|
||||
import com.opencsv.CSVReaderBuilder;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.ContextBasedTest;
|
||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionEntity;
|
||||
@ -26,34 +22,17 @@ import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
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.Value;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.annotation.Commit;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.io.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.lang.Boolean.parseBoolean;
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
@ -96,9 +75,9 @@ import static org.assertj.core.api.Fail.fail;
|
||||
|
||||
* To finally import the office data, run:
|
||||
*
|
||||
* import-office-tables # comes from .aliases file and uses .environment
|
||||
* gw-importOfficeTables # comes from .aliases file and uses .environment
|
||||
*/
|
||||
@Tag("import")
|
||||
@Tag("importOfficeData")
|
||||
@DataJpaTest(properties = {
|
||||
"spring.datasource.url=${HSADMINNG_POSTGRES_JDBC_URL:jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers}",
|
||||
"spring.datasource.username=${HSADMINNG_POSTGRES_ADMIN_USERNAME:ADMIN}",
|
||||
@ -109,7 +88,7 @@ import static org.assertj.core.api.Fail.fail;
|
||||
@Import({ Context.class, JpaAttempt.class })
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@ExtendWith(OrderedDependedTestsExtension.class)
|
||||
public class ImportOfficeData extends ContextBasedTest {
|
||||
public class ImportOfficeData extends CsvDataImport {
|
||||
|
||||
private static final String[] SUBSCRIBER_ROLES = new String[] {
|
||||
"subscriber:operations-discussion",
|
||||
@ -123,15 +102,16 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
new String[]{"partner", "vip-contact", "ex-partner", "billing", "contractual", "operation"},
|
||||
SUBSCRIBER_ROLES);
|
||||
|
||||
// at least as the number of lines in business-partners.csv from test-data, but less than real data partner count
|
||||
// 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 String MIGRATION_DATA_PATH = ofNullable(System.getenv("HSADMINNG_MIGRATION_DATA_PATH")).orElse("migration") + "/";
|
||||
|
||||
static int relationId = 2000000;
|
||||
|
||||
private static final List<Integer> IGNORE_BUSINESS_PARTNERS = Arrays.asList(
|
||||
512167, // 11139, partner without contractual contact
|
||||
512170, // 11142, partner without contractual contact
|
||||
511725, // 10764, partner without contractual contact
|
||||
// 512171, // 11143, partner without partner contact -- exc
|
||||
-1
|
||||
);
|
||||
|
||||
@ -140,44 +120,23 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
-1
|
||||
);
|
||||
|
||||
@Value("${spring.datasource.url}")
|
||||
private String jdbcUrl;
|
||||
static Map<Integer, HsOfficeContactEntity> contacts = new WriteOnceMap<>();
|
||||
static Map<Integer, HsOfficePersonEntity> persons = new WriteOnceMap<>();
|
||||
static Map<Integer, HsOfficePartnerEntity> partners = new WriteOnceMap<>();
|
||||
static Map<Integer, HsOfficeDebitorEntity> debitors = new WriteOnceMap<>();
|
||||
static Map<Integer, HsOfficeMembershipEntity> memberships = new WriteOnceMap<>();
|
||||
|
||||
@Value("${spring.datasource.username}")
|
||||
private String postgresAdminUser;
|
||||
|
||||
@Value("${hsadminng.superuser}")
|
||||
private String rbacSuperuser;
|
||||
|
||||
private static Map<Integer, HsOfficeContactEntity> contacts = new WriteOnceMap<>();
|
||||
private static Map<Integer, HsOfficePersonEntity> persons = new WriteOnceMap<>();
|
||||
private static Map<Integer, HsOfficePartnerEntity> partners = new WriteOnceMap<>();
|
||||
private static Map<Integer, HsOfficeDebitorEntity> debitors = new WriteOnceMap<>();
|
||||
private static Map<Integer, HsOfficeMembershipEntity> memberships = new WriteOnceMap<>();
|
||||
|
||||
private static Map<Integer, HsOfficeRelationEntity> relations = new WriteOnceMap<>();
|
||||
private static Map<Integer, HsOfficeSepaMandateEntity> sepaMandates = new WriteOnceMap<>();
|
||||
private static Map<Integer, HsOfficeBankAccountEntity> bankAccounts = new WriteOnceMap<>();
|
||||
private static Map<Integer, HsOfficeCoopSharesTransactionEntity> coopShares = new WriteOnceMap<>();
|
||||
private static Map<Integer, HsOfficeCoopAssetsTransactionEntity> coopAssets = new WriteOnceMap<>();
|
||||
|
||||
@PersistenceContext
|
||||
EntityManager em;
|
||||
|
||||
@Autowired
|
||||
TransactionTemplate txTemplate;
|
||||
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
@MockBean
|
||||
HttpServletRequest request;
|
||||
static Map<Integer, HsOfficeRelationEntity> relations = new WriteOnceMap<>();
|
||||
static Map<Integer, HsOfficeSepaMandateEntity> sepaMandates = new WriteOnceMap<>();
|
||||
static Map<Integer, HsOfficeBankAccountEntity> bankAccounts = new WriteOnceMap<>();
|
||||
static Map<Integer, HsOfficeCoopSharesTransactionEntity> coopShares = new WriteOnceMap<>();
|
||||
static Map<Integer, HsOfficeCoopAssetsTransactionEntity> coopAssets = new WriteOnceMap<>();
|
||||
|
||||
@Test
|
||||
@Order(1010)
|
||||
void importBusinessPartners() {
|
||||
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "business-partners.csv")) {
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/office/business_partners.csv")) {
|
||||
final var lines = readAllLines(reader);
|
||||
importBusinessPartners(justHeader(lines), withoutHeader(lines));
|
||||
} catch (Exception e) {
|
||||
@ -193,28 +152,39 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
// no contacts yet => mostly null values
|
||||
assertThat(toFormattedString(partners)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
17=partner(P-10017: null null, null),
|
||||
20=partner(P-10020: null null, null),
|
||||
22=partner(P-11022: null null, null),
|
||||
90=partner(P-19090: null null, null),
|
||||
99=partner(P-19999: null null, null)
|
||||
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(toFormattedString(contacts)).isEqualTo("{}");
|
||||
assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
17=debitor(D-1001700: rel(anchor='null null, null', type='DEBITOR'), mih),
|
||||
20=debitor(D-1002000: rel(anchor='null null, null', type='DEBITOR'), xyz),
|
||||
22=debitor(D-1102200: rel(anchor='null null, null', type='DEBITOR'), xxx),
|
||||
90=debitor(D-1909000: rel(anchor='null null, null', type='DEBITOR'), yyy),
|
||||
99=debitor(D-1999900: rel(anchor='null null, null', type='DEBITOR'), zzz)
|
||||
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(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
17=Membership(M-1001700, P-10017, [2000-12-06,), ACTIVE),
|
||||
20=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN),
|
||||
22=Membership(M-1102200, P-11022, [2021-04-01,), ACTIVE)
|
||||
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)
|
||||
}
|
||||
""");
|
||||
}
|
||||
@ -222,8 +192,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
@Test
|
||||
@Order(1020)
|
||||
void importContacts() {
|
||||
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "contacts.csv")) {
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/office/contacts.csv")) {
|
||||
final var lines = readAllLines(reader);
|
||||
importContacts(justHeader(lines), withoutHeader(lines));
|
||||
} catch (Exception e) {
|
||||
@ -238,83 +207,151 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
|
||||
assertThat(toFormattedString(partners)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
17=partner(P-10017: NP Mellies, Michael, Herr Michael Mellies ),
|
||||
20=partner(P-10020: LP JM GmbH, Herr Philip Meyer-Contract , JM GmbH),
|
||||
22=partner(P-11022: ?? Test PS, Petra Schmidt , Test PS),
|
||||
90=partner(P-19090: NP Camus, Cecilia, Frau Cecilia Camus ),
|
||||
99=partner(P-19999: null null, null)
|
||||
100=partner(P-10003: ?? Michael Mellis, Herr Michael Mellis , Michael Mellis),
|
||||
120=partner(P-10020: LP JM GmbH, Herr Philip Meyer-Contract , JM GmbH),
|
||||
122=partner(P-11022: ?? Test PS, Petra Schmidt , Test PS),
|
||||
132=partner(P-10152: ?? Ragnar IT-Beratung, Herr Ragnar Richter , Ragnar IT-Beratung),
|
||||
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., Firma Hostmaster Hostsharing , Hostsharing e.G.),
|
||||
541=partner(P-11018: ?? Wasserwerk Südholstein, Frau Christiane Milberg , Wasserwerk Südholstein),
|
||||
542=partner(P-11019: ?? Das Perfekte Haus, Herr Richard Wiese , Das Perfekte Haus)
|
||||
}
|
||||
""");
|
||||
assertThat(toFormattedString(contacts)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
1101=contact(caption='Herr Michael Mellies ', emailAddresses='{ "main": "mih@example.org"}'),
|
||||
1200=contact(caption='JM e.K.', emailAddresses='{ "main": "jm-ex-partner@example.org"}'),
|
||||
1201=contact(caption='Frau Dr. Jenny Meyer-Billing , JM GmbH', emailAddresses='{ "main": "jm-billing@example.org"}'),
|
||||
1202=contact(caption='Herr Andrew Meyer-Operation , JM GmbH', emailAddresses='{ "main": "am-operation@example.org"}'),
|
||||
1203=contact(caption='Herr Philip Meyer-Contract , JM GmbH', emailAddresses='{ "main": "pm-partner@example.org"}'),
|
||||
1204=contact(caption='Frau Tammy Meyer-VIP , JM GmbH', emailAddresses='{ "main": "tm-vip@example.org"}'),
|
||||
1301=contact(caption='Petra Schmidt , Test PS', emailAddresses='{ "main": "ps@example.com"}'),
|
||||
1401=contact(caption='Frau Frauke Fanninga ', emailAddresses='{ "main": "ff@example.org"}'),
|
||||
1501=contact(caption='Frau Cecilia Camus ', emailAddresses='{ "main": "cc@example.org"}')
|
||||
}
|
||||
100=contact(caption='Herr Michael Mellis , Michael Mellis', emailAddresses='{ "main": "michael@Mellis.example.org"}'),
|
||||
1200=contact(caption='JM e.K.', emailAddresses='{ "main": "jm-ex-partner@example.org"}'),
|
||||
1201=contact(caption='Frau Dr. Jenny Meyer-Billing , JM GmbH', emailAddresses='{ "main": "jm-billing@example.org"}'),
|
||||
1202=contact(caption='Herr Andrew Meyer-Operation , JM GmbH', emailAddresses='{ "main": "am-operation@example.org"}'),
|
||||
1203=contact(caption='Herr Philip Meyer-Contract , JM GmbH', emailAddresses='{ "main": "pm-partner@example.org"}'),
|
||||
1204=contact(caption='Frau Tammy Meyer-VIP , JM GmbH', emailAddresses='{ "main": "tm-vip@example.org"}'),
|
||||
1301=contact(caption='Petra Schmidt , Test PS', emailAddresses='{ "main": "ps@example.com"}'),
|
||||
132=contact(caption='Herr Ragnar Richter , Ragnar IT-Beratung', 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='Firma Hostmaster Hostsharing , Hostsharing e.G.', emailAddresses='{ "main": "hostmaster@hostsharing.net"}'),
|
||||
90436=contact(caption='Frau Christiane Milberg , Wasserwerk Südholstein', emailAddresses='{ "main": "rechnung@ww-sholst.example.org"}'),
|
||||
90437=contact(caption='Herr Richard Wiese , Das Perfekte Haus', emailAddresses='{ "main": "admin@das-perfekte-haus.example.org"}'),
|
||||
90438=contact(caption='Herr Karim Metzger , Wasswerwerk Südholstein', emailAddresses='{ "main": "karim.metzger@ww-sholst.example.org"}'),
|
||||
90590=contact(caption='Herr Inhaber R. Wiese , Das Perfekte Haus', 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"}')
|
||||
}
|
||||
""");
|
||||
assertThat(toFormattedString(persons)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
1=person(personType='LP', tradeName='Hostsharing eG'),
|
||||
1101=person(personType='NP', familyName='Mellies', givenName='Michael'),
|
||||
1200=person(personType='LP', tradeName='JM e.K.'),
|
||||
1201=person(personType='LP', tradeName='JM GmbH', familyName='Meyer-Billing', givenName='Jenny'),
|
||||
1202=person(personType='LP', tradeName='JM GmbH', familyName='Meyer-Operation', givenName='Andrew'),
|
||||
1203=person(personType='LP', tradeName='JM GmbH', familyName='Meyer-Contract', givenName='Philip'),
|
||||
1204=person(personType='LP', tradeName='JM GmbH', familyName='Meyer-VIP', givenName='Tammy'),
|
||||
1301=person(personType='??', tradeName='Test PS', familyName='Schmidt', givenName='Petra'),
|
||||
1401=person(personType='NP', familyName='Fanninga', givenName='Frauke'),
|
||||
1501=person(personType='NP', familyName='Camus', givenName='Cecilia')
|
||||
}
|
||||
100=person(personType='??', tradeName='Michael Mellis', familyName='Mellis', givenName='Michael'),
|
||||
1200=person(personType='LP', tradeName='JM e.K.'),
|
||||
1201=person(personType='LP', tradeName='JM GmbH', familyName='Meyer-Billing', givenName='Jenny'),
|
||||
1202=person(personType='LP', tradeName='JM GmbH', familyName='Meyer-Operation', givenName='Andrew'),
|
||||
1203=person(personType='LP', tradeName='JM GmbH', familyName='Meyer-Contract', givenName='Philip'),
|
||||
1204=person(personType='LP', tradeName='JM GmbH', familyName='Meyer-VIP', givenName='Tammy'),
|
||||
1301=person(personType='??', tradeName='Test PS', familyName='Schmidt', givenName='Petra'),
|
||||
132=person(personType='??', tradeName='Ragnar IT-Beratung', familyName='Richter', givenName='Ragnar'),
|
||||
1401=person(personType='NP', familyName='Fanninga', givenName='Frauke'),
|
||||
1501=person(personType='NP', familyName='Camus', givenName='Cecilia'),
|
||||
212=person(personType='LP', tradeName='Hostsharing e.G.', familyName='Hostsharing', givenName='Hostmaster'),
|
||||
90436=person(personType='??', tradeName='Wasserwerk Südholstein', familyName='Milberg', givenName='Christiane'),
|
||||
90437=person(personType='??', tradeName='Das Perfekte Haus', familyName='Wiese', givenName='Richard'),
|
||||
90438=person(personType='??', tradeName='Wasswerwerk Südholstein', familyName='Metzger', givenName='Karim'),
|
||||
90590=person(personType='??', tradeName='Das Perfekte Haus', 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')
|
||||
}
|
||||
""");
|
||||
assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
17=debitor(D-1001700: rel(anchor='NP Mellies, Michael', type='DEBITOR', holder='NP Mellies, Michael'), mih),
|
||||
20=debitor(D-1002000: rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH'), xyz),
|
||||
22=debitor(D-1102200: rel(anchor='?? Test PS', type='DEBITOR', holder='?? Test PS'), xxx),
|
||||
90=debitor(D-1909000: rel(anchor='NP Camus, Cecilia', type='DEBITOR', holder='NP Camus, Cecilia'), yyy),
|
||||
99=debitor(D-1999900: rel(anchor='null null, null', type='DEBITOR'), zzz)
|
||||
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(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
17=Membership(M-1001700, P-10017, [2000-12-06,), ACTIVE),
|
||||
20=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN),
|
||||
22=Membership(M-1102200, P-11022, [2021-04-01,), ACTIVE)
|
||||
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(toFormattedString(relations)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
2000000=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||
2000001=rel(anchor='NP Mellies, Michael', type='DEBITOR', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||
2000002=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000003=rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH', contact='Frau Dr. Jenny Meyer-Billing , JM GmbH'),
|
||||
2000004=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000005=rel(anchor='?? Test PS', type='DEBITOR', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000006=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus '),
|
||||
2000007=rel(anchor='NP Camus, Cecilia', type='DEBITOR', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus '),
|
||||
2000008=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='null null, null'),
|
||||
2000009=rel(anchor='null null, null', type='DEBITOR'),
|
||||
2000010=rel(anchor='NP Mellies, Michael', type='OPERATIONS', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||
2000011=rel(anchor='NP Mellies, Michael', type='REPRESENTATIVE', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||
2000012=rel(anchor='LP JM GmbH', type='EX_PARTNER', holder='LP JM e.K.', contact='JM e.K.'),
|
||||
2000013=rel(anchor='LP JM GmbH', type='OPERATIONS', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000014=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000015=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='operations-announce', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000016=rel(anchor='LP JM GmbH', type='REPRESENTATIVE', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000017=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='members-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000018=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='customers-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000019=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Frau Tammy Meyer-VIP , JM GmbH'),
|
||||
2000020=rel(anchor='?? Test PS', type='OPERATIONS', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000021=rel(anchor='?? Test PS', type='REPRESENTATIVE', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000022=rel(anchor='NP Mellies, Michael', type='SUBSCRIBER', mark='operations-announce', holder='NP Fanninga, Frauke', contact='Frau Frauke Fanninga '),
|
||||
2000023=rel(anchor='NP Camus, Cecilia', type='OPERATIONS', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus '),
|
||||
2000024=rel(anchor='NP Camus, Cecilia', type='REPRESENTATIVE', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus ')
|
||||
2000000=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
|
||||
2000001=rel(anchor='?? Michael Mellis', type='DEBITOR', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
|
||||
2000002=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Ragnar IT-Beratung', contact='Herr Ragnar Richter , Ragnar IT-Beratung'),
|
||||
2000003=rel(anchor='?? Ragnar IT-Beratung', type='DEBITOR', holder='?? Ragnar IT-Beratung', contact='Herr Ragnar Richter , Ragnar IT-Beratung'),
|
||||
2000004=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='LP Hostsharing e.G.', contact='Firma Hostmaster Hostsharing , Hostsharing e.G.'),
|
||||
2000005=rel(anchor='LP Hostsharing e.G.', type='DEBITOR', holder='LP Hostsharing e.G.', contact='Firma Hostmaster Hostsharing , Hostsharing e.G.'),
|
||||
2000006=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Wasserwerk Südholstein', contact='Frau Christiane Milberg , Wasserwerk Südholstein'),
|
||||
2000007=rel(anchor='?? Wasserwerk Südholstein', type='DEBITOR', holder='?? Wasserwerk Südholstein', contact='Frau Christiane Milberg , Wasserwerk Südholstein'),
|
||||
2000008=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Das Perfekte Haus', contact='Herr Richard Wiese , Das Perfekte Haus'),
|
||||
2000009=rel(anchor='?? Das Perfekte Haus', type='DEBITOR', holder='?? Das Perfekte Haus', contact='Herr Inhaber R. Wiese , Das Perfekte Haus'),
|
||||
2000010=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000011=rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH', contact='Frau Dr. Jenny Meyer-Billing , JM GmbH'),
|
||||
2000012=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000013=rel(anchor='?? Test PS', type='DEBITOR', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
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', holder='LP Hostsharing e.G.', contact='Firma Hostmaster Hostsharing , Hostsharing e.G.'),
|
||||
2000019=rel(anchor='LP Hostsharing e.G.', type='REPRESENTATIVE', holder='LP Hostsharing e.G.', contact='Firma Hostmaster Hostsharing , Hostsharing e.G.'),
|
||||
2000020=rel(anchor='?? Michael Mellis', type='OPERATIONS', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
|
||||
2000021=rel(anchor='?? Michael Mellis', type='REPRESENTATIVE', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
|
||||
2000022=rel(anchor='?? Michael Mellis', type='SUBSCRIBER', mark='operations-discussion', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
|
||||
2000023=rel(anchor='?? Michael Mellis', type='SUBSCRIBER', mark='operations-announce', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
|
||||
2000024=rel(anchor='?? Michael Mellis', type='SUBSCRIBER', mark='generalversammlung', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
|
||||
2000025=rel(anchor='?? Michael Mellis', type='SUBSCRIBER', mark='members-announce', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
|
||||
2000026=rel(anchor='?? Michael Mellis', type='SUBSCRIBER', mark='members-discussion', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
|
||||
2000027=rel(anchor='?? Ragnar IT-Beratung', type='OPERATIONS', holder='?? Ragnar IT-Beratung', contact='Herr Ragnar Richter , Ragnar IT-Beratung'),
|
||||
2000028=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='operations-discussion', holder='?? Ragnar IT-Beratung', contact='Herr Ragnar Richter , Ragnar IT-Beratung'),
|
||||
2000029=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='operations-announce', holder='?? Ragnar IT-Beratung', contact='Herr Ragnar Richter , Ragnar IT-Beratung'),
|
||||
2000030=rel(anchor='LP JM GmbH', type='EX_PARTNER', holder='LP JM e.K.', contact='JM e.K.'),
|
||||
2000031=rel(anchor='LP JM GmbH', type='OPERATIONS', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000032=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000033=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='operations-announce', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||
2000034=rel(anchor='LP JM GmbH', type='REPRESENTATIVE', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000035=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='members-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000036=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='customers-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||
2000037=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Frau Tammy Meyer-VIP , JM GmbH'),
|
||||
2000038=rel(anchor='?? Test PS', type='OPERATIONS', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000039=rel(anchor='?? Test PS', type='REPRESENTATIVE', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||
2000040=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='operations-announce', holder='NP Fanninga, Frauke', contact='Frau Frauke Fanninga '),
|
||||
2000041=rel(anchor='NP Camus, Cecilia', type='OPERATIONS', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus '),
|
||||
2000042=rel(anchor='NP Camus, Cecilia', type='REPRESENTATIVE', holder='NP Camus, Cecilia', contact='Frau Cecilia Camus '),
|
||||
2000043=rel(anchor='?? Wasserwerk Südholstein', type='REPRESENTATIVE', holder='?? Wasserwerk Südholstein', contact='Frau Christiane Milberg , Wasserwerk Südholstein'),
|
||||
2000044=rel(anchor='?? Wasserwerk Südholstein', type='SUBSCRIBER', mark='generalversammlung', holder='?? Wasserwerk Südholstein', contact='Frau Christiane Milberg , Wasserwerk Südholstein'),
|
||||
2000045=rel(anchor='?? Wasserwerk Südholstein', type='SUBSCRIBER', mark='members-announce', holder='?? Wasserwerk Südholstein', contact='Frau Christiane Milberg , Wasserwerk Südholstein'),
|
||||
2000046=rel(anchor='?? Wasserwerk Südholstein', type='SUBSCRIBER', mark='members-discussion', holder='?? Wasserwerk Südholstein', contact='Frau Christiane Milberg , Wasserwerk Südholstein'),
|
||||
2000047=rel(anchor='?? Das Perfekte Haus', type='OPERATIONS', holder='?? Das Perfekte Haus', contact='Herr Richard Wiese , Das Perfekte Haus'),
|
||||
2000048=rel(anchor='?? Das Perfekte Haus', type='REPRESENTATIVE', holder='?? Das Perfekte Haus', contact='Herr Richard Wiese , Das Perfekte Haus'),
|
||||
2000049=rel(anchor='?? Das Perfekte Haus', type='SUBSCRIBER', mark='operations-discussion', holder='?? Das Perfekte Haus', contact='Herr Richard Wiese , Das Perfekte Haus'),
|
||||
2000050=rel(anchor='?? Das Perfekte Haus', type='SUBSCRIBER', mark='operations-announce', holder='?? Das Perfekte Haus', contact='Herr Richard Wiese , Das Perfekte Haus'),
|
||||
2000051=rel(anchor='?? Das Perfekte Haus', type='SUBSCRIBER', mark='generalversammlung', holder='?? Das Perfekte Haus', contact='Herr Richard Wiese , Das Perfekte Haus'),
|
||||
2000052=rel(anchor='?? Das Perfekte Haus', type='SUBSCRIBER', mark='members-announce', holder='?? Das Perfekte Haus', contact='Herr Richard Wiese , Das Perfekte Haus'),
|
||||
2000053=rel(anchor='?? Das Perfekte Haus', type='SUBSCRIBER', mark='members-discussion', holder='?? Das Perfekte Haus', contact='Herr Richard Wiese , Das Perfekte Haus'),
|
||||
2000054=rel(anchor='?? Wasserwerk Südholstein', type='OPERATIONS', holder='?? Wasswerwerk Südholstein', contact='Herr Karim Metzger , Wasswerwerk Südholstein'),
|
||||
2000055=rel(anchor='?? Wasserwerk Südholstein', type='SUBSCRIBER', mark='operations-discussion', holder='?? Wasswerwerk Südholstein', contact='Herr Karim Metzger , Wasswerwerk Südholstein'),
|
||||
2000056=rel(anchor='?? Wasserwerk Südholstein', type='SUBSCRIBER', mark='operations-announce', holder='?? Wasswerwerk Südholstein', contact='Herr Karim Metzger , Wasswerwerk Südholstein'),
|
||||
2000057=rel(anchor='?? Ragnar IT-Beratung', type='REPRESENTATIVE', holder='NP Richter, Ragnar', contact='Ragnar Richter '),
|
||||
2000058=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='generalversammlung', holder='NP Richter, Ragnar', contact='Ragnar Richter '),
|
||||
2000059=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='members-announce', holder='NP Richter, Ragnar', contact='Ragnar Richter '),
|
||||
2000060=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='members-discussion', holder='NP Richter, Ragnar', contact='Ragnar Richter '),
|
||||
2000061=rel(anchor='?? Ragnar IT-Beratung', type='OPERATIONS', holder='NP Henning, Eike', contact='Eike Henning '),
|
||||
2000062=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='operations-discussion', holder='NP Henning, Eike', contact='Eike Henning '),
|
||||
2000063=rel(anchor='?? Ragnar IT-Beratung', type='SUBSCRIBER', mark='operations-announce', holder='NP Henning, Eike', contact='Eike Henning '),
|
||||
2000064=rel(anchor='?? Ragnar IT-Beratung', type='OPERATIONS', holder='NP Henning, Jan', contact='Jan Henning ')
|
||||
}
|
||||
""");
|
||||
}
|
||||
@ -322,8 +359,9 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
@Test
|
||||
@Order(1030)
|
||||
void importSepaMandates() {
|
||||
assumeThatWeAreExplicitlyImportingOfficeData();
|
||||
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "sepa-mandates.csv")) {
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/office/sepa_mandates.csv")) {
|
||||
final var lines = readAllLines(reader);
|
||||
importSepaMandates(justHeader(lines), withoutHeader(lines));
|
||||
} catch (Exception e) {
|
||||
@ -334,20 +372,29 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
@Test
|
||||
@Order(1039)
|
||||
void verifySepaMandates() {
|
||||
assumeThatWeAreExplicitlyImportingOfficeData();
|
||||
assumeThatWeAreImportingControlledTestData();
|
||||
|
||||
assertThat(toFormattedString(bankAccounts)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
234234=bankAccount(DE37500105177419788228: holder='Michael Mellies', bic='INGDDEFFXXX'),
|
||||
235600=bankAccount(DE02300209000106531065: holder='JM e.K.', bic='CMCIDEDD'),
|
||||
235662=bankAccount(DE49500105174516484892: holder='JM GmbH', bic='INGDDEFFXXX')
|
||||
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(toFormattedString(sepaMandates)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
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,))
|
||||
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,))
|
||||
}
|
||||
""");
|
||||
}
|
||||
@ -355,7 +402,9 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
@Test
|
||||
@Order(1040)
|
||||
void importCoopShares() {
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "share-transactions.csv")) {
|
||||
assumeThatWeAreExplicitlyImportingOfficeData();
|
||||
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/office/share_transactions.csv")) {
|
||||
final var lines = readAllLines(reader);
|
||||
importCoopShares(justHeader(lines), withoutHeader(lines));
|
||||
} catch (Exception e) {
|
||||
@ -366,23 +415,32 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
@Test
|
||||
@Order(1041)
|
||||
void verifyCoopShares() {
|
||||
assumeThatWeAreExplicitlyImportingOfficeData();
|
||||
assumeThatWeAreImportingControlledTestData();
|
||||
|
||||
assertThat(toFormattedString(coopShares)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
33443=CoopShareTransaction(M-1001700: 2000-12-06, SUBSCRIPTION, 20, 1001700, initial share subscription),
|
||||
33451=CoopShareTransaction(M-1002000: 2000-12-06, SUBSCRIPTION, 2, 1002000, initial share subscription),
|
||||
33701=CoopShareTransaction(M-1001700: 2005-01-10, SUBSCRIPTION, 40, 1001700, increase),
|
||||
33810=CoopShareTransaction(M-1002000: 2016-12-31, CANCELLATION, 22, 1002000, membership ended)
|
||||
}
|
||||
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() {
|
||||
assumeThatWeAreExplicitlyImportingOfficeData();
|
||||
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "asset-transactions.csv")) {
|
||||
try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/office/asset_transactions.csv")) {
|
||||
final var lines = readAllLines(reader);
|
||||
importCoopAssets(justHeader(lines), withoutHeader(lines));
|
||||
} catch (Exception e) {
|
||||
@ -393,20 +451,29 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
@Test
|
||||
@Order(1059)
|
||||
void verifyCoopAssets() {
|
||||
assumeThatWeAreExplicitlyImportingOfficeData();
|
||||
assumeThatWeAreImportingControlledTestData();
|
||||
|
||||
assertThat(toFormattedString(coopAssets)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
30000=CoopAssetsTransaction(M-1001700: 2000-12-06, DEPOSIT, 1280.00, 1001700, for subscription A),
|
||||
31000=CoopAssetsTransaction(M-1002000: 2000-12-06, DEPOSIT, 128.00, 1002000, for subscription B),
|
||||
32000=CoopAssetsTransaction(M-1001700: 2005-01-10, DEPOSIT, 2560.00, 1001700, for subscription C),
|
||||
33001=CoopAssetsTransaction(M-1001700: 2005-01-10, TRANSFER, -512.00, 1001700, for transfer to 10),
|
||||
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, ADJUSTMENT, -128.00, 1909000, chargeback for subscription E, M-1909000:DEP:+128.00)
|
||||
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),
|
||||
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, ADJUSTMENT, -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)
|
||||
}
|
||||
""");
|
||||
}
|
||||
@ -414,13 +481,18 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
@Test
|
||||
@Order(1099)
|
||||
void verifyMemberships() {
|
||||
assumeThatWeAreExplicitlyImportingOfficeData();
|
||||
assumeThatWeAreImportingControlledTestData();
|
||||
|
||||
assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
17=Membership(M-1001700, P-10017, [2000-12-06,), ACTIVE),
|
||||
20=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN),
|
||||
22=Membership(M-1102200, P-11022, [2021-04-01,), ACTIVE),
|
||||
90=Membership(M-1909000, P-19090, empty, INVALID)
|
||||
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)
|
||||
}
|
||||
""");
|
||||
}
|
||||
@ -431,11 +503,11 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
partners.forEach((id, p) -> {
|
||||
final var partnerRel = p.getPartnerRel();
|
||||
assertThat(partnerRel).describedAs("partner " + id + " without partnerRel").isNotNull();
|
||||
if ( id != 99 ) {
|
||||
assertThat(partnerRel.getContact()).describedAs("partner " + id + " without partnerRel.contact").isNotNull();
|
||||
assertThat(partnerRel.getContact().getCaption()).describedAs("partner " + id + " without valid partnerRel.contact").isNotNull();
|
||||
assertThat(partnerRel.getHolder()).describedAs("partner " + id + " without partnerRel.relHolder").isNotNull();
|
||||
assertThat(partnerRel.getHolder().getPersonType()).describedAs("partner " + id + " without valid partnerRel.relHolder").isNotNull();
|
||||
if ( id != 199 ) {
|
||||
logError( () -> assertThat(partnerRel.getContact()).describedAs("partner " + id + " without partnerRel.contact").isNotNull());
|
||||
logError( () -> assertThat(partnerRel.getContact().getCaption()).describedAs("partner " + id + " without valid partnerRel.contact").isNotNull());
|
||||
logError( () -> assertThat(partnerRel.getHolder()).describedAs("partner " + id + " without partnerRel.relHolder").isNotNull());
|
||||
logError( () -> assertThat(partnerRel.getHolder().getPersonType()).describedAs("partner " + id + " without valid partnerRel.relHolder").isNotNull());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -523,13 +595,29 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(9000)
|
||||
@Commit
|
||||
void persistEntities() {
|
||||
@Order(3005)
|
||||
void removeEmptyPersons() {
|
||||
// avoid a error when persisting the deliberately invalid partner entry #99
|
||||
final var idsToRemove = new HashSet<Integer>();
|
||||
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));
|
||||
|
||||
System.out.println("PERSISTING to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'");
|
||||
assumeThatWeAreImportingControlledTestData();
|
||||
assertThat(idsToRemove.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(9000)
|
||||
void persistOfficeEntities() {
|
||||
|
||||
System.out.println("PERSISTING office data to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'");
|
||||
deleteTestDataFromHsOfficeTables();
|
||||
resetFromHsOfficeSequences();
|
||||
resetHsOfficeSequences();
|
||||
deleteFromTestTables();
|
||||
deleteFromRbacTables();
|
||||
|
||||
@ -542,6 +630,8 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
persons.forEach(this::persist);
|
||||
relations.forEach( (id, rel) -> this.persist(id, rel.getAnchor()) );
|
||||
relations.forEach( (id, rel) -> this.persist(id, rel.getHolder()) );
|
||||
}).assertSuccessful();
|
||||
|
||||
jpaAttempt.transacted(() -> {
|
||||
@ -602,18 +692,8 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
|
||||
}
|
||||
|
||||
private void persist(final Integer id, final RbacObject entity) {
|
||||
try {
|
||||
//System.out.println("persisting #" + entity.hashCode() + ": " + entity);
|
||||
em.persist(entity);
|
||||
// uncomment for debugging purposes
|
||||
// em.flush();
|
||||
// System.out.println("persisted #" + entity.hashCode() + " as " + entity.getUuid());
|
||||
} catch (Exception exc) {
|
||||
System.err.println("failed to persist #" + entity.hashCode() + ": " + entity);
|
||||
System.err.println(exc);
|
||||
}
|
||||
|
||||
protected void assumeThatWeAreExplicitlyImportingOfficeData() {
|
||||
// not throwing AssumptionException
|
||||
}
|
||||
|
||||
private static boolean isImportingControlledTestData() {
|
||||
@ -624,62 +704,6 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
assumeThat(partners.size()).isLessThanOrEqualTo(MAX_NUMBER_OF_TEST_DATA_PARTNERS);
|
||||
}
|
||||
|
||||
private void deleteTestDataFromHsOfficeTables() {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
em.createNativeQuery("delete from hs_hosting_asset where true").executeUpdate();
|
||||
em.createNativeQuery("delete from hs_booking_item where true").executeUpdate();
|
||||
em.createNativeQuery("delete from hs_booking_project 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_coopsharestransaction 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_sepamandate 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_bankaccount 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_relation where true").executeUpdate();
|
||||
em.createNativeQuery("delete from hs_office_contact where true").executeUpdate();
|
||||
em.createNativeQuery("delete from hs_office_person where true").executeUpdate();
|
||||
}).assertSuccessful();
|
||||
}
|
||||
|
||||
private void resetFromHsOfficeSequences() {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
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 public.hs_office_coopsharestransaction_legacy_id_seq restart with 1000000000;")
|
||||
.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() {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
em.createNativeQuery("delete from test_domain where true").executeUpdate();
|
||||
em.createNativeQuery("delete from test_package where true").executeUpdate();
|
||||
em.createNativeQuery("delete from test_customer where true").executeUpdate();
|
||||
}).assertSuccessful();
|
||||
}
|
||||
|
||||
private void deleteFromRbacTables() {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context(rbacSuperuser);
|
||||
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_context where true").executeUpdate();
|
||||
}).assertSuccessful();
|
||||
}
|
||||
|
||||
private <E extends RbacObject> void updateLegacyIds(
|
||||
Map<Integer, E> entities,
|
||||
final String legacyIdTable,
|
||||
@ -698,59 +722,25 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
);
|
||||
}
|
||||
|
||||
public List<String[]> readAllLines(Reader reader) throws Exception {
|
||||
|
||||
final var parser = new CSVParserBuilder()
|
||||
.withSeparator(';')
|
||||
.withQuoteChar('"')
|
||||
.build();
|
||||
|
||||
final var filteredReader = skippingEmptyAndCommentLines(reader);
|
||||
try (CSVReader csvReader = new CSVReaderBuilder(filteredReader)
|
||||
.withCSVParser(parser)
|
||||
.build()) {
|
||||
return csvReader.readAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static Reader skippingEmptyAndCommentLines(Reader reader) throws IOException {
|
||||
try (var bufferedReader = new BufferedReader(reader);
|
||||
StringWriter writer = new StringWriter()) {
|
||||
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
if (!line.isBlank() && !line.startsWith("#")) {
|
||||
writer.write(line);
|
||||
writer.write("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return new StringReader(writer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void importBusinessPartners(final String[] header, final List<String[]> records) {
|
||||
|
||||
final var columns = new Columns(header);
|
||||
|
||||
final var mandant = HsOfficePersonEntity.builder()
|
||||
.personType(HsOfficePersonType.LEGAL_PERSON)
|
||||
.tradeName("Hostsharing eG")
|
||||
.build();
|
||||
persons.put(1, mandant);
|
||||
|
||||
records.stream()
|
||||
.map(this::trimAll)
|
||||
.map(row -> new Record(columns, row))
|
||||
.forEach(rec -> {
|
||||
if (this.IGNORE_BUSINESS_PARTNERS.contains(rec.getInteger("bp_id"))) {
|
||||
final Integer bpId = rec.getInteger("bp_id");
|
||||
if (IGNORE_BUSINESS_PARTNERS.contains(bpId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var person = HsOfficePersonEntity.builder().build();
|
||||
|
||||
final var partnerRel = addRelation(
|
||||
HsOfficeRelationType.PARTNER, mandant, person,
|
||||
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
|
||||
);
|
||||
|
||||
@ -759,7 +749,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
.details(HsOfficePartnerDetailsEntity.builder().build())
|
||||
.partnerRel(partnerRel)
|
||||
.build();
|
||||
partners.put(rec.getInteger("bp_id"), partner);
|
||||
partners.put(bpId, partner);
|
||||
|
||||
final var debitorRel = addRelation(
|
||||
HsOfficeRelationType.DEBITOR, partnerRel.getHolder(), // partner person
|
||||
@ -777,7 +767,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
.vatBusiness("GROSS".equals(rec.getString("indicator_vat"))) // TODO: remove
|
||||
.vatId(rec.getString("uid_vat"))
|
||||
.build();
|
||||
debitors.put(rec.getInteger("bp_id"), debitor);
|
||||
debitors.put(bpId, debitor);
|
||||
|
||||
if (isNotBlank(rec.getString("member_since"))) {
|
||||
assertThat(rec.getInteger("member_id")).isEqualTo(partner.getPartnerNumber());
|
||||
@ -793,7 +783,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
? HsOfficeMembershipStatus.ACTIVE
|
||||
: HsOfficeMembershipStatus.UNKNOWN)
|
||||
.build();
|
||||
memberships.put(rec.getInteger("bp_id"), membership);
|
||||
memberships.put(bpId, membership);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -807,6 +797,10 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
.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));
|
||||
|
||||
@ -958,10 +952,10 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
final var contactId = rec.getInteger("contact_id");
|
||||
final var bpId = rec.getInteger("bp_id");
|
||||
|
||||
if (this.IGNORE_CONTACTS.contains(contactId)) {
|
||||
if (IGNORE_CONTACTS.contains(contactId)) {
|
||||
return;
|
||||
}
|
||||
if (this.IGNORE_BUSINESS_PARTNERS.contains(bpId)) {
|
||||
if (IGNORE_BUSINESS_PARTNERS.contains(bpId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1019,6 +1013,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
});
|
||||
|
||||
assertNoMissingContractualRelations();
|
||||
useHostsharingAsPartnerAnchor();
|
||||
}
|
||||
|
||||
private static void assertNoMissingContractualRelations() {
|
||||
@ -1038,6 +1033,16 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
}
|
||||
}
|
||||
|
||||
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 + ",");
|
||||
@ -1128,27 +1133,6 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
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())
|
||||
.map(e -> e.replaceAll("\n ", " ").replace("\n", ""))
|
||||
.collect(Collectors.joining(",\n")) +
|
||||
"\n}\n";
|
||||
}
|
||||
|
||||
private String[] trimAll(final String[] record) {
|
||||
for (int i = 0; i < record.length; ++i) {
|
||||
if (record[i] != null) {
|
||||
record[i] = record[i].trim();
|
||||
}
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
private Map<String, String> toPhoneNumbers(final Record rec) {
|
||||
final var phoneNumbers = new LinkedHashMap<String, String>();
|
||||
if (isNotBlank(rec.getString("phone_private")))
|
||||
@ -1218,104 +1202,4 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
private String toName(final String salut, final String title, final String firstname, final String lastname) {
|
||||
return toCaption(salut, title, firstname, lastname, null);
|
||||
}
|
||||
|
||||
private Reader resourceReader(@NotNull final String resourcePath) {
|
||||
return new InputStreamReader(requireNonNull(getClass().getClassLoader().getResourceAsStream(resourcePath)));
|
||||
}
|
||||
|
||||
private static String[] justHeader(final List<String[]> lines) {
|
||||
return stream(lines.getFirst()).map(String::trim).toArray(String[]::new);
|
||||
}
|
||||
|
||||
private List<String[]> withoutHeader(final List<String[]> records) {
|
||||
return records.subList(1, records.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Columns {
|
||||
|
||||
private final List<String> columnNames;
|
||||
|
||||
public Columns(final String[] header) {
|
||||
columnNames = List.of(header);
|
||||
}
|
||||
|
||||
int indexOf(final String columnName) {
|
||||
int index = columnNames.indexOf(columnName);
|
||||
if (index < 0) {
|
||||
throw new RuntimeException("column name '" + columnName + "' not found in: " + columnNames);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
class Record {
|
||||
|
||||
private final Columns columns;
|
||||
private final String[] row;
|
||||
|
||||
public Record(final Columns columns, final String[] row) {
|
||||
this.columns = columns;
|
||||
this.row = row;
|
||||
}
|
||||
|
||||
String getString(final String columnName) {
|
||||
return row[columns.indexOf(columnName)];
|
||||
}
|
||||
|
||||
boolean isEmpty(final String columnName) {
|
||||
final String value = getString(columnName);
|
||||
return value == null || value.isBlank();
|
||||
}
|
||||
|
||||
boolean getBoolean(final String columnName) {
|
||||
final String value = getString(columnName);
|
||||
return isNotBlank(value) &&
|
||||
( parseBoolean(value.trim()) || value.trim().startsWith("t"));
|
||||
}
|
||||
|
||||
Integer getInteger(final String columnName) {
|
||||
final String value = getString(columnName);
|
||||
return isNotBlank(value) ? Integer.parseInt(value.trim()) : 0;
|
||||
}
|
||||
|
||||
BigDecimal getBigDecimal(final String columnName) {
|
||||
final String value = getString(columnName);
|
||||
if (isNotBlank(value)) {
|
||||
return new BigDecimal(value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
LocalDate getLocalDate(final String columnName) {
|
||||
final String dateString = getString(columnName);
|
||||
if (isNotBlank(dateString)) {
|
||||
return LocalDate.parse(dateString);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class OrderedDependedTestsExtension implements TestWatcher, BeforeEachCallback {
|
||||
|
||||
private static boolean previousTestsPassed = true;
|
||||
|
||||
public void testFailed(ExtensionContext context, Throwable cause) {
|
||||
previousTestsPassed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeEach(final ExtensionContext extensionContext) {
|
||||
assumeThat(previousTestsPassed).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
class WriteOnceMap<K, V> extends TreeMap<K, V> {
|
||||
|
||||
@Override
|
||||
public V put(final K k, final V v) {
|
||||
assertThat(containsKey(k)).describedAs("overwriting " + get(k) + " index " + k + " with " + v).isFalse();
|
||||
return super.put(k, v);
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
member_asset_id; bp_id; date; action; amount; comment
|
||||
30000; 17; 2000-12-06; PAYMENT; 1280.00; for subscription A
|
||||
31000; 20; 2000-12-06; PAYMENT; 128.00; for subscription B
|
||||
32000; 17; 2005-01-10; PAYMENT; 2560.00; for subscription C
|
||||
33001; 17; 2005-01-10; HANDOVER; -512.00; for transfer to 10
|
||||
33002; 20; 2005-01-10; ADOPTION; 512.00; for transfer from 7
|
||||
34001; 20; 2016-12-31; CLEARING; -8.00; for cancellation D
|
||||
34002; 20; 2016-12-31; PAYBACK; -100.00; for cancellation D
|
||||
34003; 20; 2016-12-31; LOSS; -20.00; for cancellation D
|
||||
35001; 90; 2024-01-15; PAYMENT; 128.00; for subscription E
|
||||
35002; 90; 2024-01-20; ADJUSTMENT;-128.00; chargeback for subscription E
|
|
@ -1,6 +0,0 @@
|
||||
bp_id;member_id;member_code;member_since;member_until;member_role;author_contract;nondisc_contract;free;exempt_vat;indicator_vat;uid_vat
|
||||
17;10017;hsh00-mih;2000-12-06;;Aufsichtsrat;2006-10-15;2001-10-15;false;false;NET;DE-VAT-007
|
||||
20;10020;hsh00-xyz;2000-12-06;2015-12-31;;;;false;false;GROSS;
|
||||
22;11022;hsh00-xxx;2021-04-01;;;;;true;true;GROSS;
|
||||
90;19090;hsh00-yyy;;;;;;true;true;GROSS;
|
||||
99;19999;hsh00-zzz;;;;;;false;false;GROSS;
|
|
@ -1,20 +0,0 @@
|
||||
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, implizites contractual
|
||||
1101; 17; Herr; Michael; Mellies; ; ; ; Kleine Freiheit 50; 26524; Hage; DE; ; +49 4931 123456; +49 1522 123456;; mih@example.org; partner,contractual,billing,operation
|
||||
|
||||
# eine juristische Person mit drei separaten Ansprechpartnern, vip-contact und ex-partner
|
||||
1200; 20;; ; ; ; JM e.K.;; Wiesenweg 15; 12335; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; jm-ex-partner@example.org; ex-partner
|
||||
1201; 20; Frau; Jenny; Meyer-Billing; Dr.; JM GmbH;; Waldweg 5; 11001; Berlin; DE; +49 30 7777777; +49 30 1111111; ; +49 30 2222222; jm-billing@example.org; billing
|
||||
1202; 20; Herr; Andrew; Meyer-Operation; ; JM GmbH;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 3333333; ; +49 30 4444444; am-operation@example.org; operation,vip-contact,subscriber:operations-announce
|
||||
1203; 20; Herr; Philip; Meyer-Contract; ; JM GmbH;; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; pm-partner@example.org; partner,contractual,subscriber:members-announce,subscriber:customers-announce
|
||||
1204; 20; Frau; Tammy; Meyer-VIP; ; JM GmbH;; Waldweg 5; 11001; Berlin; DE; +49 30 999999; +49 30 999999; ; +49 30 6666666; tm-vip@example.org; vip-contact
|
||||
|
||||
# eine juristische Person mit nur einem Ansprechpartner und explizitem contractual
|
||||
1301; 22; ; Petra; Schmidt; ; Test PS;; ; ; ; ; ; ; ; ; ps@example.com; partner,billing,contractual,operation
|
||||
|
||||
# eine natürliche Person, die nur Subscriber ist
|
||||
1401; 17; Frau; Frauke; Fanninga; ; ; ; Am Walde 1; 29456; Hitzacker; DE; ; ; ;; ff@example.org; subscriber:operations-announce
|
||||
|
||||
# eine natürliche Person als Partner
|
||||
1501; 90; Frau; Cecilia; Camus; ; ; ; Rue d'Avignion 60; 45000; Orléans; FR; ; ; ;; cc@example.org; partner,contractual,billing,operation
|
|
@ -20,58 +20,58 @@ dump() {
|
||||
dump "select bp_id, member_id, member_code, member_since, member_until, member_role, author_contract, nondisc_contract, free, exempt_vat, indicator_vat, uid_vat
|
||||
from business_partner
|
||||
order by bp_id" \
|
||||
"business-partners.csv"
|
||||
"office/business_partners.csv"
|
||||
|
||||
dump "select contact_id, bp_id, salut, first_name, last_name, title, firma, co, street, zipcode, city, country, phone_private, phone_office, phone_mobile, fax, email, array_to_string(array_agg(role), ',') as roles
|
||||
from contact
|
||||
left join contactrole_ref using(contact_id)
|
||||
group by contact_id
|
||||
order by contact_id" \
|
||||
"contacts.csv"
|
||||
"office/contacts.csv"
|
||||
|
||||
dump "select sepa_mandat_id, bp_id, bank_customer, bank_name, bank_iban, bank_bic, mandat_ref, mandat_signed, mandat_since, mandat_until, mandat_used
|
||||
from sepa_mandat
|
||||
order by sepa_mandat_id" \
|
||||
"sepa-mandates.csv"
|
||||
"office/sepa_mandates.csv"
|
||||
|
||||
dump "select member_asset_id, bp_id, date, action, amount, comment
|
||||
from member_asset
|
||||
WHERE bp_id NOT IN (511912)
|
||||
order by member_asset_id" \
|
||||
"asset-transactions.csv"
|
||||
"office/asset_transactions.csv"
|
||||
|
||||
dump "select member_share_id, bp_id, date, action, quantity, comment
|
||||
from member_share
|
||||
WHERE bp_id NOT IN (511912)
|
||||
order by member_share_id" \
|
||||
"share-transactions.csv"
|
||||
"office/share_transactions.csv"
|
||||
|
||||
dump "select inet_addr_id, inet_addr, description
|
||||
from inet_addr
|
||||
order by inet_addr_id" \
|
||||
"inet_addr.csv"
|
||||
"hosting/inet_addr.csv"
|
||||
|
||||
dump "select hive_id, hive_name, inet_addr_id, description
|
||||
from hive
|
||||
order by hive_id" \
|
||||
"hive.csv"
|
||||
"hosting/hive.csv"
|
||||
|
||||
dump "select packet_id, basepacket_code, packet_name, bp_id, hive_id, created, cancelled, cur_inet_addr_id, old_inet_addr_id, free
|
||||
from packet
|
||||
left join basepacket using (basepacket_id)
|
||||
order by packet_id" \
|
||||
"packet.csv"
|
||||
"hosting/packet.csv"
|
||||
|
||||
dump "select packet_component_id, packet_id, quantity, basecomponent_code, created, cancelled
|
||||
from packet_component
|
||||
left join basecomponent using (basecomponent_id)
|
||||
order by packet_component_id" \
|
||||
"packet_component.csv"
|
||||
"hosting/packet_component.csv"
|
||||
|
||||
dump "select unixuser_id, name, comment, shell, homedir, locked, packet_id, userid, quota_softlimit, quota_hardlimit, storage_softlimit, storage_hardlimit
|
||||
from unixuser
|
||||
order by unixuser_id" \
|
||||
"unixuser.csv"
|
||||
"hosting/unixuser.csv"
|
||||
|
||||
# weil das fehlt, muss group by komplett gesetzt werden: alter table domain add constraint PK_domain primary key (domain_id);
|
||||
dump "select domain_id, domain_name, domain_since, domain_dns_master, domain_owner, valid_subdomain_names, passenger_python, passenger_nodejs, passenger_ruby, fcgi_php_bin, array_to_string(array_agg(domain_option_name), ',') as domainoptions
|
||||
@ -80,7 +80,7 @@ dump "select domain_id, domain_name, domain_since, domain_dns_master, domain_own
|
||||
left join domain_option using (domain_option_id)
|
||||
group by domain.domain_id, domain.domain_name, domain_since, domain_dns_master, domain_owner, valid_subdomain_names, passenger_python, passenger_nodejs, passenger_ruby, fcgi_php_bin
|
||||
order by domain.domain_id" \
|
||||
"domain.csv"
|
||||
"hosting/domain.csv"
|
||||
|
||||
dump "select emailaddr_id, domain_id, localpart, subdomain, target
|
||||
from emailaddr
|
||||
@ -90,14 +90,14 @@ dump "select emailaddr_id, domain_id, localpart, subdomain, target
|
||||
dump "select emailalias_id, pac_id, name, target
|
||||
from emailalias
|
||||
order by emailalias_id" \
|
||||
"emailalias.csv"
|
||||
"hosting/emailalias.csv"
|
||||
|
||||
dump "select dbuser_id, engine, packet_id, name
|
||||
from database_user
|
||||
order by dbuser_id" \
|
||||
"database_user.csv"
|
||||
"hosting/database_user.csv"
|
||||
|
||||
dump "select database_id, engine, packet_id, name, owner, encoding
|
||||
from database
|
||||
order by database_id" \
|
||||
"database.csv"
|
||||
"hosting/database.csv"
|
||||
|
26
src/test/resources/migration/hosting/hive.csv
Normal file
26
src/test/resources/migration/hosting/hive.csv
Normal file
@ -0,0 +1,26 @@
|
||||
hive_id;hive_name;inet_addr_id;description
|
||||
1;h00;358;
|
||||
2;h01;359;
|
||||
4;h02;360;
|
||||
7;h03;361;
|
||||
13;h04;430;
|
||||
14;h50;433;
|
||||
20;h05;354;
|
||||
21;h06;355;
|
||||
22;h07;357;
|
||||
28;h60;363;
|
||||
31;h63;431;
|
||||
37;h67;381;
|
||||
38;h97;537;
|
||||
39;h96;536;
|
||||
45;h74;485;
|
||||
50;h82;514;
|
||||
128;h19;565;
|
||||
148;h50;522;
|
||||
163;h92;457;
|
||||
173;h25;1759;
|
||||
192;h93;1778;
|
||||
193;h95;1779;
|
||||
205;vm1107;1861;
|
||||
208;vm1110;1864;
|
||||
210;vm1112;1833;
|
|
10
src/test/resources/migration/hosting/inet_addr.csv
Normal file
10
src/test/resources/migration/hosting/inet_addr.csv
Normal file
@ -0,0 +1,10 @@
|
||||
inet_addr_id;inet_addr;description
|
||||
363;83.223.95.34;
|
||||
381;83.223.95.52;
|
||||
402;83.223.95.73;
|
||||
433;83.223.95.104;
|
||||
457;83.223.95.128;
|
||||
473;83.223.95.144;
|
||||
574;83.223.95.245;
|
||||
1168;83.223.79.72;
|
||||
1790;83.223.94.179;
|
|
10
src/test/resources/migration/hosting/packet.csv
Normal file
10
src/test/resources/migration/hosting/packet.csv
Normal file
@ -0,0 +1,10 @@
|
||||
packet_id;basepacket_code;packet_name;bp_id;hive_id;created;cancelled;cur_inet_addr_id;old_inet_addr_id;free
|
||||
630;PAC/WEB;hsh00;213;14;2001-06-01;;473;;1
|
||||
968;SRV/MGD;vm1061;132;28;2013-04-01;;363;;0
|
||||
978;SRV/MGD;vm1050;213;14;2013-04-01;;433;;1
|
||||
1061;SRV/MGD;vm1068;100;37;2013-08-19;;381;;f
|
||||
1094;PAC/WEB;lug00;100;37;2013-09-10;;1168;;1
|
||||
1112;PAC/WEB;mim00;100;37;2013-09-17;;402;;1
|
||||
1447;SRV/MGD;vm1093;213;163;2014-11-28;;457;;t
|
||||
19959;PAC/WEB;dph00;542;163;2021-06-02;;574;;0
|
||||
23611;SRV/CLD;vm2097;541;;2022-08-10;;1790;;0
|
|
143
src/test/resources/migration/hosting/packet_component.csv
Normal file
143
src/test/resources/migration/hosting/packet_component.csv
Normal file
@ -0,0 +1,143 @@
|
||||
packet_component_id;packet_id;quantity;basecomponent_code;created;cancelled
|
||||
46105;1094;10;TRAFFIC;2017-03-27;
|
||||
46109;1094;5;MULTI;2017-03-27;
|
||||
46111;1094;0;DAEMON;2017-03-27;
|
||||
46113;1094;1024;QUOTA;2017-03-27;
|
||||
46117;1112;0;DAEMON;2017-03-27;
|
||||
46121;1112;20;TRAFFIC;2017-03-27;
|
||||
46122;1112;5;MULTI;2017-03-27;
|
||||
46123;1112;3072;QUOTA;2017-03-27;
|
||||
143133;1094;1;SLABASIC;2017-09-01;
|
||||
143483;1112;1;SLABASIC;2017-09-01;
|
||||
757383;1112;0;SLAEXT24H;;
|
||||
770533;1094;0;SLAEXT24H;;
|
||||
784283;1112;0;OFFICE;;
|
||||
797433;1094;0;OFFICE;;
|
||||
1228033;1112;0;STORAGE;;
|
||||
1241433;1094;0;STORAGE;;
|
||||
1266451;978;0;SLAPLAT4H;2021-10-05;
|
||||
1266452;978;250;TRAFFIC;2021-10-05;
|
||||
1266453;978;0;SLAPLAT8H;2021-10-05;
|
||||
1266454;978;0;SLAMAIL4H;2021-10-05;
|
||||
1266455;978;0;SLAMARIA8H;2021-10-05;
|
||||
1266456;978;0;SLAPGSQL4H;2021-10-05;
|
||||
1266457;978;0;SLAWEB4H;2021-10-05;
|
||||
1266458;978;0;SLAMARIA4H;2021-10-05;
|
||||
1266459;978;0;SLAPGSQL8H;2021-10-05;
|
||||
1266460;978;0;SLAOFFIC8H;2021-10-05;
|
||||
1266461;978;0;SLAWEB8H;2021-10-05;
|
||||
1266462;978;256000;STORAGE;2021-10-05;
|
||||
1266463;978;153600;QUOTA;2021-10-05;
|
||||
1266464;978;0;SLAOFFIC4H;2021-10-05;
|
||||
1266465;978;32768;RAM;2021-10-05;
|
||||
1266466;978;4;CPU;2021-10-05;
|
||||
1266467;978;1;SLABASIC;2021-10-05;
|
||||
1266468;978;0;SLAMAIL8H;2021-10-05;
|
||||
1275583;978;0;SLAPLAT2H;2022-04-20;
|
||||
1280533;978;0;SLAWEB2H;2022-04-20;
|
||||
1285483;978;0;SLAMARIA2H;2022-04-20;
|
||||
1290433;978;0;SLAPGSQL2H;2022-04-20;
|
||||
1295383;978;0;SLAMAIL2H;2022-04-20;
|
||||
1300333;978;0;SLAOFFIC2H;2022-04-20;
|
||||
1305933;1447;0;SLAWEB2H;2022-05-02;
|
||||
1305934;1447;0;SLAPLAT4H;2022-05-02;
|
||||
1305935;1447;0;SLAWEB8H;2022-05-02;
|
||||
1305936;1447;0;SLAOFFIC4H;2022-05-02;
|
||||
1305937;1447;0;SLAMARIA4H;2022-05-02;
|
||||
1305938;1447;0;SLAOFFIC8H;2022-05-02;
|
||||
1305939;1447;1;SLABASIC;2022-05-02;
|
||||
1305940;1447;0;SLAMAIL8H;2022-05-02;
|
||||
1305941;1447;0;SLAPGSQL4H;2022-05-02;
|
||||
1305942;1447;6;CPU;2022-05-02;
|
||||
1305943;1447;250;TRAFFIC;2022-05-02;
|
||||
1305944;1447;0;SLAOFFIC2H;2022-05-02;
|
||||
1305945;1447;0;SLAMAIL4H;2022-05-02;
|
||||
1305946;1447;0;SLAPGSQL2H;2022-05-02;
|
||||
1305947;1447;0;SLAMARIA2H;2022-05-02;
|
||||
1305948;1447;0;SLAMARIA8H;2022-05-02;
|
||||
1305949;1447;0;SLAWEB4H;2022-05-02;
|
||||
1305950;1447;16384;RAM;2022-05-02;
|
||||
1305951;1447;0;SLAPGSQL8H;2022-05-02;
|
||||
1305952;1447;512000;STORAGE;2022-05-02;
|
||||
1305953;1447;0;SLAMAIL2H;2022-05-02;
|
||||
1305954;1447;0;SLAPLAT2H;2022-05-02;
|
||||
1305955;1447;0;SLAPLAT8H;2022-05-02;
|
||||
1305956;1447;307200;QUOTA;2022-05-02;
|
||||
1312013;23611;1;SLABASIC;2022-08-10;
|
||||
1312014;23611;0;BANDWIDTH;2022-08-10;
|
||||
1312015;23611;12288;RAM;2022-08-10;
|
||||
1312016;23611;25600;QUOTA;2022-08-10;
|
||||
1312017;23611;0;SLAINFR8H;2022-08-10;
|
||||
1312018;23611;0;STORAGE;2022-08-10;
|
||||
1312019;23611;0;SLAINFR2H;2022-08-10;
|
||||
1312020;23611;8;CPU;2022-08-10;
|
||||
1312021;23611;250;TRAFFIC;2022-08-10;
|
||||
1312022;23611;0;SLAINFR4H;2022-08-10;
|
||||
1313883;978;0;BANDWIDTH;;
|
||||
1316583;1447;0;BANDWIDTH;;
|
||||
1338074;968;0;SLAMARIA2H;2023-09-05;
|
||||
1338075;968;384000;QUOTA;2023-09-05;
|
||||
1338076;968;1;SLAMAIL8H;2023-09-05;
|
||||
1338077;968;0;BANDWIDTH;2023-09-05;
|
||||
1338078;968;0;SLAWEB2H;2023-09-05;
|
||||
1338079;968;0;SLAOFFIC4H;2023-09-05;
|
||||
1338080;968;256000;STORAGE;2023-09-05;
|
||||
1338081;968;0;SLAPLAT4H;2023-09-05;
|
||||
1338082;968;0;SLAPGSQL2H;2023-09-05;
|
||||
1338083;968;0;SLAPLAT2H;2023-09-05;
|
||||
1338084;968;250;TRAFFIC;2023-09-05;
|
||||
1338085;968;1;SLAMARIA8H;2023-09-05;
|
||||
1338086;968;0;SLAPGSQL4H;2023-09-05;
|
||||
1338087;968;0;SLAMAIL2H;2023-09-05;
|
||||
1338088;968;1;SLAPLAT8H;2023-09-05;
|
||||
1338089;968;0;SLAWEB4H;2023-09-05;
|
||||
1338090;968;6;CPU;2023-09-05;
|
||||
1338091;968;1;SLAPGSQL8H;2023-09-05;
|
||||
1338092;968;0;SLAMARIA4H;2023-09-05;
|
||||
1338093;968;0;SLAMAIL4H;2023-09-05;
|
||||
1338094;968;14336;RAM;2023-09-05;
|
||||
1338095;968;0;SLAOFFIC2H;2023-09-05;
|
||||
1338096;968;0;SLAOFFIC8H;2023-09-05;
|
||||
1338097;968;1;SLABASIC;2023-09-05;
|
||||
1338098;968;1;SLAWEB8H;2023-09-05;
|
||||
1339228;19959;20;TRAFFIC;2023-10-27;
|
||||
1339229;19959;1;SLABASIC;2023-10-27;
|
||||
1339230;19959;0;DAEMON;2023-10-27;
|
||||
1339231;19959;25600;QUOTA;2023-10-27;
|
||||
1339232;19959;0;STORAGE;2023-10-27;
|
||||
1339233;19959;0;SLAEXT24H;2023-10-27;
|
||||
1339234;19959;0;OFFICE;2023-10-27;
|
||||
1339235;19959;1;MULTI;2023-10-27;
|
||||
1341088;1061;0;SLAOFFIC2H;2023-12-14;
|
||||
1341089;1061;0;SLAOFFIC8H;2023-12-14;
|
||||
1341090;1061;256000;STORAGE;2023-12-14;
|
||||
1341091;1061;0;SLAMAIL4H;2023-12-14;
|
||||
1341092;1061;0;SLAMAIL2H;2023-12-14;
|
||||
1341093;1061;0;SLAPLAT2H;2023-12-14;
|
||||
1341094;1061;4096;RAM;2023-12-14;
|
||||
1341095;1061;0;SLAPLAT4H;2023-12-14;
|
||||
1341096;1061;1;SLAPGSQL8H;2023-12-14;
|
||||
1341097;1061;2;CPU;2023-12-14;
|
||||
1341098;1061;0;QUOTA;2023-12-14;
|
||||
1341099;1061;0;SLAMAIL8H;2023-12-14;
|
||||
1341100;1061;1;SLABASIC;2023-12-14;
|
||||
1341101;1061;1;SLAMARIA8H;2023-12-14;
|
||||
1341102;1061;0;SLAPGSQL4H;2023-12-14;
|
||||
1341103;1061;0;SLAPGSQL2H;2023-12-14;
|
||||
1341104;1061;0;SLAMARIA4H;2023-12-14;
|
||||
1341105;1061;0;SLAOFFIC4H;2023-12-14;
|
||||
1341106;1061;1;SLAPLAT8H;2023-12-14;
|
||||
1341107;1061;0;BANDWIDTH;2023-12-14;
|
||||
1341108;1061;1;SLAWEB8H;2023-12-14;
|
||||
1341109;1061;0;SLAWEB2H;2023-12-14;
|
||||
1341110;1061;0;SLAMARIA2H;2023-12-14;
|
||||
1341111;1061;250;TRAFFIC;2023-12-14;
|
||||
1341112;1061;0;SLAWEB4H;2023-12-14;
|
||||
1346628;630;0;SLAEXT24H;2024-03-19;
|
||||
1346629;630;0;OFFICE;2024-03-19;
|
||||
1346630;630;16384;QUOTA;2024-03-19;
|
||||
1346631;630;0;DAEMON;2024-03-19;
|
||||
1346632;630;10240;STORAGE;2024-03-19;
|
||||
1346633;630;1;SLABASIC;2024-03-19;
|
||||
1346634;630;50;TRAFFIC;2024-03-19;
|
||||
1346635;630;25;MULTI;2024-03-19;
|
|
19
src/test/resources/migration/office/asset_transactions.csv
Normal file
19
src/test/resources/migration/office/asset_transactions.csv
Normal file
@ -0,0 +1,19 @@
|
||||
member_asset_id; bp_id; date; action; amount; comment
|
||||
358; 100; 2000-12-06; PAYMENT; 5120; for subscription A
|
||||
442; 132; 2003-07-07; PAYMENT; 64;
|
||||
577; 100; 2011-12-12; PAYMENT; 1024;
|
||||
632; 132; 2013-10-21; PAYMENT; 64;
|
||||
885; 100; 2020-12-15; PAYMENT; 6144; Einzahlung
|
||||
924; 541; 2021-05-21; PAYMENT; 256; Beitritt - Lastschrift
|
||||
925; 542; 2021-05-31; PAYMENT; 64; Beitritt - Lastschrift
|
||||
1093; 100; 2023-10-05; PAYMENT; 3072; Kapitalerhoehung - Ueberweisung
|
||||
1094; 100; 2023-10-06; PAYMENT; 3072; Kapitalerhoehung - Ueberweisung
|
||||
31000; 120; 2000-12-06; PAYMENT; 128.00; for subscription B
|
||||
32000; 100; 2005-01-10; PAYMENT; 2560.00; for subscription C
|
||||
33001; 100; 2005-01-10; HANDOVER; -512.00; for transfer to 10
|
||||
33002; 120; 2005-01-10; ADOPTION; 512.00; for transfer from 7
|
||||
34001; 120; 2016-12-31; CLEARING; -8.00; for cancellation D
|
||||
34002; 120; 2016-12-31; PAYBACK; -100.00; for cancellation D
|
||||
34003; 120; 2016-12-31; LOSS; -20.00; for cancellation D
|
||||
35001; 190; 2024-01-15; PAYMENT; 128.00; for subscription E
|
||||
35002; 190; 2024-01-20; ADJUSTMENT;-128.00; chargeback for subscription E
|
|
10
src/test/resources/migration/office/business_partners.csv
Normal file
10
src/test/resources/migration/office/business_partners.csv
Normal file
@ -0,0 +1,10 @@
|
||||
bp_id;member_id;member_code;member_since;member_until;member_role;author_contract;nondisc_contract;free;exempt_vat;indicator_vat;uid_vat
|
||||
100;10003;hsh00-mim;2000-12-06;;Aufsichtsrat;;2001-04-24;0;0;GROSS;DE217249198
|
||||
132;10152;hsh00-rar;2003-07-12;;;;;0;0;GROSS;DE 236 109 136
|
||||
213;10000;hsh00-hsh;;;Hostsharing eG;;;1;0;GROSS;
|
||||
541;11018;hsh00-wws;2021-05-17;;;;;0;0;GROSS;
|
||||
542;11019;hsh00-dph;2021-05-25;;;;;0;0;GROSS;
|
||||
120;10020;hsh00-xyz;2000-12-06;2015-12-31;;;;false;false;GROSS;
|
||||
122;11022;hsh00-xxx;2021-04-01;;;;;true;true;GROSS;
|
||||
190;19090;hsh00-yyy;;;;;;true;true;GROSS;
|
||||
199;19999;hsh00-zzz;;;;;;false;false;GROSS;
|
|
35
src/test/resources/migration/office/contacts.csv
Normal file
35
src/test/resources/migration/office/contacts.csv
Normal file
@ -0,0 +1,35 @@
|
||||
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
|
||||
|
||||
# Hostsharing, the mandate itself
|
||||
212; 213; Firma; Hostmaster; Hostsharing; ; Hostsharing e.G.; ; ; ; ; Germany; ; ; ; ; hostmaster@hostsharing.net; billing,operation,contractual,partner
|
||||
|
||||
# some natural persons
|
||||
100; 100; Herr; Michael; Mellis; ; Michael Mellis; ; Dr. Bolte Str. 50; 26524; Hage; Germany; ; +49 4931/1234567; +49/1522123455; +49 40 912345-9; michael@Mellis.example.org; billing,operation,contractual,partner,subscriber:members-announce,subscriber:operations-announce,subscriber:operations-discussion,subscriber:members-discussion,subscriber:generalversammlung
|
||||
132; 132; Herr; Ragnar; Richter; ; Ragnar IT-Beratung; ; Vioktoriastraße 114; 70197; Stuttgart; Germany; +49 711 987654-1; +49 711 987654-2; ; +49 711 87654-3; hostsharing@ragnar-richter.de; billing,operation,partner,subscriber:operations-announce,subscriber:operations-discussion
|
||||
|
||||
# eine juristische Person mit drei separaten Ansprechpartnern, vip-contact und ex-partner
|
||||
1200; 120; ; ; ; ; JM e.K.; ; Wiesenweg 15; 12335; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; jm-ex-partner@example.org; ex-partner
|
||||
1201; 120; Frau; Jenny; Meyer-Billing; Dr.; JM GmbH; ; Waldweg 5; 11001; Berlin; DE; +49 30 7777777; +49 30 1111111; ; +49 30 2222222; jm-billing@example.org; billing
|
||||
1202; 120; Herr; Andrew; Meyer-Operation; ; JM GmbH; ; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 3333333; ; +49 30 4444444; am-operation@example.org; operation,vip-contact,subscriber:operations-announce
|
||||
1203; 120; Herr; Philip; Meyer-Contract; ; JM GmbH; ; Waldweg 5; 11001; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; pm-partner@example.org; partner,contractual,subscriber:members-announce,subscriber:customers-announce
|
||||
1204; 120; Frau; Tammy; Meyer-VIP; ; JM GmbH; ; Waldweg 5; 11001; Berlin; DE; +49 30 999999; +49 30 999999; ; +49 30 6666666; tm-vip@example.org; vip-contact
|
||||
|
||||
# eine juristische Person mit nur einem Ansprechpartner und explizitem contractual
|
||||
1301; 122; ; Petra; Schmidt; ; Test PS; ; ; ; ; ; ; ; ; ; ps@example.com; partner,billing,contractual,operation
|
||||
|
||||
# eine natürliche Person, die nur Subscriber ist
|
||||
1401; 120; Frau; Frauke; Fanninga; ; ; ; Am Walde 1; 29456; Hitzacker; DE; ; ; ; ; ff@example.org; subscriber:operations-announce
|
||||
|
||||
# eine natürliche Person als Partner
|
||||
1501; 190; Frau; Cecilia; Camus; ; ; ; Rue d'Avignion 60; 45000; Orléans; FR; ; ; ; ; cc@example.org; partner,contractual,billing,operation
|
||||
|
||||
# some more contacts of realistic business partners
|
||||
|
||||
90436; 541; Frau; Christiane; Milberg; ; Wasserwerk Südholstein; ; Am Wasserwerk 1-3; 25491; Hetlingen; Germany; ; ; +49 4103 12345-1; ; rechnung@ww-sholst.example.org; billing,partner,subscriber:members-discussion,contractual,subscriber:members-announce,subscriber:generalversammlung
|
||||
90437; 542; Herr; Richard; Wiese; ; Das Perfekte Haus; ; Kennedyplatz 11; 45279; Essen; Germany; ; ; +49-172-12345; ; admin@das-perfekte-haus.example.org; operation,partner,subscriber:members-discussion,contractual,subscriber:operations-announce,subscriber:operations-discussion,subscriber:members-announce,subscriber:generalversammlung
|
||||
90438; 541; Herr; Karim; Metzger; ; Wasswerwerk Südholstein; ; Am Wasserwerk 1-3; 25491; Hetlingen; Germany; ; +49 4103 12345-2; ; ; karim.metzger@ww-sholst.example.org; operation,subscriber:operations-announce,subscriber:operations-discussion
|
||||
90590; 542; Herr; Inhaber R.; Wiese; ; Das Perfekte Haus; Client-ID 515217; Essen, Kastanienallee 81; 30127; Hannover; Germany; ; ; ; ; 515217@kkemail.example.org; billing
|
||||
90629; 132; ; Ragnar; Richter; ; ; ; ; ; ; ; ; ; ; ; mail@ragnar-richter..example.org; contractual,subscriber:members-announce,subscriber:members-discussion,subscriber:generalversammlung
|
||||
90677; 132; ; Eike; Henning; ; ; ; ; ; ; ; ; ; ; ; hostsharing@eike-henning..example.org; operation,subscriber:operations-announce,subscriber:operations-discussion
|
||||
90698; 132; ; Jan; Henning; ; ; ; ; ; ; ; ; 01577 12345678; ; ; mail@jan-henning.example.org; operation
|
||||
|
|
8
src/test/resources/migration/office/sepa_mandates.csv
Normal file
8
src/test/resources/migration/office/sepa_mandates.csv
Normal file
@ -0,0 +1,8 @@
|
||||
sepa_mandat_id;bp_id;bank_customer;bank_name;bank_iban;bank_bic;mandat_ref;mandat_signed;mandat_since;mandat_until;mandat_used
|
||||
30;132;Ragnar Richter;GLS Gemeinschaftsbank eG;DE02300209000106531065;GENODEM1GLS;HS-10152-20140801;2013-12-01;2013-12-01;2016-02-15;2014-01-20
|
||||
132;100;Michael Mellis;Hamburger Volksbank;DE37500105177419788228;GENODEF1HH2;HS-10003-20140801;2013-12-01;2013-12-01;;2022-12-31
|
||||
386;541;Wasserwerk Suedholstein;Sparkasse Westholstein;DE49500105174516484892;NOLADE21WHO;HS-11018-20210512;2021-05-12;2021-05-17;;2022-12-31
|
||||
387;542;Richard Wiese Das Perfekte Haus;Commerzbank Wuppertal;DE89370400440532013000;COBADEFFXXX;HS-11019-20210519;2021-05-19;2021-05-25;;2022-12-31
|
||||
234234;100;Michael Mellis;ING Bank AG;DE37500105177419788228;INGDDEFFXXX;MH12345;2004-06-12;2004-06-15;;2022-10-20
|
||||
235600;120;JM e.K.;Targobank AG;DE02300209000106531065;CMCIDEDD;JM33344;2004-01-15;2004-01-20;2005-06-27 ;2016-01-18
|
||||
235662;120;JM GmbH;ING Bank AG;DE49500105174516484892;INGDDEFFXXX;JM33344;2005-06-28;2005-07-01;;2016-01-18
|
|
12
src/test/resources/migration/office/share_transactions.csv
Normal file
12
src/test/resources/migration/office/share_transactions.csv
Normal file
@ -0,0 +1,12 @@
|
||||
member_share_id;bp_id;date;action;quantity;comment
|
||||
3;100;2000-12-06;SUBSCRIPTION;80;initial share subscription
|
||||
90;132;2003-07-12;SUBSCRIPTION;1;
|
||||
241;100;2011-12-05;SUBSCRIPTION;16;
|
||||
279;132;2013-10-21;SUBSCRIPTION;1;
|
||||
523;100;2020-12-08;SUBSCRIPTION;96;Kapitalerhoehung
|
||||
562;541;2021-05-17;SUBSCRIPTION;4;Beitritt
|
||||
563;542;2021-05-25;SUBSCRIPTION;1;Beitritt
|
||||
721;100;2023-10-10;SUBSCRIPTION;96;Kapitalerhoehung
|
||||
33451;120;2000-12-06;SUBSCRIPTION;2;initial share subscription
|
||||
33701;100;2005-01-10;SUBSCRIPTION;40;increase
|
||||
33810;120;2016-12-31;UNSUBSCRIPTION;22;membership ended
|
|
@ -1,4 +0,0 @@
|
||||
sepa_mandat_id; bp_id; bank_customer; bank_name; bank_iban; bank_bic; mandat_ref; mandat_signed; mandat_since; mandat_until; mandat_used
|
||||
234234; 17; Michael Mellies; ING Bank AG; DE37500105177419788228; INGDDEFFXXX; MH12345; 2004-06-12; 2004-06-15; ; 2022-10-20
|
||||
235600; 20; JM e.K.; Targobank AG; DE02300209000106531065; CMCIDEDD; JM33344; 2004-01-15; 2004-01-20;2005-06-27 ;2016-01-18
|
||||
235662; 20; JM GmbH; ING Bank AG; DE49500105174516484892; INGDDEFFXXX; JM33344; 2005-06-28; 2005-07-01; ; 2016-01-18
|
|
@ -1,5 +0,0 @@
|
||||
member_share_id;bp_id; date; action; quantity; comment
|
||||
33443; 17; 2000-12-06; SUBSCRIPTION; 20; initial share subscription
|
||||
33451; 20; 2000-12-06; SUBSCRIPTION; 2; initial share subscription
|
||||
33701; 17; 2005-01-10; SUBSCRIPTION; 40; increase
|
||||
33810; 20; 2016-12-31; UNSUBSCRIPTION; 22; membership ended
|
|
Loading…
Reference in New Issue
Block a user