package gw.rating.rtm uses gw.api.domain.BeanLoader uses gw.api.domain.FKLoader uses gw.api.locale.DisplayKey uses gw.api.validation.EntityValidationException uses gw.entity.IArrayPropertyInfo uses gw.pc.rating.entity.CoveringIndexType uses gw.rating.RatingValidationUtil uses gw.rating.flow.util.QueryUtils uses gw.rating.rtm.domain.ErrorCollector uses gw.rating.rtm.domain.RateTableRowError uses gw.rating.rtm.domain.table.RateTableCell uses gw.rating.rtm.domain.table.RateTableModel uses gw.rating.rtm.domain.table.RateTableRow uses gw.rating.rtm.validation.RateTableValidator uses gw.rating.rtm.valueprovider.ReferenceFactorValueProvider uses gw.validation.PCValidationBase uses gw.validation.PCValidationContext class RateBookValidation extends PCValidationBase { var rateBook : RateBook var status : RateBookStatus var validateStateChange : boolean construct(valContext : PCValidationContext, book : RateBook, forStatus : RateBookStatus, checkForStateChange : boolean) { super(valContext) rateBook = book status = forStatus validateStateChange = checkForStateChange } override function validateImpl() { checkLegalStateChange() if (status == TC_STAGE) { validateAll() } else { checkRateTablesForDatabaseQueryIssues() checkRoutinesContainParameterSetsThatAreValidForAllPriorVersions() } } static function checkFactorRow(tableDef : RateTableDefinition) : String { if (tableDef.EntityName == "DefaultRateFactorRow" or tableDef.EntityName == "RateFactorRow") { return DisplayKey.get("Web.Rating.Errors.DatabaseQueryWithDefaultRow", tableDef.TableCode, tableDef.EntityName) } else if (tableDef.CoveringIndexType < CoveringIndexType.PARAMS) { return DisplayKey.get("Web.Rating.Errors.DatabaseQueryWithUnindexedRow", tableDef.TableCode) } else if (tableDef.CoveringIndexType != CoveringIndexType.PARAMS_AND_FACTORS) { return DisplayKey.get("Web.Rating.Errors.DatabaseQueryWithPartialIndex", tableDef.TableCode) } return null } private function checkLegalStateChange() { Context.addToVisited(this, "checkLegalStateChange") if (!validateStateChange) return var allowedToChange = true switch (status) { case TC_STAGE: allowedToChange = rateBook.isDraft() break case TC_APPROVED: allowedToChange = rateBook.isStage() break case TC_ACTIVE : allowedToChange = rateBook.isApproved() break default: } if (!allowedToChange) { Result.addError(rateBook, TC_DEFAULT, DisplayKey.get("Web.Rating.Errors.RateBookBadStatusTransition", rateBook.Status.DisplayName, status)) } } private function validateAll() { validateRateTables() validateCalcRoutines() checkRoutinesContainParameterSetsThatAreValidForAllPriorVersions() } private function preloadCalcRoutineParameterSets(calcRoutines: List) { FKLoader.preLoadFKs(calcRoutines, CalcRoutineParameterSet) } private function preloadCalcRoutineParameterSetAndParameters(calcRoutines: List) { preloadCalcRoutineParameterSets(calcRoutines) RatingValidationUtil.loadArrays(calcRoutines*.ParameterSet.toList(), "Parameters") } private function checkRoutinesContainParameterSetsThatAreValidForAllPriorVersions() { var calcRoutinesVersionMap = QueryUtils.getCalcRoutineFromRateBookWithSameCode(rateBook) rateBook.CalcRoutines.each( \ routine -> { var versionsOfSameRoutine = calcRoutinesVersionMap.get(routine.Code) preloadCalcRoutineParameterSetAndParameters(versionsOfSameRoutine) var parameterSuperSet = getSuperSetOfParameters(versionsOfSameRoutine) if (not listOfParametersAreEqual(parameterSuperSet, routine.ParameterSet.Parameters.toList())) { Result.addWarning(routine, ValidationLevel.TC_DEFAULT, DisplayKey.get("Web.Rating.Warnings.ParameterChangedForSuperSetForAllVersionsForRoutine", routine.Code, parameterSuperSet.toList().ParameterSetForUIMessage)) } }) } private function listOfParametersAreEqual(list1 : List, list2 : List ) : boolean { return list1.Count == list2.Count and list1.allMatch( \ elt1 -> list2.where( \ elt -> elt.Code == elt1.Code and elt.ParamType == elt1.ParamType).Count == 1) } private function getSuperSetOfParameters(versionsOfSameRoutine : List) : List { var parameterSuperSet = new ArrayList() versionsOfSameRoutine.orderBy( \ elt -> elt.Version).each( \ version -> { version.ParameterSet.Parameters.each( \ parameterToAdd -> { var duplicates = parameterSuperSet.where( \ elt -> elt.Code == parameterToAdd.Code and elt.ParamType == parameterToAdd.ParamType) if (duplicates.Empty) { parameterSuperSet.add(parameterToAdd) } }) }) return parameterSuperSet } private function checkRateTablesForDatabaseQueryIssues() { Context.addToVisited(this, "checkRateTablesForDatabaseQueryIssues") for (t in rateBook.RateTables.where(\ rt -> rt.QueryStrategy == TC_DATABASE)) { var msg = checkFactorRow(t.Definition) if (msg != null) { Result.addWarning(t, TC_DEFAULT, msg) } } } private function validateRateTables() { if (rateBook.RateTables.HasElements) { for (table in rateTablesWithoutFactors()) { Result.addError(table, TC_DEFAULT, DisplayKey.get("Web.Rating.Errors.RateTableWithMissingFactors", table.Definition.TableName)) } for (table in rateBook.tablesWithDefinitionChanges()) { // for these tables, we need to validate rows against their definition var model = new RateTableModel(table) table.Factors.each(\ bean -> model.addFactorRow(bean)) try { new RateTableValidator().validate(model, new LocalCollector()) } catch (eve: EntityValidationException) { Result.addError(table, ValidationLevel.TC_DEFAULT, DisplayKey.get("Web.Rating.Errors.RateTableWithAlteredDefinition", table.Definition.TableCode)) } } checkRateTablesForDatabaseQueryIssues() } checkForMissingRateTableReferences() } private function validateCalcRoutines() { if (rateBook.RateTables.IsEmpty and rateBook.RateBookCalcRoutines.IsEmpty) { Result.addError(rateBook, TC_DEFAULT, DisplayKey.get("Web.RatingErrors.FailEmptyRateBookPromotionToStaging")) } if (rateBook.RateBookCalcRoutines.HasElements) { var invalidRoutines : List = {} for (def in CalcRoutinesThatNeedRevalidation) { var ctx = new PCValidationContext(TC_DEFAULT) var validator = new gw.rating.flow.validation.RateRoutineValidation(ctx, def) // do all validations except calcRoutineCannotBeUpdatedIfReferencedByNonDraftBook() validator.validate(EXPORT) if (ctx.Result.hasErrors()) { invalidRoutines.add(def) } } if (invalidRoutines.HasElements) { Context.Result.addError(rateBook, TC_DEFAULT, DisplayKey.get("Web.Rating.Errors.InvalidRateRoutines", invalidRoutines.map(\ r -> r.Code).join(", "))) } } } property get CalcRoutinesThatNeedRevalidation() : Set { return rateBook.CalcRoutinesNotInPromotedRateBook } private function rateTablesWithoutFactors(): RateTable[] { return rateBook.RateTables.where(\table -> table.Empty) } private function checkForMissingRateTableReferences() { Context.addToVisited(this, "checkForMissingRateTableReferences") var references = rateBook.RateTables.map(\ r -> r.Definition.TableCode).toSet() rateBook.RateTables.each(\ t -> { t.Definition.AllColumns.each(\col -> { var valueProvider = gw.rating.rtm.valueprovider.Parser.parse(col.ValueProvider) if (valueProvider.ClassName == ReferenceFactorValueProvider.Type.Name) { var referencedRateTableCode = valueProvider.Arguments.first() if (!references.contains(referencedRateTableCode)) { Result.addError(t.Definition, TC_DEFAULT, DisplayKey.get("Web.Rating.Errors.RateBookMissingTableReference", t.Definition.TableCode, referencedRateTableCode)) } } }) }) } class LocalCollector implements ErrorCollector { var count = 0 override function getErrorCount() : int { return count } override function addRowError(row : RateTableRow, errorType : RateTableErrorType) { count++ } override function addCellError(row : RateTableRow, cell : RateTableCell>, errorType : RateTableErrorType, msg : String = null) { count++ } override function getRowErrors(row : RateTableRow) : List { throw new UnsupportedOperationException("getRowErrors() not implemented") } override function getErrorSummary() : String { return count == 0 ? null : "${count} errors" } override function reset() { throw new UnsupportedOperationException("reset() not implemented") } } }