> 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/budowanie-aplikacji/logika-biznesowa/scriptcode/walidatory-skryptowe-validationscript/sciaga-walidatorow-skryptowych.md).

# Ściąga - przykładowe walidatory skryptowe

Poniższe fragmenty kodu przedstawiają przykładowe walidatory skryptowe napisane w **ScriptCode**.

Udostępnione szablony mają charakter poglądowy i wymagają samodzielnego dostosowania. Należy uwzględnić specyfikację parametrów wejściowych, dedykowaną logikę biznesową oraz odpowiednią treść komunikatów walidacyjnych. Każda implementacja powinna zostać pokryta testami jednostkowymi, uwzględniającymi scenariusze brzegowe.

## Walidator numeru PESEL

Służy do zweryfikowania poprawności podanego numeru PESEL.

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

```js
/*
* Walidator weryfikujący poprawność numeru PESEL (format, suma kontrolna oraz poprawność daty urodzenia).
*/
function callService(context) {
    const peselInput = context.getFirstParameter('pesel');

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

    // A) Weryfikacja formatu (dokładnie 11 cyfr)
    if (!peselInput.match(/^[0-9]{11}$/)) {
        return [{
            'key': 'pl.error.invalidPeselFormat',
            'parameters': [peselInput]
        }];
    }

    // B) Wykluczenie PESEL-u składającego się z samych zer
    if (peselInput == "00000000000") {
        return [{
            'key': 'pl.error.peselAllZeros',
            'parameters': [peselInput]
        }];
    }

    // C) Sprawdzenie sumy kontrolnej peselu
    if (!isValidChecksum(peselInput)) {
        return [{
            'key': 'pl.error.invalidPeselChecksum',
            'parameters': [peselInput]
        }];
    }

    // D) Weryfikacja poprawności daty urodzenia
    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 [];

    /*
    * Sprawdza, czy przekazana wartość jest pusta.
    */
    function isInputEmpty(value) {
        return value == null || String(value).trim() === '';
    }

    /*
    * Oblicza i weryfikuje cyfrę kontrolną numeru PESEL.
    */
    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;
    }

    /*
    * Oblicza rok urodzenia z numeru PESEL.
    */
    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;
    }

    /*
    * Oblicza miesiąc urodzenia z numeru PESEL.
    */
    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;
    }

    /*
    * Oblicza dzień urodzenia z numeru PESEL.
    */
    function getBirthDay(pesel) {
        let day = 10 * parseInt(pesel[4]);
        day += parseInt(pesel[5]);
        return day;
    }

    /*
    * Weryfikuje, czy dzień i miesiąc są poprawne dla danego roku (w tym lata przestępne).
    */
    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 %}

## Walidator wieku

Służy do weryfikacji wieku na podstawie daty urodzenia. Sprawdza, czy osoba ukończyła 15. rok życia.

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

```js
/*
* Walidator sprawdza datę urodzenia dziecka i zwraca błąd, jeśli ukończyło ono 15. rok życia.
*/
function callService(context) {

    const ERR_AGE_VALIDATION = [{ 
        key: 'pl.error.ageValidationError', 
        parameters: ['Błąd podczas walidacji wieku.'] 
    }];
    
    const ERR_ADULT = [{ 
        key: 'pl.error.aboveMaximumAge', 
        parameters: ['Świadczenie przysługuje na dziecko w wieku do ukończenia 15 r. życia.'] 
    }];

    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();

    //Ustalanie dnia 15. urodzin
    const birthDate = new Date(birthTimestamp);
    const legalAgeLimitDate = new Date(birthDate.getFullYear() + 15, birthDate.getMonth(), birthDate.getDate());

    //Porównanie do dzisiejszej daty
    if (today >= legalAgeLimitDate) {
        return ERR_ADULT;
    }

    return [];
}
```

{% endcode %}

## Walidator roku urodzenia

Służy do weryfikacji, czy wprowadzona data urodzenia nie jest wcześniejsza niż rok 1900.

```js
/*
* Sprawdza, czy rok urodzenia nie jest wcześniejszy niż 1900 r.
*/
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, 'Data urodzenia nie może być wcześniejsza niż 1900 r.']
            }];           
        }
    }

    return [];
}
```

## Walidator numeru dowodu osobistego

Służy do weryfikowania polskiego numeru dowodu osobistego.

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

```js
/* 
*Skrypt służy do formalnej i matematycznej weryfikacji poprawności numeru polskiego dowodu osobistego.
*/
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;
    }

    /*
    * Konwertuje litery w numerze dowodu na odpowiadające im wartości liczbowe.
    */
    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;
    }

    /*
    * Oblicza i weryfikuje sumę kontrolną numeru dowodu osobistego.
    */
    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];
    }

    /*
    * Weryfikuje, czy numer dowodu spełnia wymagania formatu (3 litery + 6 cyfr) oraz czy jego suma kontrolna jest poprawna.
    */
    function isMaskCorrect(number) {
        return REGEX_ID_MASK.test(number) && isChecksumValid(number);
    }

    /**
    * Sprawdza, czy długość wpisanego numeru zgadza się z oczekiwaną długością (9 znaków).
    */
    function isLengthCorrect(numberId) {
        return numberId.length === WEIGHT.length && isMaskCorrect(numberId);
    }
}
```

{% endcode %}

## Walidator adresu e-mail

Służy do weryfikacji formatu oraz składni wprowadzonego adresu e-mail.

```js
/*
* Waliduje poprawność składniową adresu e-mail na podstawie wyrażenia regularnego.
*/
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, 'Podana wartość jest błędna']
        }];
    } else {
        return [];
    }
}
```

## Walidator rozmiaru plików

Służy sprawdzeniu czy suma wszystkich załączonych plików nie przekracza dopuszczalnego limitu.

```js
/**
 * Walidator weryfikujący, czy łączny rozmiar załączonych plików nie przekracza dopuszczalnego limitu 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, 
                'Maksymalny rozmiar wszystkich załączonych plików nie może przekroczyć 3,5 MB.'
            ]
        }];
    }

    return [];

}
```

## Walidator wartości minimalnej

Służy do weryfikacji, czy kwota lub liczba wprowadzona przez użytkownika spełnia wymóg dolnego limitu.

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

```js
/*
* Walidator weryfikujący czy wprowadzona wartość jest większa bądź równa wartości minimalnej.
*/
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, 'Minimalna wartość dla tego pola wynosi {}.']
        }];
    }

    return [];

    /*
    * Sprawdza, czy przekazana wartość jest pusta.
    */
    function isInputEmpty(value) {
        return value == null || String(value).trim() === '';
    }

    /*
    * Parsuje tekstową liczbę całkowitą użytkownika do obiektu BigDecimal.
    */
    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 %}

## Walidator duplikatów

Służy sprawdzeniu czy wśród podanych przez użytkownika wartości nie znajdują się duplikaty na przykładzie numerów PESEL.

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

```js
/*
* Waliduje unikalność numerów PESEL wprowadzonych na formularzu.
*/
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, 'Wprowadzony numer PESEL został już podany na wniosku dla innej osoby. Wpisz poprawną wartość.']
        }];
    } else {
        return [];
    }

    /*
    * Sprawdza, czy w przekazanej tablicy znajdują się jakiekolwiek powtarzające się wartości.
    */
    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 %}

## Walidator liczby zaznaczonych checkboxów

Służy do weryfikacji, czy na formularzu został zaznaczony przynajmniej jeden checkbox z podanej grupy.

```js
/**
 * Sprawdza, czy zaznaczono przynajmniej jeden checkbox z przekazanej listy wejściowej.
 */
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, 'Należy wybrać przynajmniej jedną opcję']
        }];
    }
    
    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/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.
