package gw.rating.rtm.validation uses gw.api.locale.DisplayKey uses gw.api.database.Query uses gw.pl.util.ArgCheck uses gw.rating.rtm.valueprovider.CustomValueProviderData uses gw.validation.PCValidationBase uses gw.validation.PCValidationContext uses gw.validation.PCValidationResult uses gw.validation.ValidationUtil @Export class RateTableDefinitionValidation extends PCValidationBase { final var _rateTableDefinition : RateTableDefinition /** * @return true only if the opCode corresponds to an interpolated match */ function isInterpolationOpCode(opCode : String) : boolean { return {"Interpolate", "InterpolateWithRelax"}.contains(opCode) } /** * @return true only if the opCode corresponds to a match that does not rely on sorting by score */ function isNonSortingOpCode(opCode : String) : boolean { return {"ExactMatch", "RangeMatchMaxIncl", "RangeMatchMaxExcl"}.contains(opCode) } construct(valContext : PCValidationContext, definition : RateTableDefinition) { super(valContext) ArgCheck.nonNull(definition, "definition") _rateTableDefinition = definition } override protected function validateImpl() { Context.addToVisited(this, "validateImpl") atLeastOneMatchOp() atLeastOneFactor() atLeastOneArgumentSourceSet() decimalPlacesFieldForDecimalFactorsAreZeroOrGreater() decimalPlacesForDecimalFactorsDoNotExceedBackingColumnScales() decimalPlacesFieldForDecimalParamsAreZeroOrGreater() decimalPlacesForDecimalParamsDoNotExceedBackingColumnScales() allParamsInSameMatchOpHaveSameColumnScale() validCustomEntity() duplicateSortOrder() uniqueMatchOpNames() uniqueParameterNames() uniqueTableCode() onlyOneInterpolation() onlyExactMatchOrRangeBeforeInterpolation() validateMatchOpAreInSortedOrder() parameterDoesNotDependOnMultiValueParameter() addNewArgumentSourceSetToUseParameter() parameterSetForArgSourceIsValid() } static function validateRateTableDefinition(definition: RateTableDefinition) { PCValidationContext.doPageLevelValidation(\ context -> { columnProviderArgs(definition, context.Result) var validation = new RateTableDefinitionValidation(context, definition) validation.validate() }) } static function validatePostEnter(definition: RateTableDefinition) { PCValidationContext.doPageLevelValidation(\context -> { for (column in definition.AllColumns) { new CustomValueProviderData(column).processRateTableColumnOnEnter(context.Result) } }) } private static function columnProviderArgs(definition: RateTableDefinition, result: PCValidationResult) { for (column in definition.AllColumns) { new CustomValueProviderData(column).processRateTableColumnOnExit(result) } } function atLeastOneMatchOp() { Context.addToVisited(this, "atLeastOneMatchOp") if (_rateTableDefinition.MatchOps.Count < 1) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.MissingMatchOp")) } } function atLeastOneFactor() { Context.addToVisited(this, "atLeastOneFactor") if (_rateTableDefinition.Factors.Count < 1) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.MissingFactors")) } } function atLeastOneArgumentSourceSet() { Context.addToVisited(this, "atLeastOneArgumentSourceSet") if (_rateTableDefinition.ArgumentSourceSets.Count < 1) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.MissingArgumentSourceSet")) } } function decimalPlacesForDecimalFactorsDoNotExceedBackingColumnScales() { Context.addToVisited(this, "factorScalesDoNotExceedBackingColumn") if (_rateTableDefinition.Factors.Count > 0) { _rateTableDefinition.Factors .where(\factor -> factor.ColumnType == TC_DECIMAL) .each(\factor -> { if (factor.ColumnScale > factor.Scale) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.DecimalPlacesTooBig", factor.ColumnName, factor.Scale)) } }) } } function decimalPlacesForDecimalParamsDoNotExceedBackingColumnScales() { Context.addToVisited(this, "paramScalesDoNotExceedBackingColumn") if (_rateTableDefinition.SortedParameters.Count > 0) { _rateTableDefinition.MatchOps*.Params .where(\param -> param.ColumnType == TC_DECIMAL) .each(\param -> { if (param.ColumnScale > param.Scale) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.Parameter.DecimalPlacesTooBig", param.ColumnName, param.Scale)) } }) } } function decimalPlacesFieldForDecimalFactorsAreZeroOrGreater() { Context.addToVisited(this, "factorScalesShouldNotBeNegative") if (_rateTableDefinition.Factors.Count > 0) { _rateTableDefinition.Factors .where(\factor -> factor.ColumnType == TC_DECIMAL) .each(\factor -> { if (factor.ColumnScale < 0) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.DecimalPlacesMustBeGreaterThanZero", factor.ColumnName)) } }) } } function decimalPlacesFieldForDecimalParamsAreZeroOrGreater() { Context.addToVisited(this, "paramScalesShouldNotBeNegative") if (_rateTableDefinition.SortedParameters.Count > 0) { _rateTableDefinition.MatchOps*.Params .where(\param -> param.ColumnType == TC_DECIMAL) .each(\param-> { if (param.ColumnScale < 0) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.Parameter.DecimalPlacesMustBeGreaterThanZero", param.ColumnName)) } }) } } function allParamsInSameMatchOpHaveSameColumnScale() { Context.addToVisited(this, "paramScalesInSameMatchOpShouldBeEqual") if (_rateTableDefinition.MatchOps.Count > 0) { _rateTableDefinition.MatchOps.where(\ op -> op.Params.Count > 1).each(\ op -> { var paramScales = op.Params.where(\ param -> param.ColumnType == TC_DECIMAL)*.ColumnScale.toSet() if (paramScales.Count > 1) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.Parameter.DecimalPlacesMustBeTheSameUnderOneMatchOp", op.DisplayName)) } }) } } function validCustomEntity() { Context.addToVisited(this, "validCustomEntity") if (not _rateTableDefinition.hasValidEntity()) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.InvalidEntity", _rateTableDefinition.EntityName)) } } function duplicateSortOrder() { Context.addToVisited(this, "duplicateSortOrder") var rateTableColumns = _rateTableDefinition.MatchOps.flatMap( \ elt -> elt.Params) var parameterColumnPriorities = rateTableColumns.map(\ c -> c.SortOrder) if (parameterColumnPriorities.length > parameterColumnPriorities.toSet().size()) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.DuplicateSortOrder")) } var factorPriorities = _rateTableDefinition.Factors.map(\ c -> c.SortOrder) if (factorPriorities.length > factorPriorities.toSet().size()) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.DuplicateFactorSortOrder")) } } function uniqueMatchOpNames() { Context.addToVisited(this, "uniqueMatchOpNames") if (_rateTableDefinition.MatchOps*.Name.toSet().Count != _rateTableDefinition.MatchOps.Count) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.DuplicateMatchOpName")) } } function uniqueParameterNames() { Context.addToVisited(this, "uniqueParameterNames") if (_rateTableDefinition.SortedParameters*.ColumnName.toSet().Count != _rateTableDefinition.SortedParameters*.ColumnName.Count) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.DuplicateParameterName")) } } function uniqueTableCode() { Context.addToVisited(this, "uniqueTableCode") var q = Query.make(RateTableDefinition) q.compare(RateTableDefinition#TableCode, Equals, _rateTableDefinition.TableCode) q.compare(RateTableDefinition#PolicyLine, Equals, _rateTableDefinition.PolicyLine) for (var rtd in q.select()) { if (rtd.ID != _rateTableDefinition.ID) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.DuplicateTableCode", _rateTableDefinition.TableCode)) return } } } function onlyOneInterpolation() { Context.addToVisited(this, "onlyOneInterpolation") if(_rateTableDefinition.MatchOps.countWhere(\ mo-> isInterpolationOpCode(mo.MatchOpDefinition.OpCode)) > 1) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.MoreThanOneInterpolation")) } } // Enforce the property that only matchops which do not rely on sorting by score // are allowed to be higher priority than the exactMatchOp function onlyExactMatchOrRangeBeforeInterpolation() { Context.addToVisited(this, "onlyExactMatchOrRangeBeforeInterpolation") var sawOtherOp = false for (op in _rateTableDefinition.SortedMatchOps) { var opCode = op.MatchOpDefinition.OpCode if (isInterpolationOpCode(opCode)) { if (sawOtherOp) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.NoSortedMatchOpBeforeInterpolation")) } break } sawOtherOp = sawOtherOp or not isNonSortingOpCode(opCode) } } function validateMatchOpAreInSortedOrder() { Context.addToVisited(this, "validateMatchOpAreInSortedOrder" ) var prevRateTableColSortOrder : java.lang.Integer = 0 var prevRateTableColName = "" var rateTableColumns = _rateTableDefinition.SortedMatchOps.flatMap( \ elt -> elt.sortedParams()) for (rateTableCol in rateTableColumns){ if (prevRateTableColSortOrder.compareTo(rateTableCol.SortOrder) > 0) { var msg = DisplayKey.get("Validation.Rating.RateTableDefinition.MatchOpsAreInPriorityOrder", rateTableCol.MatchOp.Name, prevRateTableColName) Result.addError(_rateTableDefinition, TC_DEFAULT, msg) } else { prevRateTableColSortOrder = rateTableCol.SortOrder prevRateTableColName = rateTableCol.MatchOp.Name } } } static function validateRateTableDefinitionsBeforeExport(definitions : List, valLevel : ValidationLevel) { var context = ValidationUtil.createContext(valLevel) definitions.each(\ c -> { var defContext = ValidationUtil.createContext(valLevel) var validation = new RateTableDefinitionValidation(defContext, c) validation.validate() defContext.Result.Errors.each(\ o -> context.Result.addError(c, valLevel, c.TableCode + ": " + (o as gw.api.validation.ValidationIssue).Reason)) defContext.Result.Warnings.each(\ o -> context.Result.addWarning(c, valLevel, c.TableCode + ": " + (o as gw.api.validation.ValidationIssue).Reason)) }) context.raiseExceptionIfProblemsFound() } function parameterDoesNotDependOnMultiValueParameter() { Context.addToVisited(this, "parameterDoesNotDependOnMultiValueParameter") if (_rateTableDefinition.SortedParameters.Count > 1 and _rateTableDefinition.AllColumns.hasMatch( \ column -> column.MultiSelect)) { var rateTableColumns = _rateTableDefinition.SortedMatchOps.flatMap( \ elt -> elt.sortedParams()) for (rateTableCol in rateTableColumns){ if(rateTableCol.DependsOn.MultiSelect){ Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.DependsOnMultiValueParameterError")) } } } } function addNewArgumentSourceSetToUseParameter(){ Context.addToVisited(this, "addNewArgumentSourceSetToUseParameter") if (_rateTableDefinition.ArgumentSourceSets.HasElements) { var existingParametersCovered = _rateTableDefinition.ArgumentSourceSets*.RateTableArgumentSources*.Parameter.toSet() if (not existingParametersCovered.containsAll(_rateTableDefinition.MatchOps.toSet()) and _rateTableDefinition.IsInPromotedRateBookViaRateRoutine){ Result.addWarning(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.AddArgumentSourceSetForNewParameters")) } } } function parameterSetForArgSourceIsValid() { Context.addToVisited(this, "parameterSetForArgSourceIsValid") var argumentSourceSets = _rateTableDefinition.ArgumentSourceSets if (argumentSourceSets.HasElements) { var params = _rateTableDefinition.getParameterSet().Parameters*.Code.toSet() var argumentSources = argumentSourceSets*.RateTableArgumentSources var argSrcRoots = argumentSources*.Root.toSet().where( \ elt -> elt != null) if (not params.containsAll(argSrcRoots)) { Result.addError(_rateTableDefinition, TC_DEFAULT, DisplayKey.get("Validation.Rating.RateTableDefinition.ParameterSetNoLongerInScope")) } } } }