def validateSum(value, fields_to_sum, record):
        """ Check that the value of one field is the sum of others

        :param value: The field which holds the sum we will validate against
        :param fields_to_sum: A comma separated list of fields which we should sum. These should be valid Decimals
        :param record: Record containing the data for the current record
        :return: True if the sum of fields is equal to the designated sum field
        """

        decimalValues = []

        # Validate that our sum is a decimal
        if Validator.checkType(str(value), 'DECIMAL'):
            decimalSum = Validator.getType(value, 'DECIMAL')
        else:
            return False

        # Validate each field we are summing is a decimal and store their values in an array
        for field in Validator.cleanSplit(fields_to_sum, True):
            entry = record[FieldCleaner.cleanName(field)]
            if entry is None or entry == "":
                decimalValues.append(0)
            elif Validator.checkType(entry, 'DECIMAL'):
                decimalValues.append(Validator.getType(entry, 'DECIMAL'))
            else:
                return False

        return decimalSum == sum(decimalValues)
    def conditionalRequired(cls, data,rule,datatype,interfaces,record, isList = False):
        """ If conditional rule passes, data must not be empty

        Args:
            data: Data to be checked
            rule: Rule object to test against
            datatype: Type to convert data into
            interfaces: InterfaceHolder object to the databases
            record: Some rule types require the entire record as a dict
        """
        # Get rule object for conditional rule
        conditionalRule = interfaces.validationDb.getRuleByLabel(rule.rule_text_1)
        if conditionalRule.file_column is not None:
            # This is a single field rule
            conditionalTypeId = conditionalRule.file_column.field_types_id
            conditionalDataType = interfaces.validationDb.getFieldTypeById(conditionalTypeId)
            conditionalData = record[conditionalRule.file_column.name]
        else:
            conditionalDataType = None
            conditionalData = record
        # If conditional rule passes, check that data is not empty
        if Validator.evaluateRule(conditionalData,conditionalRule,conditionalDataType,interfaces,record):
            if isList:
                # rule_text_2 is a list of fields
                fieldList = rule.rule_text_2.split(",")
                for field in fieldList:
                    if not cls.isFieldPopulated(record[FieldCleaner.cleanName(field)]):
                        # If any are empty, rule fails
                        return False
            else:
                # data is value from a single field
                return cls.isFieldPopulated(data)
        else:
            # If conditional rule fails, this field is not required, so the condtional requirement passes
            return True
    def requireOne(record, fields, interfaces):
        """ Require at least one of the specified fields to be present

        Args:
            record: Dict for current record
            fields: List of fields to check
            interfaces: interface holder for DBs

        Returns:
            True if at least one of the fields is present
        """
        for field in fields:
            fieldName = FieldCleaner.cleanName(field)
            if fieldName in record and record[fieldName] is not None and str(record[fieldName]).strip() != "":
                # If data is present in this field, rule is satisfied
                return True

        # If all were empty, return false
        return False
    def rule_check_prefix(cls, data, value, rule, datatype, interfaces, record):
        """ Check that 1-digit prefix is consistent with reimbursable flag """
        dataString = FieldCleaner.cleanString(data)

        # Load target field and dict to compare with
        targetField = FieldCleaner.cleanName(rule.rule_text_1)
        prefixMap = json.loads(str(rule.rule_text_2))

        # Check that character and value are consistent with dict in rule_text_2
        if dataString[0] not in prefixMap:
            # Unknown prefix, this is a failure
            return False
        source = prefixMap[dataString[0]]
        target = record[targetField]
        source = source.lower() if source is not None else source
        target = target.lower() if target is not None else target

        if source == target:
            # Matches the value in target field, rule passes
            return True
        else:
            return False
 def rule_sum_fields(cls, data, value, rule, datatype, interfaces, record):
     """Checks that set of fields sums to value in other field"""
     valueToMatch = record[FieldCleaner.cleanName(rule.rule_text_1)]
     if valueToMatch is None or valueToMatch == "":
         valueToMatch = 0
     return cls.validateSum(valueToMatch, rule.rule_text_2, record)