Skip to content

Commit

Permalink
Pull request finos#403: CTCTOWALTZ-3337:
Browse files Browse the repository at this point in the history
Merge in WALTZ/waltz from WALTZ/waltz-drp:CTCTOWALTZ-3337-bulk-assessment-7156 to db-feature/waltz-7156-bulk-assessment-rating

* commit '2da4c3bf4f5f3f537404745bfe26f4de2b21b1ab':
  CTCTOWALTZ-3337:  [x] Added bulk edit for Measurable  finos#7156
  CTCTOWALTZ-3337:  [x] Fixed the PR review comments.  finos#7156
  CTCTOWALTZ-3337:  [x] Fixed the PR review comments.  finos#7156
  CTCTOWALTZ-3337:  [x] Fixed the PR review comments.  [x] Added few more tests  finos#7156
  CTCTOWALTZ-3337:  [x] Fixed the PR review comments.  [x] Added few more tests  finos#7156
  CTCTOWALTZ-3337:  [x] Check for cardinality added  [x] Apply Assessment Rating implemented  [x]Updated UI to show overflow errors.  finos#7156
  CTCTOWALTZ-3337:  [x] Created Parser to parse the assessment rating input.  [x] Preview Add implementation of all entity kinds  [x] UI changes to support bulk edit for all entity kinds with new editor.  [x] Removed existing bulk editor for Application entity kind.  finos#7156
  • Loading branch information
devendra-ramesh-patil-db committed Oct 17, 2024
2 parents 718a19a + 2da4c3b commit 7e2f54e
Show file tree
Hide file tree
Showing 23 changed files with 1,272 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
import org.finos.waltz.schema.tables.Application;
import org.jooq.Condition;

import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;

import static org.finos.waltz.common.Checks.checkTrue;
import static org.finos.waltz.common.SetUtilities.asSet;
Expand Down Expand Up @@ -71,5 +75,4 @@ public static Condition mkApplicationConditions(Application appTable, IdSelectio
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
package org.finos.waltz.integration_test.inmem.service;

import org.finos.waltz.common.ListUtilities;
import org.finos.waltz.integration_test.inmem.BaseInMemoryIntegrationTest;
import org.finos.waltz.model.EntityKind;
import org.finos.waltz.model.assessment_definition.AssessmentDefinition;
import org.finos.waltz.model.assessment_definition.AssessmentVisibility;
import org.finos.waltz.model.assessment_rating.bulk_upload.AssessmentRatingValidationResult;
import org.finos.waltz.model.assessment_rating.bulk_upload.ValidationError;
import org.finos.waltz.service.application.ApplicationService;
import org.finos.waltz.service.assessment_definition.AssessmentDefinitionService;
import org.finos.waltz.service.assessment_rating.BulkAssessmentRatingService;
import org.finos.waltz.test_common.helpers.ActorHelper;
import org.finos.waltz.test_common.helpers.AppHelper;
import org.finos.waltz.test_common.helpers.AssessmentHelper;
import org.finos.waltz.test_common.helpers.RatingSchemeHelper;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

import static org.finos.waltz.common.CollectionUtilities.all;
import static org.finos.waltz.common.CollectionUtilities.isEmpty;
import static org.finos.waltz.common.ListUtilities.asList;
import static org.finos.waltz.model.EntityReference.mkRef;
import static org.finos.waltz.test_common.helpers.NameHelper.mkName;
import static org.junit.jupiter.api.Assertions.*;

public class BulkAssessmentRatingServiceTest extends BaseInMemoryIntegrationTest {
private static final Logger LOG = LoggerFactory.getLogger(BulkAssessmentRatingServiceTest.class);

@Autowired
private AssessmentHelper assessmentHelper;
@Autowired
private RatingSchemeHelper ratingSchemeHelper;

@Autowired
private ApplicationService applicationService;

@Autowired
private BulkAssessmentRatingService bulkAssessmentRatingService;

@Autowired
private AppHelper appHelper;

@Autowired
private ActorHelper actorHelper;

@Autowired
private AssessmentDefinitionService assessmentDefinitionService;

private static final String stem = "BAR";

@Test
public void previewAdds() {
/**
* Entity Kind: APPLICATION
*/
String name = mkName(stem, "previewApp");
String kindExternalId = mkName(stem, "previewAppCode");
Long schemeId = ratingSchemeHelper.createEmptyRatingScheme(name + "SchemeApp");
ratingSchemeHelper.saveRatingItem(schemeId, "Yes", 0, "green", "Y");
appHelper.createNewApp(
mkName(stem, "previewUpdatesApp"),
ouIds.root,
kindExternalId);
AssessmentDefinition def1 = assessmentDefinitionService.getById(getAssessmentDefinition(EntityKind.APPLICATION, schemeId, name));

AssessmentRatingValidationResult result1 = bulkAssessmentRatingService.bulkPreview(
mkRef(def1.entityKind(), def1.id().get()),
mkGoodTsv(kindExternalId));

assertNotNull(result1, "Expected a result");
assertNoErrors(result1);
assertExternalIdsMatch(result1, asList(kindExternalId));

/**
*EntityKind: ACTOR
*/
String actorName = mkName(stem,"previewActor");
Long actorSchemeId = ratingSchemeHelper.createEmptyRatingScheme(name+"SchemeActor");
ratingSchemeHelper.saveRatingItem(actorSchemeId,"Yes",0,"green","Y");
actorHelper.createActor(actorName);
AssessmentDefinition def2 = assessmentDefinitionService.getById(getAssessmentDefinition(EntityKind.ACTOR,actorSchemeId,actorName));

AssessmentRatingValidationResult result2 = bulkAssessmentRatingService.bulkPreview(
mkRef(def2.entityKind(),def2.id().get()),
mkGoodTsv(actorName));

assertNotNull(result2,"Expected a result");
assertNoErrors(result2);
assertExternalIdsMatch(result2,asList(actorName));

}

@Test
public void previewAddsForCardinalityChecks() {
String appName = mkName(stem, "previewApp3");
String appExternalId = mkName(stem, "previewAppCode3");
Long schemeId = ratingSchemeHelper.createEmptyRatingScheme(mkName(stem, "SchemeApp1"));
ratingSchemeHelper.saveRatingItem(schemeId, "Yes", 0, "green", "Y");
ratingSchemeHelper.saveRatingItem(schemeId, "No", 0, "red", "N");
appHelper.createNewApp(
appName,
ouIds.root,
appExternalId);
AssessmentDefinition def = assessmentDefinitionService.getById(getAssessmentDefinition(EntityKind.APPLICATION, schemeId, "Assessment1"));

/**
* Zero-One
*/
String[] externalIds = {appExternalId, appExternalId};
String[] ratingCodes = {"Y", "N"};
AssessmentRatingValidationResult result = bulkAssessmentRatingService.bulkPreview(
mkRef(def.entityKind(), def.id().get()),
mkTsvWithForCardinalityCheck(externalIds, ratingCodes));

result
.validatedItems()
.forEach(d -> {
if (d.parsedItem().ratingCode().equals("N")) {
assertTrue(d.errors().contains(ValidationError.DUPLICATE), "Should be complaining about the duplicate entity with rating N");
}
});

assertEquals(2, result.validatedItems().size(), "Expected 2 items");
}

@Test
public void previewUpdateErrors() {
String appName = mkName(stem, "previewApp1");
String appExternalId = mkName(stem, "previewAppCode1");
Long schemeId = ratingSchemeHelper.createEmptyRatingScheme(mkName(stem, "SchemeApp"));
ratingSchemeHelper.saveRatingItem(schemeId, "Yes", 0, "green", "Y");
ratingSchemeHelper.saveRatingItem(schemeId, "No", 0, "red", "N");
appHelper.createNewApp(
appName,
ouIds.root,
appExternalId);
AssessmentDefinition def = assessmentDefinitionService.getById(getAssessmentDefinition(EntityKind.APPLICATION, schemeId, "Assessment"));

AssessmentRatingValidationResult result = bulkAssessmentRatingService.bulkPreview(
mkRef(def.entityKind(), def.id().get()),
mkBadTsv(appExternalId));

result
.validatedItems()
.forEach(d -> {
if (d.parsedItem().ratingCode().equals("badExternalId")) {
assertTrue(d.errors().contains(ValidationError.ENTITY_KIND_NOT_FOUND), "Should be complaining about the entity not found");
}
if (d.parsedItem().ratingCode().equals("badRatingCode")) {
assertTrue(d.errors().contains(ValidationError.RATING_NOT_FOUND), "Should be complaining about the rating code not found");
}
});

assertEquals(3, result.validatedItems().size(), "Expected 3 items");
}

private long getAssessmentDefinition(EntityKind kind, Long schemeId, String name) {
return assessmentHelper.createDefinition(schemeId, name + "Definition", "", AssessmentVisibility.PRIMARY, "Test", kind, null);
}

private void assertNoErrors(AssessmentRatingValidationResult result) {
assertTrue(
all(result.validatedItems(), d -> isEmpty(d.errors())),
"Should have no errors");
}

private void assertExternalIdsMatch(AssessmentRatingValidationResult result,
List<String> expectedExternalIds) {
assertEquals(
expectedExternalIds,
ListUtilities.map(result.validatedItems(), d -> d.parsedItem().externalId()),
"Expected external ids do not match");
}

private String mkGoodTsv(String externalId) {
return "externalId\tratingCode\tisReadOnly\tcomment\n"
+ externalId + "\tY\ttrue\tcomment\n";
}

private String mkTsvWithForCardinalityCheck(String[] externalIds, String[] ratingCodes) {
return "externalId\tratingCode\tisReadOnly\tcomment\n"
+ externalIds[0] + "\t" + ratingCodes[0] + "\ttrue\tcomment\n"
+ externalIds[1] + "\t" + ratingCodes[1] + "\ttrue\tcomment\n";
}

private String mkBadTsv(String externalId) {
return "externalId\tratingCode\tisReadOnly\tcomment\n"
+"badExternalId\tY\ttrue\tcomment\n"
+ externalId + "\tN\ttrue\tcomment\n"
+ externalId + "\tbadRatingCode\ttrue\tcomment\n";
}

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

import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.finos.waltz.model.Nullable;
import org.immutables.value.Value;

@Value.Immutable
@JsonDeserialize(as = ImmutableAssessmentRatingParsedItem.class)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
public interface AssessmentRatingParsedItem {
@JsonAlias("external_id")
String externalId();

String ratingCode();

@Value.Default
default boolean isReadOnly() { return false; }

@Nullable
String comment();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.finos.waltz.model.assessment_rating.bulk_upload;

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

import java.util.List;

@Value.Immutable
@JsonSerialize(as = ImmutableAssessmentRatingParsedResult.class)
public interface AssessmentRatingParsedResult {

@Value.Immutable
interface AssessmentRatingParseError {
String message();

@Nullable
Integer line();

@Nullable
Integer column();
}

List<AssessmentRatingParsedItem> parsedItems();

@Nullable String input();

@Nullable
AssessmentRatingParseError error();


static AssessmentRatingParsedResult mkResult(List<AssessmentRatingParsedItem> items,
String input) {
return ImmutableAssessmentRatingParsedResult
.builder()
.parsedItems(items)
.input(input)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.finos.waltz.model.assessment_rating.bulk_upload;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.finos.waltz.model.EntityReference;
import org.finos.waltz.model.Nullable;
import org.finos.waltz.model.rating.RatingSchemeItem;
import org.immutables.value.Value;

import java.util.Set;

@Value.Immutable
@JsonDeserialize(as = ImmutableAssessmentRatingValidatedItem.class)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
public interface AssessmentRatingValidatedItem {

AssessmentRatingParsedItem parsedItem();

ChangeOperation changeOperation();

Set<ChangedFieldType> changedFields();

Set<ValidationError> errors();

@Nullable
RatingSchemeItem ratingSchemeItem();

@Nullable
EntityReference entityKindReference();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.finos.waltz.model.assessment_rating.bulk_upload;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.finos.waltz.model.EntityReference;
import org.finos.waltz.model.Nullable;
import org.immutables.value.Value;
import org.jooq.lambda.tuple.Tuple2;

import java.util.List;
import java.util.Set;

@Value.Immutable
@JsonSerialize(as= ImmutableAssessmentRatingValidationResult.class)
public interface AssessmentRatingValidationResult {
List<AssessmentRatingValidatedItem> validatedItems();

@Nullable
AssessmentRatingParsedResult.AssessmentRatingParseError error();

@Value.Derived
default int removalCount() {
return removals().size();
}

Set<Tuple2<EntityReference, Long>> removals();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.finos.waltz.model.assessment_rating.bulk_upload;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;

@Value.Immutable
@JsonSerialize(as = ImmutableBulkAssessmentRatingApplyResult.class)
public interface BulkAssessmentRatingApplyResult {
int recordsAdded();
int recordsUpdated();
int recordsRemoved();
int skippedRows();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.finos.waltz.model.assessment_rating.bulk_upload;

public enum ChangeOperation {
ADD,
REMOVE,
RESTORE,
UPDATE,
NONE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.finos.waltz.model.assessment_rating.bulk_upload;

public enum ChangedFieldType {
ENTITY,
RATING,
READ_ONLY,
COMMENT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.finos.waltz.model.assessment_rating.bulk_upload;

public enum ValidationError {
ENTITY_KIND_NOT_FOUND,
RATING_NOT_FOUND,
DUPLICATE,

RATING_NOT_USER_SELECTABLE
}
Loading

0 comments on commit 7e2f54e

Please sign in to comment.