> For the complete documentation index, see [llms.txt](https://docs.eximee.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/logika-biznesowa/scriptcode/walidatory-skryptowe-validationscript/sciaga-walidatorow-skryptowych.md).

# Cheat sheet - sample script validators

The code snippets below show example script validators written in **ScriptCode**.

The provided templates are for illustrative purposes and require adaptation. The input parameter specification, dedicated business logic, and the appropriate content of validation messages must be taken into account. Each implementation should be covered by unit tests, including edge-case scenarios.

## PESEL number validator

Used to verify the correctness of the provided PESEL number.

{% code lineNumbers="true" expandable="true" %}

```js
/*
* Validator checking the correctness of the PESEL number (format, checksum, and date of birth correctness).
*/
function callService(context) {
    const peselInput = context.getFirstParameter('pesel');

    if (isInputEmpty(peselInput)) {
        return [];
    }

    // A) Format verification (exactly 11 digits)
    if (!peselInput.match(/^[0-9]{11}$/)) {
        return [{
            'key': 'pl.error.invalidPeselFormat',
            'parameters': [peselInput]
        }];
    }

    // B) Excluding a PESEL made up of all zeros
    if (peselInput == "00000000000") {
        return [{
            'key': 'pl.error.peselAllZeros',
            'parameters': [peselInput]
        }];
    }

    // C) Checking the PESEL checksum
    if (!isValidChecksum(peselInput)) {
        return [{
            'key': 'pl.error.invalidPeselChecksum',
            'parameters': [peselInput]
        }];
    }

    // D) Verifying the date of birth correctness
    const year = getBirthYear(peselInput);
    const month = getBirthMonth(peselInput) + 1;
    const day = getBirthDay(peselInput);

    if (isMonthAndDayCorrect(year, month, day) == false) {
        return [{
            'key': 'pl.error.invalidPeselBirthDate',
            'parameters': [peselInput]
        }];
    }

    return [];

    /*
    * Checks whether the provided value is empty.
    */
    function isInputEmpty(value) {
        return value == null || String(value).trim() === '';
    }

    /*
    * Calculates and validates the PESEL checksum digit.
    */
    function isValidChecksum(pesel) {
        const weight = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3];
        const peselDigits = pesel.split('').map(Number);

        let sum = 0;
        for (let i = 0; i < weight.length; i++) {
            sum += peselDigits[i] * weight[i];
        }

        const controlDigit = peselDigits[10];
        const lastNumber = sum % 10;
        const calculatedControlDigit = (10 - lastNumber) % 10;

        return calculatedControlDigit === controlDigit;
    }

    /*
    * Calculates the birth year from the PESEL number.
    */
    function getBirthYear(pesel) {
        let year = 10 * parseInt(pesel[0]);
        year += parseInt(pesel[1]);
        let month = 10 * parseInt(pesel[2]);
        month += parseInt(pesel[3]);
        if (month > 80 && month < 93) {
            year += 1800;
        } else if (month > 0 && month < 13) {
            year += 1900;
        } else if (month > 20 && month < 33) {
            year += 2000;
        } else if (month > 40 && month < 53) {
            year += 2100;
        } else if (month > 60 && month < 73) {
            year += 2200;
        }
        return year;
    }

    /*
    * Calculates the month of birth from the PESEL number.
    */
    function getBirthMonth(pesel) {
        let month = 10 * parseInt(pesel[2]);
        month += parseInt(pesel[3]);
        if (month > 80 && month < 93) {
            month -= 80;
        } else if (month > 20 && month < 33) {
            month -= 20;
        } else if (month > 40 && month < 53) {
            month -= 40;
        } else if (month > 60 && month < 73) {
            month -= 60;
        }
        return month - 1;
    }

    /*
    * Calculates the day of birth from the PESEL number.
    */
    function getBirthDay(pesel) {
        let day = 10 * parseInt(pesel[4]);
        day += parseInt(pesel[5]);
        return day;
    }

    /*
    * Verifies whether the day and month are correct for the given year (including leap years).
    */
    function isMonthAndDayCorrect(yearNumber, monthNumber, dayNumber) {

        const longMonths = [1, 3, 5, 7, 8, 10, 12];
        const shortMonths = [4, 6, 9, 11];

        if (longMonths.indexOf(monthNumber) != -1) {
            if (dayNumber > 31) {
                return false;
            } return true;
        } else if (shortMonths.indexOf(monthNumber) != -1) {
            if (dayNumber > 30) {
                return false;
            } return true;
        } else if (monthNumber == 2) {
            if (((yearNumber % 4 == 0) && (yearNumber % 100 != 0)) || (yearNumber % 400 == 0)) {
                if (dayNumber > 29) {
                    return false;
                } return true;
            } else {
                if (dayNumber > 28) {
                    return false;
                } return true;
            }
        } else {
            return false;
        }
    }

}
```

{% endcode %}

## Age validator

Used to verify age based on the date of birth. Checks whether the person has reached the age of 15.

{% code lineNumbers="true" expandable="true" %}

```js
/*
* The validator checks the child's date of birth and returns an error if they have reached the age of 15.
*/
function callService(context) {

    const ERR_AGE_VALIDATION = [{ 
        key: 'pl.error.ageValidationError', 
        parameters: ['Error during age validation.'] 
    }];
    
    const ERR_ADULT = [{ 
        key: 'pl.error.aboveMaximumAge', 
        parameters: ['The benefit is granted for a child up to the age of 15.'] 
    }];

    const birthdayTimestamp = context.getFirstParameter('dataUrodzenia');

    if (!birthdayTimestamp || birthdayTimestamp === "") {
        return [];
    }

    const birthTimestamp = parseInt(birthdayTimestamp, 10);
    if (isNaN(birthTimestamp)) {
        return ERR_AGE_VALIDATION;
    }

    const today = new Date();

    // Setting the 15th birthday date
    const birthDate = new Date(birthTimestamp);
    const legalAgeLimitDate = new Date(birthDate.getFullYear() + 15, birthDate.getMonth(), birthDate.getDate());

    // Compare with today's date
    if (today >= legalAgeLimitDate) {
        return ERR_ADULT;
    }

    return [];
}
```

{% endcode %}

## Birth year validator

Used to verify whether the entered date of birth is not earlier than 1900.

```js
/*
* Checks whether the birth year is not earlier than 1900.
*/
function callService(context) {
    const birthDateInput = context.getFirstParameter('dataUrodzenia');
    
    if (birthDateInput !== "" && birthDateInput !== null) {
        const birthTimestamp = parseInt(birthDateInput, 10);
        const birthDate = new Date(birthTimestamp);
        const birthYear = birthDate.getFullYear();

        if (birthYear < 1900) {
            return [{
                'key': 'pl.error.birthYearBefore1900',
                'parameters': [birthDate, 'Date of birth cannot be earlier than 1900.']
            }];           
        }
    }

    return [];
}
```

## ID card number validator

Used to verify the Polish ID card number.

{% code lineNumbers="true" expandable="true" %}

```js
/* 
*The script is used for formal and mathematical verification of the correctness of the Polish ID card number.
*/
function callService(context) {
    const REGEX_ID_MASK = /^[A-Z]{3}\d{6}$/;
    const WEIGHT = [7, 3, 1, 9, 7, 3, 1, 7, 3];
    const EDGE_CASE = "AAA000000";

    const idNumber = context.getFirstParameter('idNumber');
    const invalidIdNumberError = [{
        'key': 'pl.error.idNumber',
        'parameters': [idNumber]
    }];

    if (typeof idNumber !== 'string' || idNumber.trim() === "") {
        return invalidIdNumberError;
    }

    if (idNumber === EDGE_CASE) {
        return invalidIdNumberError;
    }

    if (isLengthCorrect(idNumber)) {
        return [];
    } else {
        return invalidIdNumberError;
    }

    /*
    * Converts letters in the ID number to their corresponding numeric values.
    */
    function convertValueToNumber(numberID) {
        const result = numberID.toUpperCase();
        const START_VALUE = 10;
        let letter = 'A';
        const dict = {};
        for (let i = START_VALUE; i < 36; i++) {
            dict[letter] = i;
            letter = String.fromCharCode(letter.charCodeAt(0) + 1);
        }

        const convertedNumber = [];
        for (let i = 0; i < result.length; i++) {
            if (dict[result[i]] !== undefined) {
                convertedNumber.push(dict[result[i]]);
                continue;
            }
            convertedNumber.push(+result[i]);
        }
        return convertedNumber;
    }

    /*
    * Calculates and verifies the checksum of the ID card number.
    */
    function isChecksumValid(numberSum) {
        const resultConvert = convertValueToNumber(numberSum);
        let sum = 0;
        for (let i = 0; i < WEIGHT.length; ++i) {
            if (i === 3) {
                continue;
            }
            sum += resultConvert[i] * WEIGHT[i];
        }
        sum %= 10;
        return sum === resultConvert[3];
    }

    /*
    * Verifies whether the ID card number meets the format requirements (3 letters + 6 digits) and whether its checksum is correct.
    */
    function isMaskCorrect(number) {
        return REGEX_ID_MASK.test(number) && isChecksumValid(number);
    }

    /**
    * Checks whether the length of the entered number matches the expected length (9 characters).
    */
    function isLengthCorrect(numberId) {
        return numberId.length === WEIGHT.length && isMaskCorrect(numberId);
    }
}
```

{% endcode %}

## Email address validator

Used to verify the format and syntax of the entered email address.

```js
/*
* Validates the syntactic correctness of the email address based on a regular expression.
*/
function callService(context) {
    const email = context.getFirstParameter('email');
    const regex = new RegExp("^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-\\+]+)*@([A-Za-z0-9]+(-[A-Za-z0-9]+)*(\\.[A-Za-z0-9-]+)*\\.[A-Za-z]{2,})$");
    
    if (!regex.test(email) || email.match(regex)[0] !== email) {
        return [{
            'key': 'pl.error.IncorrectEmail',
            'parameters': [email, 'The provided value is invalid']
        }];
    } else {
        return [];
    }
}
```

## File size validator

Used to check whether the total size of all attached files does not exceed the allowed limit.

```js
/**
 * Validator checking whether the total size of attached files does not exceed the allowed limit of 3.5 MB.
 **/
function callService(context) {

    const MAX_TOTAL_SIZE_BYTES = 3584000;

    const file1SizeInput = context.getFirstParameter('rozmiarPliku1');
    const file2SizeInput = context.getFirstParameter('rozmiarPliku2');

    const file1Size = parseInt(file1SizeInput);
    const file2Size = parseInt(file2SizeInput);

    const totalSize = file1Size + file2Size;

    if (totalSize > MAX_TOTAL_SIZE_BYTES) {
        return [{
            key: 'pl.error.totalFileSizeExceeded',
            parameters: [
                file1Size, 
                file2Size, 
                'The maximum size of all attached files cannot exceed 3.5 MB.'
            ]
        }];
    }

    return [];

}
```

## Minimum value validator

Used to verify whether the amount or number entered by the user meets the lower limit requirement.

{% code lineNumbers="true" expandable="true" %}

```js
/*
* Validator checking whether the entered value is greater than or equal to the minimum value.
*/
function callService(context) {

    const userInput = context.getFirstParameter('userInput');
    const minValue = context.getFirstParameter('minValue');

    if (isInputEmpty(userInput) || isInputEmpty(minValue)) {
        return [];
    }

    const parsedAmount = parseUserAmount(userInput);
    const minLimit = parseUserAmount(minValue);

    if (parsedAmount.compareTo(minLimit) < 0) {
        return [{
            key: 'pl.error.minLimit',
            parameters: [minLimit, 'The minimum value for this field is {}.']
        }];
    }

    return [];

    /*
    * Checks whether the provided value is empty.
    */
    function isInputEmpty(value) {
        return value == null || String(value).trim() === '';
    }

    /*
    * Parses the user's text-based integer number into a BigDecimal object.
    */
    function parseUserAmount(amount) {
        let cleanedAmount = String(amount).replace(/\s/g, "");

        const lastCommaIndex = cleanedAmount.lastIndexOf(",");
        const lastDotIndex = cleanedAmount.lastIndexOf(".");

        if (lastCommaIndex > lastDotIndex) {
            cleanedAmount = cleanedAmount
                .replace(/\./g, "")
                .replace(",", ".");
        } else if (lastDotIndex > lastCommaIndex) {
            cleanedAmount = cleanedAmount.replace(/,/g, "");
        }

        return BigDecimal.valueOf(cleanedAmount);
    }
}
```

{% endcode %}

## Duplicate validator

Used to check whether there are duplicates among the values provided by the user, using PESEL numbers as an example.

{% code lineNumbers="true" expandable="true" %}

```js
/*
* Validates the uniqueness of PESEL numbers entered in the form.
*/
function callService(context) {

    const applicantPesel = context.getFirstParameter("applicantPesel");
    const spousePesel = context.getFirstParameter("spousePesel");
    const childrenPeselList = context.getParameters("childrenPeselList");

    let peselArrays = [];

    if (applicantPesel != null && applicantPesel.length > 0) {
        peselArrays.push(applicantPesel);
    }

    if (spousePesel != null && spousePesel.length > 0) {
        peselArrays.push(spousePesel);
    }

    if (childrenPeselList != null) {
        for (let i = 0; i < childrenPeselList.size(); i++) {
            if (childrenPeselList.get(i).length > 0) {
                peselArrays.push(childrenPeselList.get(i));
            }
        }
    }

    if (hasDuplicates(peselArrays)) {
        return [{
            'key': 'pl.error.peselDuplicated',
            'parameters': [peselArrays, 'The entered PESEL number has already been provided in the application for another person. Please enter a valid value.']
        }];
    } else {
        return [];
    }

    /*
    * Checks whether the passed array contains any repeating values.
    */
    function hasDuplicates(array) {
        let valuesSoFar = Object.create(null);
        for (let i = 0; i < array.length; ++i) {
            let value = array[i];
            if (value in valuesSoFar) {
                return true;
            }
            valuesSoFar[value] = true;
        }
        return false;
    }
}
```

{% endcode %}

## Validator for the number of selected checkboxes

Used to verify whether at least one checkbox from the given group has been selected on the form.

```js
/**
 * Checks whether at least one checkbox from the provided input list has been selected.
 */
function callService(context) {
    const checkboxValues = context.getParameters('checkBoxValues');
    let trueOccurrencesCount = 0;
    
    for (let i = 0; i < checkboxValues.size(); i++) {
        if (checkboxValues.get(i) === "true") {
            trueOccurrencesCount++;
        }
    }
    
    if (trueOccurrencesCount < 1) {
        return [{
            'key': 'pl.error.no.true.values',
            'parameters': [checkboxValues, 'At least one option must be selected']
        }];
    }
    
    return [];
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.eximee.com/documentation/documentation-en/budowanie-aplikacji/logika-biznesowa/scriptcode/walidatory-skryptowe-validationscript/sciaga-walidatorow-skryptowych.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
