diff --git a/waltz-data/src/main/java/org/finos/waltz/data/assessment_rating/AssessmentRatingDao.java b/waltz-data/src/main/java/org/finos/waltz/data/assessment_rating/AssessmentRatingDao.java
index 6ae00c5173..b63220edd5 100644
--- a/waltz-data/src/main/java/org/finos/waltz/data/assessment_rating/AssessmentRatingDao.java
+++ b/waltz-data/src/main/java/org/finos/waltz/data/assessment_rating/AssessmentRatingDao.java
@@ -228,6 +228,15 @@ public List findByGenericSelector(GenericSelector genericSelec
}
+ public int deleteByGenericSelector(GenericSelector genericSelector) {
+ return dsl
+ .deleteFrom(ar)
+ .where(ar.ENTITY_KIND.eq(genericSelector.kind().name()))
+ .and(ar.ENTITY_ID.in(genericSelector.selector()))
+ .execute();
+ }
+
+
public boolean store(SaveAssessmentRatingCommand command) {
checkNotNull(command, "command cannot be null");
AssessmentRatingRecord record = COMMAND_TO_RECORD_MAPPER.apply(command);
diff --git a/waltz-data/src/main/java/org/finos/waltz/data/entity_named_note/EntityNamedNoteDao.java b/waltz-data/src/main/java/org/finos/waltz/data/entity_named_note/EntityNamedNoteDao.java
index 920a395d36..c2fa69894f 100644
--- a/waltz-data/src/main/java/org/finos/waltz/data/entity_named_note/EntityNamedNoteDao.java
+++ b/waltz-data/src/main/java/org/finos/waltz/data/entity_named_note/EntityNamedNoteDao.java
@@ -18,6 +18,7 @@
package org.finos.waltz.data.entity_named_note;
+import org.finos.waltz.data.GenericSelector;
import org.finos.waltz.schema.tables.records.EntityNamedNoteRecord;
import org.finos.waltz.model.EntityKind;
import org.finos.waltz.model.EntityReference;
@@ -138,4 +139,12 @@ public Set findByNoteTypeExtIdAndEntityReference(String noteTyp
.and(ENTITY_NAMED_NOTE.ENTITY_ID.eq(entityReference.id()))
.fetchSet(TO_DOMAIN_MAPPER);
}
+
+ public int deleteByParentSelector(GenericSelector selector) {
+ return dsl
+ .deleteFrom(ENTITY_NAMED_NOTE)
+ .where(ENTITY_NAMED_NOTE.ENTITY_ID.in(selector.selector())
+ .and(ENTITY_NAMED_NOTE.ENTITY_KIND.eq(selector.kind().name())))
+ .execute();
+ }
}
diff --git a/waltz-data/src/main/java/org/finos/waltz/data/entity_relationship/EntityRelationshipDao.java b/waltz-data/src/main/java/org/finos/waltz/data/entity_relationship/EntityRelationshipDao.java
index 859a4d459f..079873beb9 100644
--- a/waltz-data/src/main/java/org/finos/waltz/data/entity_relationship/EntityRelationshipDao.java
+++ b/waltz-data/src/main/java/org/finos/waltz/data/entity_relationship/EntityRelationshipDao.java
@@ -25,9 +25,12 @@
import org.finos.waltz.model.EntityReference;
import org.finos.waltz.model.ImmutableEntityReference;
import org.finos.waltz.model.entity_relationship.*;
+import org.finos.waltz.schema.Tables;
import org.finos.waltz.schema.tables.records.EntityRelationshipRecord;
import org.jooq.*;
import org.jooq.impl.DSL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@@ -48,6 +51,7 @@
@Repository
public class EntityRelationshipDao {
+ private static final Logger LOG = LoggerFactory.getLogger(EntityRelationshipDao.class);
private static final List POSSIBLE_ENTITIES = newArrayList(
EntityKind.APPLICATION,
@@ -319,4 +323,103 @@ public int removeAll(long groupId, List changeInitiativeIds) {
.and(ENTITY_RELATIONSHIP.ID_B.in(changeInitiativeIds))
.execute();
}
+
+
+ public void migrateEntityRelationships(EntityReference sourceReference, EntityReference targetReference, String userId) {
+
+ dsl.transaction(ctx -> {
+
+ DSLContext tx = ctx.dsl();
+
+ LOG.info("Migrating entity relationships from source: {}/{} to target: {}/{}",
+ sourceReference.kind().prettyName(),
+ sourceReference.id(),
+ targetReference.kind().prettyName(),
+ targetReference.id());
+
+ Condition measurableIsA = Tables.ENTITY_RELATIONSHIP.ID_A.eq(sourceReference.id()).and(Tables.ENTITY_RELATIONSHIP.KIND_A.eq(sourceReference.kind().name()));
+ Condition measurableIsB = Tables.ENTITY_RELATIONSHIP.ID_B.eq(sourceReference.id()).and(Tables.ENTITY_RELATIONSHIP.KIND_B.eq(sourceReference.kind().name()));
+
+ SelectOrderByStep> allowedKindAUpdates = selectKindARelationshipsThatCanBeAdded(sourceReference, targetReference);
+
+ int kindARelsUpdated = tx
+ .update(Tables.ENTITY_RELATIONSHIP)
+ .set(Tables.ENTITY_RELATIONSHIP.ID_A, targetReference.id())
+ .set(Tables.ENTITY_RELATIONSHIP.LAST_UPDATED_AT, DateTimeUtilities.nowUtcTimestamp())
+ .set(Tables.ENTITY_RELATIONSHIP.LAST_UPDATED_BY, userId)
+ .from(allowedKindAUpdates)
+ .where(measurableIsA)
+ .and(Tables.ENTITY_RELATIONSHIP.KIND_B.eq(allowedKindAUpdates.field(Tables.ENTITY_RELATIONSHIP.KIND_B))
+ .and(Tables.ENTITY_RELATIONSHIP.ID_B.eq(allowedKindAUpdates.field(Tables.ENTITY_RELATIONSHIP.ID_B))
+ .and(Tables.ENTITY_RELATIONSHIP.RELATIONSHIP.eq(allowedKindAUpdates.field(Tables.ENTITY_RELATIONSHIP.RELATIONSHIP)))))
+ .execute();
+
+ SelectOrderByStep> allowedKindBUpdates = selectKindBRelationshipsThatCanBeAdded(sourceReference, targetReference);
+
+ int kindBRelsUpdated = tx
+ .update(Tables.ENTITY_RELATIONSHIP)
+ .set(Tables.ENTITY_RELATIONSHIP.ID_B, targetReference.id())
+ .set(Tables.ENTITY_RELATIONSHIP.LAST_UPDATED_AT, DateTimeUtilities.nowUtcTimestamp())
+ .set(Tables.ENTITY_RELATIONSHIP.LAST_UPDATED_BY, userId)
+ .from(allowedKindBUpdates)
+ .where(measurableIsB)
+ .and(Tables.ENTITY_RELATIONSHIP.KIND_A.eq(allowedKindBUpdates.field(Tables.ENTITY_RELATIONSHIP.KIND_A))
+ .and(Tables.ENTITY_RELATIONSHIP.ID_A.eq(allowedKindBUpdates.field(Tables.ENTITY_RELATIONSHIP.ID_A))
+ .and(Tables.ENTITY_RELATIONSHIP.RELATIONSHIP.eq(allowedKindBUpdates.field(Tables.ENTITY_RELATIONSHIP.RELATIONSHIP)))))
+ .execute();
+
+ int entityRelsRemoved = tx
+ .deleteFrom(Tables.ENTITY_RELATIONSHIP)
+ .where(measurableIsA.or(measurableIsB))
+ .execute();
+
+ LOG.info("Migrated {} relationships from source: {}/{} to target: {}/{}",
+ kindARelsUpdated + kindBRelsUpdated,
+ sourceReference.kind().prettyName(),
+ sourceReference.id(),
+ targetReference.kind().prettyName(),
+ targetReference.id());
+
+ LOG.info("Removed {} relationships that could not be migrated from source: {}/{} to target: {}/{} as a relationship already exists",
+ entityRelsRemoved,
+ sourceReference.kind().prettyName(),
+ sourceReference.id(),
+ targetReference.kind().prettyName(),
+ targetReference.id());
+ });
+ }
+
+ private SelectOrderByStep> selectKindARelationshipsThatCanBeAdded(EntityReference source, EntityReference target) {
+
+ SelectConditionStep> targets = DSL
+ .select(Tables.ENTITY_RELATIONSHIP.ID_B, Tables.ENTITY_RELATIONSHIP.KIND_B, Tables.ENTITY_RELATIONSHIP.RELATIONSHIP)
+ .from(Tables.ENTITY_RELATIONSHIP)
+ .where(Tables.ENTITY_RELATIONSHIP.ID_A.eq(target.id())
+ .and(Tables.ENTITY_RELATIONSHIP.KIND_A.eq(target.kind().name())));
+
+ SelectConditionStep> migrations = DSL
+ .select(Tables.ENTITY_RELATIONSHIP.ID_B, Tables.ENTITY_RELATIONSHIP.KIND_B, Tables.ENTITY_RELATIONSHIP.RELATIONSHIP)
+ .from(Tables.ENTITY_RELATIONSHIP)
+ .where(Tables.ENTITY_RELATIONSHIP.ID_A.eq(source.id())
+ .and(Tables.ENTITY_RELATIONSHIP.KIND_A.eq(source.kind().name())));
+
+ return migrations.except(targets);
+ }
+
+ private SelectOrderByStep> selectKindBRelationshipsThatCanBeAdded(EntityReference source, EntityReference target) {
+
+ SelectConditionStep> targets = DSL
+ .select(Tables.ENTITY_RELATIONSHIP.ID_A, Tables.ENTITY_RELATIONSHIP.KIND_A, Tables.ENTITY_RELATIONSHIP.RELATIONSHIP)
+ .from(Tables.ENTITY_RELATIONSHIP)
+ .where(Tables.ENTITY_RELATIONSHIP.ID_B.eq(target.id())
+ .and(Tables.ENTITY_RELATIONSHIP.KIND_B.eq(target.kind().name())));
+
+ SelectConditionStep> migrations = DSL
+ .select(Tables.ENTITY_RELATIONSHIP.ID_A, Tables.ENTITY_RELATIONSHIP.KIND_A, Tables.ENTITY_RELATIONSHIP.RELATIONSHIP)
+ .from(Tables.ENTITY_RELATIONSHIP)
+ .where(Tables.ENTITY_RELATIONSHIP.ID_B.eq(source.id())
+ .and(Tables.ENTITY_RELATIONSHIP.KIND_B.eq(source.kind().name())));
+
+ return migrations.except(targets);
+ }
}
diff --git a/waltz-data/src/main/java/org/finos/waltz/data/measurable/MeasurableDao.java b/waltz-data/src/main/java/org/finos/waltz/data/measurable/MeasurableDao.java
index 8aedd15efb..531869b66c 100644
--- a/waltz-data/src/main/java/org/finos/waltz/data/measurable/MeasurableDao.java
+++ b/waltz-data/src/main/java/org/finos/waltz/data/measurable/MeasurableDao.java
@@ -19,7 +19,6 @@
package org.finos.waltz.data.measurable;
-import org.finos.waltz.schema.tables.records.MeasurableRecord;
import org.finos.waltz.common.DateTimeUtilities;
import org.finos.waltz.data.FindEntityReferencesByIdSelector;
import org.finos.waltz.model.EntityKind;
@@ -27,6 +26,7 @@
import org.finos.waltz.model.EntityReference;
import org.finos.waltz.model.measurable.ImmutableMeasurable;
import org.finos.waltz.model.measurable.Measurable;
+import org.finos.waltz.schema.tables.records.MeasurableRecord;
import org.jooq.*;
import org.jooq.impl.DSL;
import org.slf4j.Logger;
@@ -41,15 +41,15 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
-import static org.finos.waltz.data.JooqUtilities.summarizeResults;
-import static org.finos.waltz.schema.Tables.*;
-import static org.finos.waltz.schema.tables.EntityHierarchy.ENTITY_HIERARCHY;
-import static org.finos.waltz.schema.tables.Measurable.MEASURABLE;
import static java.util.Optional.ofNullable;
import static org.finos.waltz.common.Checks.checkNotNull;
import static org.finos.waltz.common.EnumUtilities.readEnum;
import static org.finos.waltz.common.StringUtilities.mkSafe;
import static org.finos.waltz.data.JooqUtilities.TO_ENTITY_REFERENCE;
+import static org.finos.waltz.data.JooqUtilities.summarizeResults;
+import static org.finos.waltz.schema.Tables.*;
+import static org.finos.waltz.schema.tables.EntityHierarchy.ENTITY_HIERARCHY;
+import static org.finos.waltz.schema.tables.Measurable.MEASURABLE;
@Repository
@@ -229,6 +229,31 @@ public boolean updateParentId(Long measurableId, Long destinationId, String user
.execute() == 1;
}
+ public boolean moveChildren(Long measurableId, Long targetId, String userId) {
+
+ if (targetId == null) {
+ throw new IllegalArgumentException("Cannot move children without specifying a new target");
+ }
+
+ LOG.info("Moving children from measurable: {} to {}",
+ measurableId,
+ targetId);
+
+ Select extends Record1> destinationExtId = DSL
+ .select(MEASURABLE.EXTERNAL_ID)
+ .from(MEASURABLE)
+ .where(MEASURABLE.ID.eq(targetId));
+
+ return dsl
+ .update(MEASURABLE)
+ .set(MEASURABLE.PARENT_ID, targetId)
+ .set(MEASURABLE.EXTERNAL_PARENT_ID, destinationExtId)
+ .set(MEASURABLE.LAST_UPDATED_AT, DateTimeUtilities.nowUtcTimestamp())
+ .set(MEASURABLE.LAST_UPDATED_BY, userId)
+ .where(MEASURABLE.PARENT_ID.eq(measurableId))
+ .execute() == 1;
+ }
+
public List findByCategoryId(Long categoryId) {
return dsl
diff --git a/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingDao.java b/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingDao.java
index f78681d577..8bc293877f 100644
--- a/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingDao.java
+++ b/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingDao.java
@@ -18,6 +18,7 @@
package org.finos.waltz.data.measurable_rating;
+import org.finos.waltz.common.DateTimeUtilities;
import org.finos.waltz.common.exception.NotFoundException;
import org.finos.waltz.data.InlineSelectFieldFactory;
import org.finos.waltz.data.JooqUtilities;
@@ -35,6 +36,8 @@
import org.jooq.*;
import org.jooq.impl.DSL;
import org.jooq.lambda.tuple.Tuple2;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@@ -55,8 +58,7 @@
import static org.finos.waltz.common.SetUtilities.union;
import static org.finos.waltz.common.StringUtilities.firstChar;
import static org.finos.waltz.common.StringUtilities.notEmpty;
-import static org.finos.waltz.schema.Tables.MEASURABLE_CATEGORY;
-import static org.finos.waltz.schema.Tables.USER_ROLE;
+import static org.finos.waltz.schema.Tables.*;
import static org.finos.waltz.schema.tables.Application.APPLICATION;
import static org.finos.waltz.schema.tables.Measurable.MEASURABLE;
import static org.finos.waltz.schema.tables.MeasurableRating.MEASURABLE_RATING;
@@ -65,14 +67,16 @@
@Repository
public class MeasurableRatingDao {
+ private static final Logger LOG = LoggerFactory.getLogger(MeasurableRatingDao.class);
+
private static final Condition APP_JOIN_CONDITION = APPLICATION.ID.eq(MEASURABLE_RATING.ENTITY_ID)
.and(MEASURABLE_RATING.ENTITY_KIND.eq(EntityKind.APPLICATION.name()));
private static final Field ENTITY_NAME_FIELD = InlineSelectFieldFactory.mkNameField(
- MEASURABLE_RATING.ENTITY_ID,
- MEASURABLE_RATING.ENTITY_KIND,
- newArrayList(EntityKind.values()))
- .as("entity_name");
+ MEASURABLE_RATING.ENTITY_ID,
+ MEASURABLE_RATING.ENTITY_KIND,
+ newArrayList(EntityKind.values()))
+ .as("entity_name");
private static final Field ENTITY_LIFECYCLE_FIELD = InlineSelectFieldFactory.mkEntityLifecycleField(
MEASURABLE_RATING.ENTITY_ID,
@@ -382,4 +386,314 @@ public Set calculateAmendedAllocationOperations(Set operat
}
}
+
+ /**
+ * Takes a source measurable and will move all ratings, decommission dates, replacement applications and allocations to the target measurable where possible.
+ * If a value already exists on the target the migration is ignored, or in the case of allocations, aggregated.
+ *
+ * @param measurableId the source measurable from which to migrate data
+ * @param targetId the target measurable to inherit the data (where possible)
+ * @param userId the user responsible for the change
+ */
+ public void migrateRatings(Long measurableId, Long targetId, String userId) {
+
+ if (targetId == null) {
+ throw new IllegalArgumentException("Cannot migrate ratings without specifying a new target");
+ }
+
+ LOG.info("Migrating ratings from measurable: {} to {}",
+ measurableId,
+ targetId);
+
+ int sharedRatingCount = getSharedRatingsCount(measurableId, targetId);
+ int sharedDecomCount = getSharedDecommsCount(measurableId, targetId);
+
+ dsl.transaction(ctx -> {
+
+ DSLContext tx = ctx.dsl();
+
+ // RATINGS
+
+ SelectOrderByStep> allowableMigrations = selectRatingsThatCanBeModified(measurableId, targetId);
+ // Do not update the measurable where an existing mapping already exists
+
+ SelectConditionStep> ratingsToInsert = DSL
+ .select(Tables.MEASURABLE_RATING.ENTITY_ID,
+ Tables.MEASURABLE_RATING.ENTITY_KIND,
+ DSL.val(targetId),
+ Tables.MEASURABLE_RATING.RATING,
+ Tables.MEASURABLE_RATING.DESCRIPTION,
+ Tables.MEASURABLE_RATING.LAST_UPDATED_AT,
+ Tables.MEASURABLE_RATING.LAST_UPDATED_BY,
+ Tables.MEASURABLE_RATING.PROVENANCE,
+ Tables.MEASURABLE_RATING.IS_READONLY)
+ .from(Tables.MEASURABLE_RATING)
+ .innerJoin(allowableMigrations).on(Tables.MEASURABLE_RATING.ENTITY_ID.eq(allowableMigrations.field(Tables.MEASURABLE_RATING.ENTITY_ID))
+ .and(Tables.MEASURABLE_RATING.ENTITY_KIND.eq(allowableMigrations.field(Tables.MEASURABLE_RATING.ENTITY_KIND))))
+ .where(Tables.MEASURABLE_RATING.MEASURABLE_ID.eq(measurableId));
+
+ int migratedRatings = tx
+ .insertInto(Tables.MEASURABLE_RATING)
+ .columns(Tables.MEASURABLE_RATING.ENTITY_ID,
+ Tables.MEASURABLE_RATING.ENTITY_KIND,
+ Tables.MEASURABLE_RATING.MEASURABLE_ID,
+ Tables.MEASURABLE_RATING.RATING,
+ Tables.MEASURABLE_RATING.DESCRIPTION,
+ Tables.MEASURABLE_RATING.LAST_UPDATED_AT,
+ Tables.MEASURABLE_RATING.LAST_UPDATED_BY,
+ Tables.MEASURABLE_RATING.PROVENANCE,
+ Tables.MEASURABLE_RATING.IS_READONLY)
+ .select(ratingsToInsert)
+ .execute();
+
+ if (migratedRatings > 0) {
+ writeChangeLogForMerge(
+ tx,
+ targetId,
+ EntityKind.MEASURABLE_RATING,
+ Operation.UPDATE,
+ format("Migrated %d ratings from measurable: %d to %d", migratedRatings, measurableId, targetId),
+ userId);
+ }
+
+ if (sharedRatingCount > 0) {
+ writeChangeLogForMerge(
+ tx,
+ targetId,
+ EntityKind.MEASURABLE_RATING,
+ Operation.REMOVE,
+ format("Failed to migrate %d ratings from measurable: %d to %d due to existing ratings on the target", sharedRatingCount, measurableId, targetId),
+ userId);
+ }
+
+ // DECOMMS
+
+ SelectOrderByStep> allowableDecomns = selectDecommsThatCanBeModified(measurableId, targetId);
+
+ int migratedDecoms = tx
+ .update(MEASURABLE_RATING_PLANNED_DECOMMISSION)
+ .set(MEASURABLE_RATING_PLANNED_DECOMMISSION.MEASURABLE_ID, targetId)
+ .from(allowableDecomns)
+ .where(MEASURABLE_RATING_PLANNED_DECOMMISSION.ENTITY_ID.eq(allowableDecomns.field(Tables.MEASURABLE_RATING.ENTITY_ID))
+ .and(MEASURABLE_RATING_PLANNED_DECOMMISSION.ENTITY_KIND.eq(allowableDecomns.field(Tables.MEASURABLE_RATING.ENTITY_KIND))
+ .and(MEASURABLE_RATING_PLANNED_DECOMMISSION.MEASURABLE_ID.eq(measurableId))))
+ .execute();
+
+ if (migratedDecoms > 0) {
+ writeChangeLogForMerge(
+ tx,
+ targetId,
+ EntityKind.MEASURABLE_RATING_PLANNED_DECOMMISSION,
+ Operation.UPDATE,
+ format("Migrated %d decomms from measurable: %d to %d", migratedDecoms, measurableId, targetId),
+ userId);
+ }
+
+ if (sharedDecomCount > 0) {
+ writeChangeLogForMerge(
+ tx,
+ targetId,
+ EntityKind.MEASURABLE_RATING_PLANNED_DECOMMISSION,
+ Operation.REMOVE,
+ format("Failed to migrate %d decomms from measurable: %d to %d due to existing decomms on the target", sharedDecomCount, measurableId, targetId),
+ userId);
+ }
+
+
+ // ALLOCATIONS
+
+
+ SelectOrderByStep> updateableAllocs = selectAllocsThatCanBeModified(measurableId, targetId);
+ SelectHavingStep> mergableAllocs = selectAllocsToBeUpdated(measurableId, targetId);
+
+ int migratedAllocs = tx
+ .update(ALLOCATION)
+ .set(ALLOCATION.MEASURABLE_ID, targetId)
+ .from(updateableAllocs)
+ .where(ALLOCATION.ENTITY_ID.eq(updateableAllocs.field(ALLOCATION.ENTITY_ID))
+ .and(ALLOCATION.ENTITY_KIND.eq(updateableAllocs.field(ALLOCATION.ENTITY_KIND))
+ .and(ALLOCATION.MEASURABLE_ID.eq(measurableId))))
+ .execute();
+
+ int mergedAllocs = tx
+ .update(ALLOCATION)
+ .set(ALLOCATION.ALLOCATION_PERCENTAGE, mergableAllocs.field("allocation_percentage", Integer.class))
+ .from(mergableAllocs)
+ .where(ALLOCATION.ALLOCATION_SCHEME_ID.eq(mergableAllocs.field(ALLOCATION.ALLOCATION_SCHEME_ID))
+ .and(ALLOCATION.ENTITY_ID.eq(mergableAllocs.field(ALLOCATION.ENTITY_ID))
+ .and(ALLOCATION.ENTITY_KIND.eq(mergableAllocs.field(ALLOCATION.ENTITY_KIND))
+ .and(ALLOCATION.MEASURABLE_ID.eq(targetId)))))
+ .execute();
+
+ if (migratedAllocs > 0) {
+ writeChangeLogForMerge(
+ tx,
+ targetId,
+ EntityKind.ALLOCATION,
+ Operation.UPDATE,
+ format("Migrated %d allocations from measurable: %d to %d", migratedAllocs, measurableId, targetId),
+ userId);
+ }
+
+ if (mergedAllocs > 0) {
+ writeChangeLogForMerge(
+ tx,
+ targetId,
+ EntityKind.ALLOCATION,
+ Operation.UPDATE,
+ format("Merged %d allocations from measurable: %d to %d where there was an existing allocation on the target", mergedAllocs, measurableId, targetId),
+ userId);
+ }
+
+ LOG.info(format("Migrated %d ratings, %d decomms, %d/%d allocations (migrated/merged) from measurable: %d to %d",
+ migratedRatings,
+ migratedDecoms,
+ migratedAllocs,
+ mergedAllocs,
+ measurableId,
+ targetId));
+
+ int removedRatings = tx
+ .deleteFrom(Tables.MEASURABLE_RATING)
+ .where(Tables.MEASURABLE_RATING.MEASURABLE_ID.eq(measurableId))
+ .execute();
+
+ if (removedRatings > 0) {
+ writeChangeLogForMerge(
+ tx,
+ targetId,
+ EntityKind.ALLOCATION,
+ Operation.UPDATE,
+ format("Removed %d ratings from measurable: %d where they could not be migrated due to an existing rating on the target", removedRatings, measurableId, targetId),
+ userId);
+ }
+
+ // allocations, decomms and replacements are automatically cleared up via cascade delete on fk
+ LOG.info("Removed {} measurable ratings and any associated allocations, planned decommissions and replacement applications after migration", removedRatings);
+ });
+ }
+
+
+ private void writeChangeLogForMerge(DSLContext tx, Long measurableId, EntityKind childKind, Operation operation, String message, String userId) {
+ tx
+ .insertInto(CHANGE_LOG)
+ .columns(CHANGE_LOG.PARENT_KIND,
+ CHANGE_LOG.PARENT_ID,
+ CHANGE_LOG.MESSAGE,
+ CHANGE_LOG.USER_ID,
+ CHANGE_LOG.SEVERITY,
+ CHANGE_LOG.CREATED_AT,
+ CHANGE_LOG.CHILD_KIND,
+ CHANGE_LOG.OPERATION)
+ .values(EntityKind.MEASURABLE.name(),
+ measurableId,
+ message,
+ userId,
+ Severity.INFORMATION.name(),
+ DateTimeUtilities.nowUtcTimestamp(),
+ childKind.name(),
+ operation.name())
+ .execute();
+ }
+
+
+ private SelectOrderByStep> selectRatingsThatCanBeModified(Long measurableId, Long targetId) {
+
+ SelectConditionStep> targets = mkEntitySelectForMeasurable(targetId);
+ SelectConditionStep> migrations = mkEntitySelectForMeasurable(measurableId);
+
+ return migrations.except(targets);
+ }
+
+ private SelectConditionStep> mkEntitySelectForMeasurable(Long measurableId) {
+ return DSL
+ .select(Tables.MEASURABLE_RATING.ENTITY_ID, Tables.MEASURABLE_RATING.ENTITY_KIND)
+ .from(Tables.MEASURABLE_RATING)
+ .where(Tables.MEASURABLE_RATING.MEASURABLE_ID.eq(measurableId));
+ }
+
+ public int getSharedRatingsCount(Long measurableId, Long targetId) {
+
+ SelectConditionStep> targets = mkEntitySelectForMeasurable(targetId);
+ SelectConditionStep> migrations = mkEntitySelectForMeasurable(measurableId);
+
+ SelectOrderByStep> sharedRatings = migrations.intersect(targets);
+
+ return dsl.fetchCount(sharedRatings);
+ }
+
+ public int getSharedDecommsCount(Long measurableId, Long targetId) {
+
+ SelectConditionStep> targets = mkEntitySelectForDecomm(targetId);
+ SelectConditionStep> migrations = mkEntitySelectForDecomm(measurableId);
+
+ SelectOrderByStep> sharedDecomms = migrations.intersect(targets);
+
+ return dsl.fetchCount(sharedDecomms);
+ }
+
+
+ private SelectOrderByStep> selectDecommsThatCanBeModified(Long measurableId, Long targetId) {
+
+ SelectConditionStep> targets = mkEntitySelectForDecomm(targetId);
+ SelectConditionStep> migrations = mkEntitySelectForDecomm(measurableId);
+
+ return migrations.except(targets);
+ }
+
+ private SelectConditionStep> mkEntitySelectForDecomm(Long measurableId) {
+ return DSL
+ .select(MEASURABLE_RATING_PLANNED_DECOMMISSION.ENTITY_ID, MEASURABLE_RATING_PLANNED_DECOMMISSION.ENTITY_KIND)
+ .from(MEASURABLE_RATING_PLANNED_DECOMMISSION)
+ .where(MEASURABLE_RATING_PLANNED_DECOMMISSION.MEASURABLE_ID.eq(measurableId));
+ }
+
+
+ private SelectOrderByStep> selectAllocsThatCanBeModified(Long measurableId, Long targetId) {
+
+ SelectConditionStep> targets = DSL
+ .select(ALLOCATION.ENTITY_ID, ALLOCATION.ENTITY_KIND)
+ .from(ALLOCATION)
+ .where(ALLOCATION.MEASURABLE_ID.eq(targetId));
+
+ SelectConditionStep> migrations = DSL
+ .select(ALLOCATION.ENTITY_ID, ALLOCATION.ENTITY_KIND)
+ .from(ALLOCATION)
+ .where(ALLOCATION.MEASURABLE_ID.eq(measurableId));
+
+ return migrations.except(targets);
+ }
+
+ private SelectOrderByStep> selectAllocsToBeSummed(Long measurableId, Long targetId) {
+
+ SelectConditionStep> targets = DSL
+ .select(ALLOCATION.ALLOCATION_SCHEME_ID, ALLOCATION.ENTITY_ID, ALLOCATION.ENTITY_KIND)
+ .from(ALLOCATION)
+ .where(ALLOCATION.MEASURABLE_ID.eq(targetId));
+
+ SelectConditionStep> migrations = DSL
+ .select(ALLOCATION.ALLOCATION_SCHEME_ID, ALLOCATION.ENTITY_ID, ALLOCATION.ENTITY_KIND)
+ .from(ALLOCATION)
+ .where(ALLOCATION.MEASURABLE_ID.eq(measurableId));
+
+ return migrations.intersect(targets);
+ }
+
+ private SelectHavingStep> selectAllocsToBeUpdated(Long measurableId, Long targetId) {
+
+ SelectOrderByStep> valuesToBeSummed = selectAllocsToBeSummed(measurableId, targetId);
+
+ return DSL
+ .select(ALLOCATION.ALLOCATION_SCHEME_ID,
+ ALLOCATION.ENTITY_ID,
+ ALLOCATION.ENTITY_KIND,
+ DSL.cast(DSL.sum(ALLOCATION.ALLOCATION_PERCENTAGE), Integer.class).as("allocation_percentage"))
+ .from(ALLOCATION)
+ .innerJoin(valuesToBeSummed).on(ALLOCATION.ALLOCATION_SCHEME_ID.eq(valuesToBeSummed.field(ALLOCATION.ALLOCATION_SCHEME_ID))
+ .and(ALLOCATION.ENTITY_KIND.eq(valuesToBeSummed.field(ALLOCATION.ENTITY_KIND))
+ .and(ALLOCATION.ENTITY_ID.eq(valuesToBeSummed.field(ALLOCATION.ENTITY_ID)))))
+ .where(ALLOCATION.MEASURABLE_ID.in(targetId, measurableId))
+ .groupBy(ALLOCATION.ALLOCATION_SCHEME_ID, ALLOCATION.ENTITY_ID, ALLOCATION.ENTITY_KIND);
+ }
+
}
diff --git a/waltz-model/src/main/java/org/finos/waltz/model/EntityKind.java b/waltz-model/src/main/java/org/finos/waltz/model/EntityKind.java
index 4822a06033..44e45b71a5 100644
--- a/waltz-model/src/main/java/org/finos/waltz/model/EntityKind.java
+++ b/waltz-model/src/main/java/org/finos/waltz/model/EntityKind.java
@@ -23,6 +23,7 @@ public enum EntityKind {
ACTOR("Actor"),
AGGREGATE_OVERLAY_DIAGRAM("Aggregate Overlay Diagram"),
AGGREGATE_OVERLAY_DIAGRAM_INSTANCE("Aggregate Overlay Diagram Instance"),
+ ALLOCATION("Allocation"),
ALLOCATION_SCHEME("Allocation scheme"),
APPLICATION("Application"),
APP_GROUP("Application group"),
diff --git a/waltz-model/src/main/java/org/finos/waltz/model/taxonomy_management/TaxonomyChangeImpact.java b/waltz-model/src/main/java/org/finos/waltz/model/taxonomy_management/TaxonomyChangeImpact.java
index 10ee927677..eb0a01d767 100644
--- a/waltz-model/src/main/java/org/finos/waltz/model/taxonomy_management/TaxonomyChangeImpact.java
+++ b/waltz-model/src/main/java/org/finos/waltz/model/taxonomy_management/TaxonomyChangeImpact.java
@@ -33,7 +33,9 @@
public abstract class TaxonomyChangeImpact implements DescriptionProvider {
public abstract Severity severity();
+
public abstract String description();
- public abstract Set impactedReferences();
+
+ public abstract int impactCount();
}
diff --git a/waltz-model/src/main/java/org/finos/waltz/model/taxonomy_management/TaxonomyChangePreview.java b/waltz-model/src/main/java/org/finos/waltz/model/taxonomy_management/TaxonomyChangePreview.java
index fd12429fdb..fdca6c1f8d 100644
--- a/waltz-model/src/main/java/org/finos/waltz/model/taxonomy_management/TaxonomyChangePreview.java
+++ b/waltz-model/src/main/java/org/finos/waltz/model/taxonomy_management/TaxonomyChangePreview.java
@@ -32,7 +32,6 @@ public abstract class TaxonomyChangePreview {
public abstract TaxonomyChangeCommand command();
public abstract List impacts();
-
@Nullable
public abstract String errorMessage();
}
diff --git a/waltz-ng/client/measurable/components/change-control/measurable-change-control.html b/waltz-ng/client/measurable/components/change-control/measurable-change-control.html
index bbb92bc1a4..84f963606d 100644
--- a/waltz-ng/client/measurable/components/change-control/measurable-change-control.html
+++ b/waltz-ng/client/measurable/components/change-control/measurable-change-control.html
@@ -266,6 +266,44 @@
+
+
+
+
+
+
diff --git a/waltz-ng/client/measurable/components/change-control/measurable-change-control.js b/waltz-ng/client/measurable/components/change-control/measurable-change-control.js
index 3f81ca95ca..f70e914f2b 100644
--- a/waltz-ng/client/measurable/components/change-control/measurable-change-control.js
+++ b/waltz-ng/client/measurable/components/change-control/measurable-change-control.js
@@ -71,13 +71,15 @@ function controller($scope,
const vm = initialiseData(this, initialState);
function mkCmd(params = {}) {
+
const paramProcessor = vm.selectedOperation.paramProcessor || _.identity;
+ const processedParam = paramProcessor(params);
return {
changeType: vm.selectedOperation.code,
changeDomain: toEntityRef(vm.changeDomain),
primaryReference: toEntityRef(vm.measurable),
- params: paramProcessor(params),
+ params: processedParam,
createdBy: vm.userName,
lastUpdatedBy: vm.userName
};
@@ -88,7 +90,7 @@ function controller($scope,
}
function mkPreviewCmd() {
- return mkCmd();
+ return mkCmd(vm.commandParams);
}
function calcPreview() {
@@ -270,6 +272,45 @@ function controller($scope,
should be used with care`,
color: "#b40400",
options: [
+ {
+ name: "Merge",
+ code: "MERGE",
+ icon: "code-fork",
+ description: "Merges this item with another and all of it's children will be migrated",
+ onShow: () => {
+ resetForm();
+ calcPreview();
+ },
+ paramProcessor: (d) => _.isEmpty(d)
+ ? {}
+ : ({
+ targetId: d.target.id,
+ targetName: d.target.name
+ }),
+ onReset: () => {
+ vm.commandParams.target = null;
+ vm.submitDisabled = true;
+ },
+ onChange: (target) => {
+ if (target === null) {
+ toasts.warning("Must have selected a arget to merge, ignoring....");
+ vm.commandParams.target = null;
+ vm.submitDisabled = true;
+ } else if (target.id === vm.measurable.id) {
+ toasts.warning("Cannot merge onto yourself, ignoring....");
+ vm.commandParams.target = null;
+ vm.submitDisabled = true;
+ } else if (vm.measurable.concrete && !target.concrete) {
+ toasts.warning("Cannot migrate to a non-concrete node, ignoring....");
+ vm.commandParams.target = null;
+ vm.submitDisabled = true;
+ } else {
+ vm.commandParams.target = target;
+ vm.submitDisabled = false;
+ calcPreview();
+ }
+ }
+ },
{
name: "Remove",
code: "REMOVE",
diff --git a/waltz-ng/client/taxonomy-management/components/taxonomy-change-command-preview/taxonomy-change-command-preview.html b/waltz-ng/client/taxonomy-management/components/taxonomy-change-command-preview/taxonomy-change-command-preview.html
index e8a02d5aa5..76964fcd41 100644
--- a/waltz-ng/client/taxonomy-management/components/taxonomy-change-command-preview/taxonomy-change-command-preview.html
+++ b/waltz-ng/client/taxonomy-management/components/taxonomy-change-command-preview/taxonomy-change-command-preview.html
@@ -40,7 +40,7 @@
+ ng-bind="impact.impactCount">
|
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/assessment_rating/AssessmentRatingService.java b/waltz-service/src/main/java/org/finos/waltz/service/assessment_rating/AssessmentRatingService.java
index 1df1d16b1e..5e0da51388 100644
--- a/waltz-service/src/main/java/org/finos/waltz/service/assessment_rating/AssessmentRatingService.java
+++ b/waltz-service/src/main/java/org/finos/waltz/service/assessment_rating/AssessmentRatingService.java
@@ -34,7 +34,6 @@
import org.finos.waltz.model.rating.RatingSchemeItem;
import org.finos.waltz.service.changelog.ChangeLogService;
import org.finos.waltz.service.permission.permission_checker.AssessmentRatingPermissionChecker;
-import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -103,6 +102,13 @@ public List findByTargetKindForRelatedSelector(EntityKind targ
}
+ public int deleteByAssessmentRatingRelatedSelector(EntityKind targetKind,
+ IdSelectionOptions selectionOptions) {
+ GenericSelector genericSelector = genericSelectorFactory.applyForKind(targetKind, selectionOptions);
+ return assessmentRatingDao.deleteByGenericSelector(genericSelector);
+ }
+
+
public List findByDefinitionId(long definitionId) {
return assessmentRatingDao.findByDefinitionId(definitionId);
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/entity_named_note/EntityNamedNoteService.java b/waltz-service/src/main/java/org/finos/waltz/service/entity_named_note/EntityNamedNoteService.java
index 7a42650065..245a715241 100644
--- a/waltz-service/src/main/java/org/finos/waltz/service/entity_named_note/EntityNamedNoteService.java
+++ b/waltz-service/src/main/java/org/finos/waltz/service/entity_named_note/EntityNamedNoteService.java
@@ -18,13 +18,12 @@
package org.finos.waltz.service.entity_named_note;
+import org.finos.waltz.data.GenericSelector;
+import org.finos.waltz.data.GenericSelectorFactory;
+import org.finos.waltz.model.*;
import org.finos.waltz.service.changelog.ChangeLogService;
import org.finos.waltz.data.entity_named_note.EntityNamedNoteDao;
import org.finos.waltz.data.entity_named_note.EntityNamedNoteTypeDao;
-import org.finos.waltz.model.EntityReference;
-import org.finos.waltz.model.Operation;
-import org.finos.waltz.model.Severity;
-import org.finos.waltz.model.UserTimestamp;
import org.finos.waltz.model.changelog.ChangeLog;
import org.finos.waltz.model.changelog.ImmutableChangeLog;
import org.finos.waltz.model.entity_named_note.EntityNamedNodeType;
@@ -44,7 +43,7 @@ public class EntityNamedNoteService {
private final EntityNamedNoteDao entityNamedNoteDao;
private final EntityNamedNoteTypeDao entityNamedNodeTypeDao;
private final ChangeLogService changeLogService;
-
+ private final GenericSelectorFactory genericSelectorFactory = new GenericSelectorFactory();
@Autowired
public EntityNamedNoteService(EntityNamedNoteDao entityNamedNoteDao,
@@ -128,6 +127,12 @@ public boolean remove(EntityReference ref, String username) {
return rc;
}
+ public int deleteByNamedNoteParentSelector(IdSelectionOptions selectionOptions) {
+ GenericSelector selector = genericSelectorFactory.apply(selectionOptions);
+ return entityNamedNoteDao
+ .deleteByParentSelector(selector);
+ }
+
private void logMsg(EntityReference ref, String username, Operation op, String msg) {
ChangeLog logEntry = ImmutableChangeLog
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/entity_relationship/EntityRelationshipService.java b/waltz-service/src/main/java/org/finos/waltz/service/entity_relationship/EntityRelationshipService.java
index a01d94db17..59fe5cdbfb 100644
--- a/waltz-service/src/main/java/org/finos/waltz/service/entity_relationship/EntityRelationshipService.java
+++ b/waltz-service/src/main/java/org/finos/waltz/service/entity_relationship/EntityRelationshipService.java
@@ -114,4 +114,8 @@ public int deleteForGenericEntitySelector(IdSelectionOptions selectionOptions) {
GenericSelector selector = genericSelectorFactory.apply(selectionOptions);
return entityRelationshipDao.deleteForGenericEntitySelector(selector);
}
+
+ public void migrateEntityRelationships(EntityReference sourceReference, EntityReference targetReference, String userId) {
+ entityRelationshipDao.migrateEntityRelationships(sourceReference, targetReference, userId);
+ }
}
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/measurable/MeasurableService.java b/waltz-service/src/main/java/org/finos/waltz/service/measurable/MeasurableService.java
index 29b7cafbfa..65d89a8857 100644
--- a/waltz-service/src/main/java/org/finos/waltz/service/measurable/MeasurableService.java
+++ b/waltz-service/src/main/java/org/finos/waltz/service/measurable/MeasurableService.java
@@ -249,4 +249,7 @@ public void writeAuditMessage(Long measurableId, String userId, String msg) {
.build());
}
+ public boolean moveChildren(Long measurableId, Long targetMeasurableId, String userId) {
+ return measurableDao.moveChildren(measurableId, targetMeasurableId, userId);
+ }
}
\ No newline at end of file
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/measurable_rating/MeasurableRatingService.java b/waltz-service/src/main/java/org/finos/waltz/service/measurable_rating/MeasurableRatingService.java
index 66ee40f38f..b303a71b55 100644
--- a/waltz-service/src/main/java/org/finos/waltz/service/measurable_rating/MeasurableRatingService.java
+++ b/waltz-service/src/main/java/org/finos/waltz/service/measurable_rating/MeasurableRatingService.java
@@ -288,4 +288,16 @@ private void checkRatingIsAllowable(SaveMeasurableRatingCommand command) {
public boolean checkRatingExists(SaveMeasurableRatingCommand command) {
return measurableRatingDao.checkRatingExists(command);
}
+
+ public void migrateRatings(Long measurableId, Long targetMeasurableId, String userId) {
+ measurableRatingDao.migrateRatings(measurableId, targetMeasurableId, userId);
+ }
+
+ public int getSharedRatingsCount(Long measurableId, Long targetMeasurableId) {
+ return measurableRatingDao.getSharedRatingsCount(measurableId, targetMeasurableId);
+ }
+
+ public int getSharedDecommsCount(Long measurableId, Long targetMeasurableId) {
+ return measurableRatingDao.getSharedDecommsCount(measurableId, targetMeasurableId);
+ }
}
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/TaxonomyManagementUtilities.java b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/TaxonomyManagementUtilities.java
index 1bbea791d0..d1be2ab553 100644
--- a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/TaxonomyManagementUtilities.java
+++ b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/TaxonomyManagementUtilities.java
@@ -37,6 +37,7 @@
import static java.lang.String.format;
import static org.finos.waltz.common.Checks.*;
+import static org.finos.waltz.common.CollectionUtilities.any;
import static org.finos.waltz.common.SetUtilities.fromCollection;
import static org.finos.waltz.common.SetUtilities.minus;
import static org.finos.waltz.model.IdSelectionOptions.mkOpts;
@@ -70,8 +71,8 @@ public static void validateMeasurablesInCategory(MeasurableService measurableSer
public static Measurable validateMeasurableInCategory(MeasurableService measurableService,
- long measurableId,
- long categoryId) {
+ long measurableId,
+ long categoryId) {
Measurable measurable = measurableService.getById(measurableId);
checkNotNull(
@@ -90,6 +91,36 @@ public static Measurable validateMeasurableInCategory(MeasurableService measurab
return measurable;
}
+ public static void validateTargetNotChild(MeasurableService measurableService,
+ Measurable measurable,
+ Measurable targetMeasurable) {
+
+ List children = measurableService.findByMeasurableIdSelector(mkOpts(
+ measurable.entityReference(),
+ HierarchyQueryScope.CHILDREN));
+
+ checkFalse(
+ any(children, d -> d.equals(targetMeasurable)),
+ format("Target measurable [%s / %d] is a child of measurable [%s / %d]",
+ targetMeasurable.name(),
+ targetMeasurable.id().get(),
+ measurable.name(),
+ measurable.id().get()));
+ }
+
+
+ public static void validateConcreteMergeAllowed(Measurable measurable,
+ Measurable targetMeasurable) {
+
+ checkFalse(
+ measurable.concrete() && !targetMeasurable.concrete(),
+ format("Measurable [%s / %d] is concrete but target measurable [%s / %d] is abstract",
+ measurable.name(),
+ measurable.id().get(),
+ targetMeasurable.name(),
+ targetMeasurable.id().get()));
+ }
+
public static Set findCurrentRatingMappings(MeasurableRatingService measurableRatingService,
TaxonomyChangeCommand cmd) {
@@ -106,24 +137,24 @@ public static Set findCurrentRatingMappings(MeasurableRatingSer
* Optionally add an impact to the given preview and return it.
* Whether to add the impact is determined by the presence of references.
*
- * @param preview The preview builder to update
- * @param refs Set of references, if empty no impact will be added to the preview
- * @param severity Severity of the impact
- * @param msg Description of the impact
+ * @param preview The preview builder to update
+ * @param impactCount Count of the records affected by this change
+ * @param severity Severity of the impact
+ * @param msg Description of the impact
* @return The preview builder for convenience
*/
public static ImmutableTaxonomyChangePreview.Builder addToPreview(ImmutableTaxonomyChangePreview.Builder preview,
- Set refs,
+ int impactCount,
Severity severity,
String msg) {
- return refs.isEmpty()
- ? preview
- : preview
+ return impactCount == 0
+ ? preview
+ : preview
.addImpacts(ImmutableTaxonomyChangeImpact.builder()
- .impactedReferences(refs)
- .description(msg)
- .severity(severity)
- .build());
+ .impactCount(impactCount)
+ .description(msg)
+ .severity(severity)
+ .build());
}
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/MergeMeasurableCommandProcessor.java b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/MergeMeasurableCommandProcessor.java
new file mode 100644
index 0000000000..1703983799
--- /dev/null
+++ b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/MergeMeasurableCommandProcessor.java
@@ -0,0 +1,161 @@
+/*
+ * Waltz - Enterprise Architecture
+ * Copyright (C) 2016, 2017, 2018, 2019 Waltz open source project
+ * See README.md for more information
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific
+ *
+ */
+
+package org.finos.waltz.service.taxonomy_management.processors;
+
+import org.finos.waltz.common.Checks;
+import org.finos.waltz.common.DateTimeUtilities;
+import org.finos.waltz.common.SetUtilities;
+import org.finos.waltz.model.EntityKind;
+import org.finos.waltz.model.HierarchyQueryScope;
+import org.finos.waltz.model.IdSelectionOptions;
+import org.finos.waltz.model.measurable.Measurable;
+import org.finos.waltz.model.taxonomy_management.*;
+import org.finos.waltz.service.measurable.MeasurableService;
+import org.finos.waltz.service.taxonomy_management.TaxonomyCommandProcessor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Set;
+
+import static java.lang.String.format;
+import static org.finos.waltz.common.Checks.checkNotNull;
+import static org.finos.waltz.model.IdSelectionOptions.mkOpts;
+import static org.finos.waltz.service.taxonomy_management.TaxonomyManagementUtilities.*;
+
+@Service
+public class MergeMeasurableCommandProcessor implements TaxonomyCommandProcessor {
+
+ private final MeasurableService measurableService;
+ private final TaxonomyManagementHelper taxonomyManagementHelper;
+
+ @Autowired
+ public MergeMeasurableCommandProcessor(MeasurableService measurableService,
+ TaxonomyManagementHelper taxonomyManagementHelper) {
+ checkNotNull(measurableService, "measurableService cannot be null");
+ checkNotNull(taxonomyManagementHelper, "taxonomyManagementHelper cannot be null");
+ this.taxonomyManagementHelper = taxonomyManagementHelper;
+ this.measurableService = measurableService;
+ }
+
+
+ @Override
+ public Set supportedTypes() {
+ return SetUtilities.asSet(TaxonomyChangeType.MERGE);
+ }
+
+
+ @Override
+ public EntityKind domain() {
+ return EntityKind.MEASURABLE_CATEGORY;
+ }
+
+
+ public TaxonomyChangePreview preview(TaxonomyChangeCommand cmd) {
+ Measurable primaryRef = validate(cmd);
+
+ ImmutableTaxonomyChangePreview.Builder previewBuilder = ImmutableTaxonomyChangePreview
+ .builder()
+ .command(ImmutableTaxonomyChangeCommand
+ .copyOf(cmd)
+ .withPrimaryReference(primaryRef.entityReference()));
+
+ IdSelectionOptions opts = IdSelectionOptions.mkOpts(cmd.primaryReference(), HierarchyQueryScope.EXACT);
+
+ taxonomyManagementHelper.previewBookmarkRemovals(previewBuilder, opts);
+ taxonomyManagementHelper.previewInvolvementRemovals(previewBuilder, opts);
+ taxonomyManagementHelper.previewEntityNamedNoteRemovals(previewBuilder, opts);
+ taxonomyManagementHelper.previewAssessmentRemovals(previewBuilder, opts);
+ taxonomyManagementHelper.previewFlowDiagramRemovals(previewBuilder, opts);
+ taxonomyManagementHelper.previewChildNodeMigrations(previewBuilder, opts);
+
+ Long target = getTarget(cmd);
+
+ if (target != null) {
+ taxonomyManagementHelper.previewRatingMigrations(previewBuilder, opts.entityReference().id(), target);
+ taxonomyManagementHelper.previewDecommMigrations(previewBuilder, opts.entityReference().id(), target);
+ }
+
+ ImmutableTaxonomyChangePreview preview = previewBuilder.build();
+
+ return preview;
+ }
+
+
+ public TaxonomyChangeCommand apply(TaxonomyChangeCommand cmd, String userId) {
+
+ Measurable measurableToMerge = validate(cmd);
+ Long target = getTarget(cmd);
+ checkNotNull(target, "Target cannot be null when migrating a measurable");
+
+ String targetName = getTargetName(cmd);
+ IdSelectionOptions selectionOptions = mkOpts(measurableToMerge.entityReference(), HierarchyQueryScope.EXACT); // children are migrated, do not want to delete their data
+
+ taxonomyManagementHelper.migrateMeasurable(selectionOptions, target, userId);
+
+ int removedBookmarks = taxonomyManagementHelper.removeBookmarks(selectionOptions);
+ int removedInvolvements = taxonomyManagementHelper.removeInvolvements(selectionOptions);
+ int removedNotes = taxonomyManagementHelper.removeNamedNotes(selectionOptions);
+ int removedDiagrams = taxonomyManagementHelper.removeFlowDiagrams(selectionOptions);
+ int removedAssessments = taxonomyManagementHelper.removeAssessments(EntityKind.MEASURABLE, selectionOptions);
+
+ String message = format("Merged measurable: %s [%d] into target: %s [%d] - Removed: %d bookmarks; %d involvements; %d notes; %d flow diagram relationships; %d assessments",
+ measurableToMerge.name(),
+ measurableToMerge.id().get(),
+ targetName,
+ target,
+ removedBookmarks,
+ removedInvolvements,
+ removedNotes,
+ removedDiagrams,
+ removedAssessments);
+
+ measurableService.writeAuditMessage(target, userId, message);
+
+ return ImmutableTaxonomyChangeCommand
+ .copyOf(cmd)
+ .withLastUpdatedAt(DateTimeUtilities.nowUtc())
+ .withLastUpdatedBy(userId)
+ .withStatus(TaxonomyChangeLifecycleStatus.EXECUTED);
+ }
+
+
+ private Measurable validate(TaxonomyChangeCommand cmd) {
+ doBasicValidation(cmd);
+ long categoryId = cmd.changeDomain().id();
+ Measurable measurable = validateMeasurableInCategory(measurableService, cmd.primaryReference().id(), categoryId);
+ Long targetId = getTarget(cmd);
+ if (targetId != null) {
+ Measurable target = validateMeasurableInCategory(measurableService, targetId, categoryId);
+ validateTargetNotChild(measurableService, measurable, target);
+ validateConcreteMergeAllowed(measurable, target);
+ }
+ return measurable;
+ }
+
+
+ private Long getTarget(TaxonomyChangeCommand cmd) {
+ return cmd.paramAsLong("targetId", null);
+ }
+
+
+ private String getTargetName(TaxonomyChangeCommand cmd) {
+ return cmd.param("targetName");
+ }
+
+}
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/RemoveMeasurableCommandProcessor.java b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/RemoveMeasurableCommandProcessor.java
index a2c088d810..ecbfa03ad5 100644
--- a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/RemoveMeasurableCommandProcessor.java
+++ b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/RemoveMeasurableCommandProcessor.java
@@ -51,34 +51,16 @@
@Service
public class RemoveMeasurableCommandProcessor implements TaxonomyCommandProcessor {
- private final BookmarkService bookmarkService;
- private final EntityRelationshipService entityRelationshipService;
- private final FlowDiagramEntityService flowDiagramEntityService;
- private final InvolvementService involvementService;
- private final MeasurableRatingService measurableRatingService;
private final MeasurableService measurableService;
-
+ private final TaxonomyManagementHelper taxonomyManagementHelper;
@Autowired
- public RemoveMeasurableCommandProcessor(BookmarkService bookmarkService,
- EntityRelationshipService entityRelationshipService,
- FlowDiagramEntityService flowDiagramEntityService,
- InvolvementService involvementService,
- MeasurableRatingService measurableRatingService,
- MeasurableService measurableService) {
- checkNotNull(bookmarkService, "bookmarkService cannot be null");
- checkNotNull(entityRelationshipService, "entityRelationshipService cannot be null");
- checkNotNull(flowDiagramEntityService, "flowDiagramEntityService cannot be null");
- checkNotNull(involvementService, "involvementService cannot be null");
- checkNotNull(measurableRatingService, "measurableRatingService cannot be null");
+ public RemoveMeasurableCommandProcessor(MeasurableService measurableService,
+ TaxonomyManagementHelper taxonomyManagementHelper) {
checkNotNull(measurableService, "measurableService cannot be null");
- this.bookmarkService = bookmarkService;
- this.entityRelationshipService = entityRelationshipService;
- this.flowDiagramEntityService = flowDiagramEntityService;
- this.involvementService = involvementService;
- this.measurableRatingService = measurableRatingService;
this.measurableService = measurableService;
+ this.taxonomyManagementHelper = taxonomyManagementHelper;
}
@@ -106,110 +88,34 @@ public TaxonomyChangePreview preview(TaxonomyChangeCommand cmd) {
IdSelectionOptions selectionOptions = mkOpts(cmd.primaryReference(), HierarchyQueryScope.CHILDREN);
- previewChildNodeRemovals(preview, selectionOptions);
- previewAppMappingRemovals(preview, selectionOptions);
- previewBookmarkRemovals(preview, selectionOptions);
- previewInvolvementRemovals(preview, selectionOptions);
- previewFlowDiagramRemovals(preview, selectionOptions);
- previewEntityRelationships(preview, selectionOptions);
+ taxonomyManagementHelper.previewChildNodeRemovals(preview, selectionOptions);
+ taxonomyManagementHelper.previewAppMappingRemovals(preview, selectionOptions);
+ taxonomyManagementHelper.previewBookmarkRemovals(preview, selectionOptions);
+ taxonomyManagementHelper.previewInvolvementRemovals(preview, selectionOptions);
+ taxonomyManagementHelper.previewFlowDiagramRemovals(preview, selectionOptions);
+ taxonomyManagementHelper.previewEntityRelationships(preview, selectionOptions);
// TODO: entitySvgDiagrams, roadmapScenarios
return preview.build();
}
-
- private void previewEntityRelationships(ImmutableTaxonomyChangePreview.Builder preview,
- IdSelectionOptions options) {
- Set refs = entityRelationshipService
- .findForGenericEntitySelector(options)
- .stream()
- .flatMap(rel -> Stream.of(rel.a(), rel.b()))
- .filter(ref -> !ref.equals(options.entityReference()))
- .collect(Collectors.toSet());
-
- addToPreview(
- preview,
- refs,
- Severity.WARNING,
- "Entity Relationships will be removed");
- }
-
-
- private void previewFlowDiagramRemovals(ImmutableTaxonomyChangePreview.Builder preview,
- IdSelectionOptions selectionOptions) {
-
- Set refs = flowDiagramEntityService
- .findForEntitySelector(selectionOptions)
- .stream()
- .map(FlowDiagramEntity::entityReference)
- .collect(Collectors.toSet());
-
- addToPreview(
- preview,
- refs,
- Severity.WARNING,
- "Relationships to flow diagrams will be removed");
-
- }
-
-
- private void previewInvolvementRemovals(ImmutableTaxonomyChangePreview.Builder preview,
- IdSelectionOptions selectionOptions) {
- addToPreview(
- preview,
- map(involvementService.findByGenericEntitySelector(selectionOptions), Involvement::entityReference),
- Severity.ERROR,
- "Involvements (links to people) associated to this item (or it's children) will be removed");
- }
-
-
- private void previewBookmarkRemovals(ImmutableTaxonomyChangePreview.Builder preview,
- IdSelectionOptions selectionOptions) {
- Set bookmarks = bookmarkService.findByBookmarkIdSelector(selectionOptions);
- addToPreview(
- preview,
- map(bookmarks, Bookmark::entityReference),
- Severity.ERROR,
- "Bookmarks associated to this item (or it's children) will be removed");
- }
-
-
- private void previewAppMappingRemovals(ImmutableTaxonomyChangePreview.Builder preview,
- IdSelectionOptions selectionOptions) {
- List ratings = measurableRatingService.findByMeasurableIdSelector(selectionOptions);
- addToPreview(
- preview,
- map(ratings, MeasurableRating::entityReference),
- Severity.ERROR,
- "Application ratings associated to this item (or it's children) will be removed");
- }
-
-
- private void previewChildNodeRemovals(ImmutableTaxonomyChangePreview.Builder preview,
- IdSelectionOptions selectionOptions) {
- Set childRefs = map(measurableService.findByMeasurableIdSelector(selectionOptions), Measurable::entityReference);
- addToPreview(
- preview,
- minus(childRefs, asSet(selectionOptions.entityReference())),
- Severity.ERROR,
- "This node has child nodes which will also be removed");
- }
-
-
public TaxonomyChangeCommand apply(TaxonomyChangeCommand cmd, String userId) {
doBasicValidation(cmd);
Measurable measurable = validatePrimaryMeasurable(measurableService, cmd);
IdSelectionOptions selectionOptions = mkOpts(cmd.primaryReference(), HierarchyQueryScope.CHILDREN);
- removeBookmarks(selectionOptions);
- removeInvolvements(selectionOptions);
- removeAppMappings(selectionOptions);
- removeMeasurables(selectionOptions);
- removeFlowDiagrams(selectionOptions);
- removeEntityRelationshipsDiagrams(selectionOptions);
-
+ taxonomyManagementHelper.removeBookmarks(selectionOptions);
+ taxonomyManagementHelper.removeInvolvements(selectionOptions);
+ taxonomyManagementHelper.removeAppMappings(selectionOptions);
+ taxonomyManagementHelper.removeMeasurables(selectionOptions);
+ taxonomyManagementHelper.removeFlowDiagrams(selectionOptions);
+ taxonomyManagementHelper.removeEntityRelationshipsDiagrams(selectionOptions);
+ taxonomyManagementHelper.removeAssessments(EntityKind.MEASURABLE, selectionOptions);
+ taxonomyManagementHelper.removeNamedNotes(selectionOptions);
+
+
String message = String.format("Measurable %s has been removed", measurable.name());
Optional measurableId = measurable.parentId().isPresent()
? measurable.parentId()
@@ -218,40 +124,13 @@ public TaxonomyChangeCommand apply(TaxonomyChangeCommand cmd, String userId) {
// TODO: entitySvgDiagrams, roadmapScenarios
- return ImmutableTaxonomyChangeCommand.copyOf(cmd)
+ return ImmutableTaxonomyChangeCommand
+ .copyOf(cmd)
.withStatus(TaxonomyChangeLifecycleStatus.EXECUTED)
.withLastUpdatedBy(userId)
.withLastUpdatedAt(DateTimeUtilities.nowUtc());
}
- private int removeEntityRelationshipsDiagrams(IdSelectionOptions selectionOptions) {
- return entityRelationshipService.deleteForGenericEntitySelector(selectionOptions);
- }
-
-
- private int removeFlowDiagrams(IdSelectionOptions selectionOptions) {
- return flowDiagramEntityService.deleteForEntitySelector(selectionOptions);
- }
-
-
- private int removeMeasurables(IdSelectionOptions selectionOptions) {
- return measurableService.deleteByIdSelector(selectionOptions);
- }
-
-
- private int removeAppMappings(IdSelectionOptions selectionOptions) {
- return measurableRatingService.deleteByMeasurableIdSelector(selectionOptions);
- }
-
-
- private int removeInvolvements(IdSelectionOptions selectionOptions) {
- return involvementService.deleteByGenericEntitySelector(selectionOptions);
- }
-
-
- private int removeBookmarks(IdSelectionOptions selectionOptions) {
- return bookmarkService.deleteByBookmarkIdSelector(selectionOptions);
- }
}
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/TaxonomyManagementHelper.java b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/TaxonomyManagementHelper.java
new file mode 100644
index 0000000000..e81e6ea1c1
--- /dev/null
+++ b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/TaxonomyManagementHelper.java
@@ -0,0 +1,266 @@
+package org.finos.waltz.service.taxonomy_management.processors;
+
+import org.finos.waltz.model.*;
+import org.finos.waltz.model.assessment_rating.AssessmentRating;
+import org.finos.waltz.model.bookmark.Bookmark;
+import org.finos.waltz.model.entity_named_note.EntityNamedNote;
+import org.finos.waltz.model.entity_relationship.EntityRelationship;
+import org.finos.waltz.model.flow_diagram.FlowDiagramEntity;
+import org.finos.waltz.model.involvement.Involvement;
+import org.finos.waltz.model.measurable.Measurable;
+import org.finos.waltz.model.measurable_rating.MeasurableRating;
+import org.finos.waltz.model.taxonomy_management.ImmutableTaxonomyChangePreview;
+import org.finos.waltz.service.assessment_rating.AssessmentRatingService;
+import org.finos.waltz.service.bookmark.BookmarkService;
+import org.finos.waltz.service.entity_named_note.EntityNamedNoteService;
+import org.finos.waltz.service.entity_relationship.EntityRelationshipService;
+import org.finos.waltz.service.flow_diagram.FlowDiagramEntityService;
+import org.finos.waltz.service.involvement.InvolvementService;
+import org.finos.waltz.service.measurable.MeasurableService;
+import org.finos.waltz.service.measurable_rating.MeasurableRatingService;
+import org.finos.waltz.service.measurable_rating_planned_decommission.MeasurableRatingPlannedDecommissionService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import static org.finos.waltz.common.Checks.checkNotNull;
+import static org.finos.waltz.common.SetUtilities.*;
+import static org.finos.waltz.model.EntityReference.mkRef;
+import static org.finos.waltz.service.taxonomy_management.TaxonomyManagementUtilities.addToPreview;
+
+@Service
+public class TaxonomyManagementHelper {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TaxonomyManagementHelper.class);
+
+ private final BookmarkService bookmarkService;
+ private final EntityRelationshipService entityRelationshipService;
+ private final FlowDiagramEntityService flowDiagramEntityService;
+ private final InvolvementService involvementService;
+ private final MeasurableRatingService measurableRatingService;
+ private final MeasurableService measurableService;
+ private final EntityNamedNoteService entityNamedNoteService;
+ private final AssessmentRatingService assessmentRatingService;
+
+ @Autowired
+ public TaxonomyManagementHelper(BookmarkService bookmarkService,
+ EntityRelationshipService entityRelationshipService,
+ FlowDiagramEntityService flowDiagramEntityService,
+ InvolvementService involvementService,
+ MeasurableRatingService measurableRatingService,
+ MeasurableService measurableService,
+ EntityNamedNoteService entityNamedNoteService,
+ AssessmentRatingService assessmentRatingService) {
+
+ checkNotNull(bookmarkService, "bookmarkService cannot be null");
+ checkNotNull(entityRelationshipService, "entityRelationshipService cannot be null");
+ checkNotNull(flowDiagramEntityService, "flowDiagramEntityService cannot be null");
+ checkNotNull(involvementService, "involvementService cannot be null");
+ checkNotNull(measurableRatingService, "measurableRatingService cannot be null");
+ checkNotNull(measurableService, "measurableService cannot be null");
+ checkNotNull(entityNamedNoteService, "entityNamedNoteService cannot be null");
+ checkNotNull(assessmentRatingService, "assessmentRatingService cannot be null");
+
+ this.assessmentRatingService = assessmentRatingService;
+ this.bookmarkService = bookmarkService;
+ this.entityNamedNoteService = entityNamedNoteService;
+ this.entityRelationshipService = entityRelationshipService;
+ this.flowDiagramEntityService = flowDiagramEntityService;
+ this.involvementService = involvementService;
+ this.measurableRatingService = measurableRatingService;
+ this.measurableService = measurableService;
+ }
+
+
+ // PREVIEWS
+
+ public void previewEntityRelationships(ImmutableTaxonomyChangePreview.Builder preview,
+ IdSelectionOptions options) {
+
+ Collection rels = entityRelationshipService.findForGenericEntitySelector(options);
+
+ addToPreview(
+ preview,
+ rels.size(),
+ Severity.WARNING,
+ "Entity Relationships will be removed");
+ }
+
+
+ public void previewFlowDiagramRemovals(ImmutableTaxonomyChangePreview.Builder preview,
+ IdSelectionOptions selectionOptions) {
+
+ List diagrams = flowDiagramEntityService.findForEntitySelector(selectionOptions);
+
+ addToPreview(
+ preview,
+ diagrams.size(),
+ Severity.WARNING,
+ "Relationships to flow diagrams will be removed");
+
+ }
+
+ public void previewInvolvementRemovals(ImmutableTaxonomyChangePreview.Builder preview,
+ IdSelectionOptions selectionOptions) {
+ Collection involvements = involvementService.findByGenericEntitySelector(selectionOptions);
+ addToPreview(
+ preview,
+ involvements.size(),
+ Severity.ERROR,
+ "Involvements (links to people) associated to this item (or it's children) will be removed");
+ }
+
+ public void previewEntityNamedNoteRemovals(ImmutableTaxonomyChangePreview.Builder preview,
+ IdSelectionOptions selectionOptions) {
+
+ List notes = entityNamedNoteService.findByEntityReference(selectionOptions.entityReference());
+ addToPreview(
+ preview,
+ notes.size(),
+ Severity.ERROR,
+ "Entity named notes associated to this item will be removed");
+ }
+
+
+ public void previewAssessmentRemovals(ImmutableTaxonomyChangePreview.Builder preview,
+ IdSelectionOptions selectionOptions) {
+
+ List assessmentRatings = assessmentRatingService.findByTargetKindForRelatedSelector(EntityKind.MEASURABLE, selectionOptions);
+ addToPreview(
+ preview,
+ assessmentRatings.size(),
+ Severity.ERROR,
+ "Assessments associated to this item will be removed");
+ }
+
+
+ public void previewBookmarkRemovals(ImmutableTaxonomyChangePreview.Builder preview,
+ IdSelectionOptions selectionOptions) {
+ Set bookmarks = bookmarkService.findByBookmarkIdSelector(selectionOptions);
+ addToPreview(
+ preview,
+ bookmarks.size(),
+ Severity.ERROR,
+ "Bookmarks associated to this item will be removed");
+ }
+
+
+ public void previewAppMappingRemovals(ImmutableTaxonomyChangePreview.Builder preview,
+ IdSelectionOptions selectionOptions) {
+ List ratings = measurableRatingService.findByMeasurableIdSelector(selectionOptions);
+ addToPreview(
+ preview,
+ ratings.size(),
+ Severity.ERROR,
+ "Application ratings associated to this item (or it's children) will be removed");
+ }
+
+
+ public void previewChildNodeRemovals(ImmutableTaxonomyChangePreview.Builder preview,
+ IdSelectionOptions selectionOptions) {
+ Set childRefs = map(measurableService.findByMeasurableIdSelector(selectionOptions), Measurable::entityReference);
+ addToPreview(
+ preview,
+ minus(childRefs, asSet(selectionOptions.entityReference())).size(),
+ Severity.ERROR,
+ "This node has child nodes which will also be removed");
+ }
+
+ public void previewChildNodeMigrations(ImmutableTaxonomyChangePreview.Builder preview,
+ IdSelectionOptions selectionOptions) {
+
+ ImmutableIdSelectionOptions hierarchySelector = ImmutableIdSelectionOptions.copyOf(selectionOptions).withScope(HierarchyQueryScope.CHILDREN);
+
+ Set childRefs = map(measurableService.findByMeasurableIdSelector(hierarchySelector), Measurable::entityReference);
+
+ addToPreview(
+ preview,
+ minus(childRefs, asSet(selectionOptions.entityReference())).size(),
+ Severity.WARNING,
+ "This node has child nodes which will be migrated to the new target");
+ }
+
+ public void previewRatingMigrations(ImmutableTaxonomyChangePreview.Builder preview,
+ Long measurableId,
+ Long targetId) {
+
+ int sharedRatingsCount = measurableRatingService.getSharedRatingsCount(measurableId, targetId);
+
+ addToPreview(
+ preview,
+ sharedRatingsCount,
+ Severity.WARNING,
+ "This node has measurable ratings that cannot be migrated due to an existing rating on the target");
+ }
+
+ public void previewDecommMigrations(ImmutableTaxonomyChangePreview.Builder preview,
+ Long measurableId,
+ Long targetId) {
+
+ int sharedDecommsCount = measurableRatingService.getSharedDecommsCount(measurableId, targetId);
+
+ addToPreview(
+ preview,
+ sharedDecommsCount,
+ Severity.WARNING,
+ "This node has measurable rating planned decommission dates that cannot be migrated due to an existing decom on the target rating");
+ }
+
+
+ // ACTIONS
+
+ public void migrateMeasurable(IdSelectionOptions selectionOptions, Long targetId, String userId) {
+
+ EntityReference sourceMeasurable = selectionOptions.entityReference();
+ EntityReference targetMeasurable = mkRef(EntityKind.MEASURABLE, targetId);
+
+ measurableService.moveChildren(sourceMeasurable.id(), targetId, userId);
+ measurableRatingService.migrateRatings(sourceMeasurable.id(), targetId, userId);
+ entityRelationshipService.migrateEntityRelationships(sourceMeasurable, targetMeasurable, userId);
+ measurableService.deleteByIdSelector(selectionOptions);
+ }
+
+ public int removeEntityRelationshipsDiagrams(IdSelectionOptions selectionOptions) {
+ return entityRelationshipService.deleteForGenericEntitySelector(selectionOptions);
+ }
+
+
+ public int removeFlowDiagrams(IdSelectionOptions selectionOptions) {
+ return flowDiagramEntityService.deleteForEntitySelector(selectionOptions);
+ }
+
+
+ public int removeMeasurables(IdSelectionOptions selectionOptions) {
+ return measurableService.deleteByIdSelector(selectionOptions);
+ }
+
+
+ public int removeAppMappings(IdSelectionOptions selectionOptions) {
+ return measurableRatingService.deleteByMeasurableIdSelector(selectionOptions);
+ }
+
+
+ public int removeInvolvements(IdSelectionOptions selectionOptions) {
+ return involvementService.deleteByGenericEntitySelector(selectionOptions);
+ }
+
+
+ public int removeBookmarks(IdSelectionOptions selectionOptions) {
+ return bookmarkService.deleteByBookmarkIdSelector(selectionOptions);
+ }
+
+
+ public int removeAssessments(EntityKind targetKind, IdSelectionOptions selectionOptions) {
+ return assessmentRatingService.deleteByAssessmentRatingRelatedSelector(targetKind, selectionOptions);
+ }
+
+ public int removeNamedNotes(IdSelectionOptions selectionOptions) {
+ return entityNamedNoteService.deleteByNamedNoteParentSelector(selectionOptions);
+ }
+
+}
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableConcreteFlagCommandProcessor.java b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableConcreteFlagCommandProcessor.java
index 30a60d8489..4d547453be 100644
--- a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableConcreteFlagCommandProcessor.java
+++ b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableConcreteFlagCommandProcessor.java
@@ -83,7 +83,7 @@ public TaxonomyChangePreview preview(TaxonomyChangeCommand cmd) {
if (!newValue) {
addToPreview(
preview,
- findCurrentRatingMappings(measurableRatingService, cmd),
+ findCurrentRatingMappings(measurableRatingService, cmd).size(),
Severity.WARNING,
"Current app mappings exist to item, these will be invalid when the item becomes non-concrete");
}
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableDescriptionCommandProcessor.java b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableDescriptionCommandProcessor.java
index 19d79fa867..746df2e6ca 100644
--- a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableDescriptionCommandProcessor.java
+++ b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableDescriptionCommandProcessor.java
@@ -34,6 +34,7 @@
import static org.finos.waltz.common.Checks.checkNotNull;
import static org.finos.waltz.common.SetUtilities.asSet;
+import static org.finos.waltz.service.taxonomy_management.TaxonomyManagementUtilities.findCurrentRatingMappings;
@Service
public class UpdateMeasurableDescriptionCommandProcessor implements TaxonomyCommandProcessor {
@@ -79,10 +80,10 @@ public TaxonomyChangePreview preview(TaxonomyChangeCommand cmd) {
}
TaxonomyManagementUtilities.addToPreview(
- preview,
- TaxonomyManagementUtilities.findCurrentRatingMappings(measurableRatingService, cmd),
- Severity.INFORMATION,
- "Current app mappings exist to item, these may be misleading if the description change alters the meaning of this item");
+ preview,
+ findCurrentRatingMappings(measurableRatingService, cmd).size(),
+ Severity.INFORMATION,
+ "Current app mappings exist to item, these may be misleading if the description change alters the meaning of this item");
return preview.build();
diff --git a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableNameCommandProcessor.java b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableNameCommandProcessor.java
index fbd6ebdd03..006f341fd8 100644
--- a/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableNameCommandProcessor.java
+++ b/waltz-service/src/main/java/org/finos/waltz/service/taxonomy_management/processors/UpdateMeasurableNameCommandProcessor.java
@@ -84,10 +84,10 @@ public TaxonomyChangePreview preview(TaxonomyChangeCommand cmd) {
}
addToPreview(
- preview,
- findCurrentRatingMappings(measurableRatingService, cmd),
- Severity.INFORMATION,
- "Current app mappings exist to item, these may be misleading if the name change alters the meaning of this item");
+ preview,
+ findCurrentRatingMappings(measurableRatingService, cmd).size(),
+ Severity.INFORMATION,
+ "Current app mappings exist to item, these may be misleading if the name change alters the meaning of this item");
return preview.build();
}