Skip to content

Commit

Permalink
Primary Measurable Ratings
Browse files Browse the repository at this point in the history
- admin screens
- editor changes
- ddl

#CTCTOWALTZ-2746
finos#6635
  • Loading branch information
db-waltz committed Jun 19, 2023
2 parents d83aa34 + b81f23d commit 84972f1
Show file tree
Hide file tree
Showing 31 changed files with 9,678 additions and 209 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ public class MeasurableIdSelectorFactory implements IdSelectorFactory {
private final OrganisationalUnitIdSelectorFactory orgUnitIdSelectorFactory = new OrganisationalUnitIdSelectorFactory();


/**
* @param measurableId the identifier of the measurable to start from
* @return a selector which gives all measurable ids that belong to the same category as the given measurable id
*/
public static SelectConditionStep<Record1<Long>> allMeasurablesIdsInSameCategory(Long measurableId) {
return DSL
.select(MEASURABLE.ID)
.from(MEASURABLE)
.where(MEASURABLE.MEASURABLE_CATEGORY_ID.eq(DSL
.select(MEASURABLE.MEASURABLE_CATEGORY_ID)
.from(MEASURABLE)
.where(MEASURABLE.ID.eq(measurableId))));
}

@Override
public Select<Record1<Long>> apply(IdSelectionOptions options) {
switch (options.entityReference().kind()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public class MeasurableCategoryDao {
.constrainingAssessmentDefinitionId(Optional.ofNullable(r.getConstrainingAssessmentDefinitionId()))
.icon(r.getIconName())
.position(r.getPosition())
.allowPrimaryRatings(r.getAllowPrimaryRatings())
.build();
};

Expand Down Expand Up @@ -127,6 +128,7 @@ public boolean save(MeasurableCategory measurableCategory, String username) {
record.setLastUpdatedAt(DateTimeUtilities.nowUtcTimestamp());
record.setLastUpdatedBy(username);
record.setRatingSchemeId(measurableCategory.ratingSchemeId());
record.setAllowPrimaryRatings(measurableCategory.allowPrimaryRatings());

record.changed(MEASURABLE_CATEGORY.ID, false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public class MeasurableRatingDao {
.lastUpdatedAt(toLocalDateTime(r.getLastUpdatedAt()))
.lastUpdatedBy(r.getLastUpdatedBy())
.isReadOnly(r.getIsReadonly())
.isPrimary(r.getIsPrimary())
.build();
};

Expand All @@ -129,6 +130,7 @@ public class MeasurableRatingDao {
record.setLastUpdatedAt(Timestamp.valueOf(command.lastUpdate().at()));
record.setLastUpdatedBy(command.lastUpdate().by());
record.setProvenance(command.provenance());
record.setIsPrimary(command.isPrimary());
return record;
};

Expand Down Expand Up @@ -157,6 +159,7 @@ public Operation save(SaveMeasurableRatingCommand command, boolean ignoreReadOnl
.set(MEASURABLE_RATING.LAST_UPDATED_BY, command.lastUpdate().by())
.set(MEASURABLE_RATING.LAST_UPDATED_AT, command.lastUpdate().atTimestamp())
.set(MEASURABLE_RATING.PROVENANCE, command.provenance())
.set(MEASURABLE_RATING.IS_PRIMARY, command.isPrimary())
.where(MEASURABLE_RATING.ENTITY_ID.eq(command.entityReference().id()))
.and(MEASURABLE_RATING.ENTITY_KIND.eq(command.entityReference().kind().name()))
.and(MEASURABLE_RATING.MEASURABLE_ID.eq(command.measurableId()))
Expand All @@ -169,15 +172,15 @@ public Operation save(SaveMeasurableRatingCommand command, boolean ignoreReadOnl
throw new NotFoundException(
"MR_SAVE_UPDATE_FAILED",
format("Could find writable associated record to update for rating: %s", command));
};
}
return Operation.UPDATE;
} else {
if (dsl.executeInsert(record) != 1) {
throw new NotFoundException(
"MR_SAVE_INSERT_FAILED",
format("Creation of record failed: %s", command));
}
;

return Operation.ADD;
}
}
Expand Down Expand Up @@ -269,7 +272,8 @@ public List<Tally<Long>> tallyByMeasurableCategoryId(long categoryId) {


public List<MeasurableRatingTally> statsByAppSelector(Select<Record1<Long>> selector) {
return dsl.select(MEASURABLE_RATING.MEASURABLE_ID, MEASURABLE_RATING.RATING, DSL.count())
return dsl
.select(MEASURABLE_RATING.MEASURABLE_ID, MEASURABLE_RATING.RATING, DSL.count())
.from(MEASURABLE_RATING)
.where(dsl.renderInlined(MEASURABLE_RATING.ENTITY_KIND.eq(EntityKind.APPLICATION.name())
.and(MEASURABLE_RATING.ENTITY_ID.in(selector))))
Expand Down Expand Up @@ -334,6 +338,7 @@ private SelectJoinStep<Record> mkBaseQuery() {
.from(MEASURABLE_RATING);
}


public Set<Operation> calculateAmendedRatingOperations(Set<Operation> operationsForEntityAssessment,
EntityReference entityReference,
long measurableId,
Expand Down Expand Up @@ -367,6 +372,7 @@ public Set<Operation> calculateAmendedRatingOperations(Set<Operation> operations
}
}


public Set<Operation> calculateAmendedAllocationOperations(Set<Operation> operationsForAllocation,
long categoryId,
String username) {
Expand All @@ -384,9 +390,9 @@ public Set<Operation> calculateAmendedAllocationOperations(Set<Operation> operat
} else {
return operationsForAllocation;
}

}


/**
* 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.
Expand Down Expand Up @@ -564,7 +570,10 @@ public void migrateRatings(Long measurableId, Long targetId, String userId) {
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),
format("Removed %d ratings from measurable: %d where they could not be migrated due to an existing rating on the target (%d)",
removedRatings,
measurableId,
targetId),
userId);
}

Expand Down Expand Up @@ -605,13 +614,15 @@ private SelectOrderByStep<Record2<Long, String>> selectRatingsThatCanBeModified(
return migrations.except(targets);
}


private SelectConditionStep<Record2<Long, String>> 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<Record2<Long, String>> targets = mkEntitySelectForMeasurable(targetId);
Expand All @@ -622,6 +633,7 @@ public int getSharedRatingsCount(Long measurableId, Long targetId) {
return dsl.fetchCount(sharedRatings);
}


public int getSharedDecommsCount(Long measurableId, Long targetId) {

SelectConditionStep<Record2<Long, String>> targets = mkEntitySelectForDecomm(targetId);
Expand Down Expand Up @@ -679,6 +691,7 @@ private SelectOrderByStep<Record3<Long, Long, String>> selectAllocsToBeSummed(Lo
return migrations.intersect(targets);
}


private SelectHavingStep<Record4<Long, Long, String, Integer>> selectAllocsToBeUpdated(Long measurableId, Long targetId) {

SelectOrderByStep<Record3<Long, Long, String>> valuesToBeSummed = selectAllocsToBeSummed(measurableId, targetId);
Expand All @@ -689,11 +702,45 @@ private SelectHavingStep<Record4<Long, Long, String, Integer>> selectAllocsToBeU
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))
.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);
}



public boolean saveRatingItem(EntityReference entityRef,
long measurableId,
String ratingCode,
String username) {
return MeasurableRatingHelper.saveRatingItem(
dsl,
entityRef,
measurableId,
ratingCode,
username);
}


public boolean saveRatingIsPrimary(EntityReference entityRef, long measurableId, boolean isPrimary, String username) {
return dsl.transactionResult(ctx -> MeasurableRatingHelper.saveRatingIsPrimary(
ctx.dsl(),
entityRef,
measurableId,
isPrimary,
username));
}


public boolean saveRatingDescription(EntityReference entityRef, long measurableId, String description, String username) {
return dsl.transactionResult(ctx -> MeasurableRatingHelper.saveRatingDescription(
ctx.dsl(),
entityRef,
measurableId,
description,
username));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package org.finos.waltz.data.measurable_rating;

import org.finos.waltz.model.EntityReference;
import org.finos.waltz.schema.tables.records.MeasurableRatingRecord;
import org.jooq.Condition;
import org.jooq.DSLContext;
import org.jooq.impl.DSL;

import static org.finos.waltz.common.DateTimeUtilities.nowUtcTimestamp;
import static org.finos.waltz.data.measurable.MeasurableIdSelectorFactory.allMeasurablesIdsInSameCategory;
import static org.finos.waltz.schema.tables.MeasurableRating.MEASURABLE_RATING;

public class MeasurableRatingHelper {

/**
* Updates the given measurable rating to be set as primary.
* All other ratings for the same entity/category will be set to non-primary.
*
* @param tx the dsl connection to use
* @param ref the entity ref
* @param measurableId the measurable id
* @param isPrimary the new value of the isPrimary flag
*/
public static boolean saveRatingIsPrimary(DSLContext tx,
EntityReference ref,
long measurableId,
boolean isPrimary,
String username) {
tx.update(MEASURABLE_RATING)
.set(MEASURABLE_RATING.IS_PRIMARY, false)
.where(MEASURABLE_RATING.ENTITY_ID.eq(ref.id())
.and(MEASURABLE_RATING.ENTITY_KIND.eq(ref.kind().name()))
.and(MEASURABLE_RATING.MEASURABLE_ID.in(allMeasurablesIdsInSameCategory(measurableId))))
.execute();

if (isPrimary) {
// only update if we are setting to true as false case dealt with above
tx.update(MEASURABLE_RATING)
.set(MEASURABLE_RATING.IS_PRIMARY, true)
.set(MEASURABLE_RATING.LAST_UPDATED_BY, username)
.set(MEASURABLE_RATING.LAST_UPDATED_AT, nowUtcTimestamp())
.where(mkPkCondition(ref, measurableId))
.execute();
}

return true;
}


public static boolean saveRatingDescription(DSLContext tx,
EntityReference entityRef,
long measurableId,
String description,
String username) {
return tx
.update(MEASURABLE_RATING)
.set(MEASURABLE_RATING.DESCRIPTION, description)
.set(MEASURABLE_RATING.LAST_UPDATED_BY, username)
.set(MEASURABLE_RATING.LAST_UPDATED_AT, nowUtcTimestamp())
.where(mkPkCondition(entityRef, measurableId))
.execute() == 1;
}


/**
* @param tx
* @param entityRef
* @param measurableId
* @param ratingCode
* @param username
* @return
*/
public static boolean saveRatingItem(DSLContext tx,
EntityReference entityRef,
long measurableId,
String ratingCode,
String username) {

boolean exists = doesRatingExist(tx, entityRef, measurableId);

if (exists) {
int rc = tx
.update(MEASURABLE_RATING)
.set(MEASURABLE_RATING.RATING, ratingCode)
.set(MEASURABLE_RATING.LAST_UPDATED_BY, username)
.set(MEASURABLE_RATING.LAST_UPDATED_AT, nowUtcTimestamp())
.where(mkPkCondition(entityRef, measurableId))
.execute();
return rc == 1;
} else {
MeasurableRatingRecord r = tx.newRecord(MEASURABLE_RATING);

r.setRating(ratingCode);
r.setDescription(null);
r.setLastUpdatedBy(username);
r.setLastUpdatedAt(nowUtcTimestamp());
r.setEntityId(entityRef.id());
r.setEntityKind(entityRef.kind().name());
r.setMeasurableId(measurableId);
r.setProvenance("waltz");

int rc = r.insert();
return rc == 1;
}
}


public static boolean doesRatingExist(DSLContext tx,
EntityReference entityRef,
long measurableId) {
return tx
.fetchExists(DSL
.select(DSL.val(1))
.from(MEASURABLE_RATING)
.where(mkPkCondition(entityRef, measurableId)));

}


private static Condition mkPkCondition(EntityReference entityRef,
long measurableId) {
return MEASURABLE_RATING.MEASURABLE_ID.eq(measurableId)
.and(MEASURABLE_RATING.ENTITY_ID.eq(entityRef.id()))
.and(MEASURABLE_RATING.ENTITY_KIND.eq(entityRef.kind().name()));
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,17 @@ public RatingSchemeItem getRatingSchemeItemById(long id){
}


public List<RatingSchemeItem> findRatingSchemeItemsForEntityAndCategory(EntityReference ref, long measurableCategoryId) {
/**
* Gives a list of permissible rating items for the given entity and category.
* This method takes into account any constraining assessment associated to the category.
* If the rating is constrained the <code>isRestricted</code> flag on the returned RatingSchemeItem will be set.
*
* @param ref the entity being checked
* @param measurableCategoryId the category being checked
* @return list of permissible rating items for the given entity and category
*/
public List<RatingSchemeItem> findRatingSchemeItemsForEntityAndCategory(EntityReference ref,
long measurableCategoryId) {

Condition assessmentDefinitionJoinCondition = ASSESSMENT_DEFINITION.ID.eq(ASSESSMENT_RATING.ASSESSMENT_DEFINITION_ID)
.and(ASSESSMENT_RATING.ENTITY_ID.eq(ref.id())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public Set<EntityLifecycleStatus> entityLifecycleStatuses() {

@Value.Default
public SelectionFilters filters() {
return ImmutableSelectionFilters.builder().build();
return SelectionFilters.NO_FILTERS;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
@JsonDeserialize(as = ImmutableSelectionFilters.class)
public abstract class SelectionFilters {

public static final SelectionFilters NO_FILTERS = ImmutableSelectionFilters.builder().build();

public abstract Set<ApplicationKind> omitApplicationKinds();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.finos.waltz.model;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.finos.waltz.model.command.Command;
import org.immutables.value.Value;

@Value.Immutable
@JsonDeserialize(as= ImmutableUpdateRatingCodeCommand.class)
public abstract class UpdateRatingCodeCommand implements Command {

public abstract String newCode();

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;
import org.finos.waltz.model.command.Command;
import org.immutables.value.Value;

@Value.Immutable
@JsonSerialize(as = ImmutableUpdateRatingCommand.class)
Expand Down
Loading

0 comments on commit 84972f1

Please sign in to comment.