# API skryptów

## Pobieranie danych wejściowych <a href="#skrypty-scriptservice-pobieraniedanychwejsciowych" id="skrypty-scriptservice-pobieraniedanychwejsciowych"></a>

Poniżej znajduje się przykładowy kod, który pokazuje, w jaki sposób można korzystać z wejścia oraz jak należy zwrócić dane.

```javascript
function callService(context){
  const firstArgument = context.getFirstParameter("firstArgument");
  const firstArgumentList = context.getParameters("firstArgument");
  const keySet = context.getInputParameters().keySet();
  const comboboxLabel = context.getData("GesCombobox1","label");
  const result = "service script constant " + firstArgument + " list value: " + firstArgumentList + " and first from list: " + firstArgumentList.get(0) + " keySet " + keySet;
  return [{'output': result}];
}
```

## Wejście do Skrypt serwisu <a href="#skrypty-scriptservice-wejsciedoskryptserwisu" id="skrypty-scriptservice-wejsciedoskryptserwisu"></a>

Jako wejście (parametr *context* w powyższym kodzie) znajduje się obiekt, który udostępnia następujące metody:

* List\<String> **getParameters**(final String name); - pobiera konkretną listę z mapy danych wejściowych,
* String **getFirstParameter**(final String name); - pobiera pierwszy element z konkretnej listy z mapy danych wejściowych lub zwraca wartość "null",
* String **getFirstParameter**(final String name, final String defaultIfEmpty); - pobiera pierwszy element z konkretnej listy z mapy danych wejściowych, a jeśli go nie ma lub jest pusty to zwraca wartość "defaultIfEmpty",
* Map\<String, List\<String>> **getInputParameters**(); - zwraca całą mapę danych wejściowych, którą przechowuje,
* String **isVisible**(final String id); - pobiera informację, czy komponent o wskazanym id jest widoczny,
* String **getValue**(final String id); - pobiera wartość komponentu (również zmiennej sesyjnej) o wskazanym id,
* void **setValue**(final String componentId, final String value); - ustawia wartość **value** komponentu o wskazanym **componentId**. Zasada podawania componentId jest taka sama jak przy getValue.\
  Wywołując skrypt wewnątrz komponentu złożonego, w celu ustawienia wartości komponentu / zmiennej sesyjnej osadzonej w tym samym komponencie, należy componentId prefiksować znakiem **@**

> **UWAGA!** Próba wykonania **setValue** na komponencie, który nasłuchuje na inny komponent lub na komponencie, **na** którego nasłuchują inne komponenty, poskutkuje rzuceniem wyjątku.

* String **getData**(final String id, final String attribute); - pobiera wartość konkretnego atrybutu dla komponentu o wskazanym id

> **UWAGA!** Możliwe do pobrania atrybuty są zależne od komponentu.

* List\<Map\<String, String>> **callService**(String name, Map\<String, List\<String>> input); - umożliwia wołanie ServiceProxy,
* ValidatorOutput **validate**(String name, Map\<String, List\<String>> input); - umożliwia wołanie walidatora

## Wyjście ze Skrypt serwisu <a href="#skrypty-scriptservice-wyjsciezeskryptserwisu" id="skrypty-scriptservice-wyjsciezeskryptserwisu"></a>

Wynik wykonania skryptu możemy zwrócić na dwa sposoby:

1. **Lista map** - tablica obiektów na wyjściu jest parsowana na listę map, po czym zostaje przetwarzana w standardowy sposób.
2. **Pojedyncza mapa** - zwrotka zostaje opakowana jako lista jednoelementowa, po czym przetwarzana jest w standardowy sposób.

\
Wyjście z skryptu z przykładową listą:

```javascript
  return [{'output': 'result1'},{'output': 'result2'},{'output': 'result3'}];
```

## Logowanie <a href="#skrypty-scriptservice-logowanielogowanie" id="skrypty-scriptservice-logowanielogowanie"></a>

Logowanie danych wejściowych jest automatyczne

Logowanie ręczne powinno być zgodne z opisem w [Logowanie w ScriptCode](https://docs.eximee.com/budowanie-aplikacji/logika-biznesowa/scriptcode/logowanie-w-scriptcode)

```javascript
function callService(context) {
    const sessionVariable = context.getValue("@sessionVar");
    Logger.info('Wartosc zmiennej sesyjnej [arg1={}, arg2={}]', nonsensitive('arg1 nonsensitive test'), sessionVariable);
    return [{'sessionVar':sessionVariable }];
}
```

## Rzucanie wyjątków biznesowych

Błędy biznesowe zostały szczegółowo opisane na stronie [Strony błędów](https://docs.eximee.com/interfejs-uzytkownika/formularze/tworzenie-formularza/strony-bledow#bledy-biznesowe).

## Zapis danych tymczasowych <a href="#skrypty-scriptservice-zapisdanychtymczasowych" id="skrypty-scriptservice-zapisdanychtymczasowych"></a>

Możliwe jest zapisanie pewnych danych pomiędzy wywołaniami serwisu. Służy do tego obiekt `registry`.

Możliwe metody, które można wywołać na obiekcie `registry`:

* save(namespace, id, data) - zapis danych
* saveVersion(namespace, id, data, version) - zapis danych z weryfikacją wersji. Jeśli pole version jest nieustawione lub jest puste - zapis bez weryfikacji. Jeśli wartość pola version nie zgadza się z aktualną wersją przechowywanych danych, wniosek zakończy się z błędem.
* get(namespace, id) - pobranie danych
* getVersion(namespace, id) - pobranie obiektu { data: 'zapisane dane', version: 'aktualna wersja danych' }
* delete(namespace, id) - usuwanie danych.

Dane przechowywane są w przestrzeniach nazw (namespace w metodach) ustalanych przez administratorów. Każdej przestrzeni można ustawić czas życia danych. Domyślnie jest to **90 dni**. Podanie tego samego id w ramach kilku wywołań zapisu powoduje aktualizację danych powiązanych z danym id. Wersja danych to unikalny identyfikator generowany przy każdym zapisie danych.

{% hint style="info" %}
Obiekt to poprawnego działania wymaga działającej aplikacji EximeeRegistry.
{% endhint %}

{% hint style="danger" %}
**Zapis danych za pomocą EximeeRegistry nie służy do zapisu czegokolwiek na stałe!**
{% endhint %}

**Przykłady:**

```javascript
context.registry().save('test', '123123', 'dane tymczasowe');
context.registry().get('test', '123123'); // zwróci 'dane tymczasowe'
const item = context.registry().getVersion('test', '123123'); // zwróci obiekt {data,version}
context.registry().saveVersion('test','123123', 'nowe dane', item.version); // wersja zgodna zapis się uda
context.registry().saveVersion('test','123123', 'nowe dane', 'jakaś inna wersja'); // wersja niezgodna zapis się nie uda
context.registry().delete('test','123123');

```

## Pobieranie kontekstu zalogowanego użytkownika <a href="#skrypty-scriptservice-pobieraniekontekstuzalogowanegouzytkownika" id="skrypty-scriptservice-pobieraniekontekstuzalogowanegouzytkownika"></a>

{% hint style="warning" %}
Funkcjonalność dostępna od wersji platformy: 2.3403.0

Funkcjonalność działa na wnioskach uruchamianych w aplikacji webforms ze skonfigurowaną autoryzacją oauth.\
Nie działa natomiast na wnioskach uruchamianych w aplikacji Eximee Dashboard
{% endhint %}

Istnieje możliwość pobrania kontekstu aktualnie zalogowanego użytkownika, który uzupełnia wniosek.

<details>

<summary>API</summary>

```
/**
 * Kontekst security formularza, zawierające dane dotyczące bezpieczeństwa. Po realizacji tego tematu będzie zawierać tożsamość aktualnego użytkownika.
 */
interface SecurityContext {
  /**
   * Tożsamość aktualnego użytkownika
   */
  getCurrentUser(): Identity | null;
}
 
interface ScriptApi {
  // ...
  /**
   * Pobranie aktualnego kontekstu użytkownika
   */
  getSecurityContext(): SecurityContext;
}
 
/**
 * Reprezentacja roli użytkownika
 */
interface Role {
  name: string;
}
 
/**
 * Reprezentacja tożsamości użytkownika
 */
interface Identity {
  /**
   * Identyfikator tożsamości użytkownika. W kontekście tego tematu zawsze 'current'
   */
  id: string;
  /**
   * Nazwa użytkownika. W kontekście tego tematu jest to SKP pracownika.
   */
  username?: string;
  /**
   * Role użytkownika
   */                              
  roles?: Role[];
 
  /**
   * Imię użytkownika
   */
  firstName?: string;
 
  /**
   * Nazwisko użytkownika
   */
  lastName?: string;
}
```

</details>

{% hint style="info" %}
Podczas uruchomienia skryptu bez zalogowanego kontekstu użytkownika metoda **`context.getSecurityContext()`** zwróci wartość **null**
{% endhint %}

Przykładowe użycie w skrypcie kontekstu użytkownika

```javascript
function callService(context) {
    context.getSecurityContext().getCurrentUser();               
  // return: { id: 'current', username: '100001', firstName: 'Jan', lastName: 'Kowalski', roles: [{name: 'role_001'}, {name: 'role_002'}] }
    // Sprawdzanie czy zalogowany użytkownik ma role "role_001".
    var czyMaRole = context.getSecurityContext().getCurrentUser().roles.map(x=> x.name).includes("role_001");
     
    // Pobranie loginu aktualnie zalogowanego użytkownika. 
    var username = context.getSecurityContext().getCurrentUser().username;
}

```

## Pobieranie konfiguracji aplikacji <a href="#skrypty-scriptservice-pobieraniekonfiguracjiaplikacji" id="skrypty-scriptservice-pobieraniekonfiguracjiaplikacji"></a>

{% hint style="warning" %}
Funkcjonalność dostępna od wersji platformy: 3.190.0

Funkcjonalność działa na wnioskach uruchamianych jako [Aplikacja biznesowa](https://docs.eximee.com/wprowadzenie/aplikacja-biznesowa)
{% endhint %}

{% hint style="info" %}
Funkcjonalność pobierania konfiguracji aplikacji jest dostępna dla skryptów (scriptService), zadań skryptowych (scriptTask) oraz walidatorów skryptowych (validationScript).
{% endhint %}

W skryptach istnieje możliwość pobrania konfiguracji aplikacji

```javascript
interface Api {
    config: {
        v1: {
          get(klucz: string): string;
          getOrDefault(klucz: string, defaultValue: string): string;
        }
    }
}
```

Przykładowy skrypt pobierający konfiguracje:

```javascript

function callService(context) {
    let value1
    try {
        value1 = api.config.v1.get("application.url");
    } catch (e) {
        value1 = "default"
    }
 
    let value2 = api.config.v1.get("application.url");
 
    let value3 = api.config.v1.getOrDefault("not_existing_key", "defaultValue")
 
    return [{'value1': value1, 'value2': value2, 'value3': value3}];
}

```

## Przetwarzanie plików xlsx <a href="#skrypty-scriptservice-przetwarzanieplikowxlsx" id="skrypty-scriptservice-przetwarzanieplikowxlsx"></a>

{% hint style="warning" %}
Potrzebny moduł xlsx-sheet-handling-module
{% endhint %}

Możliwy jest odczyt plików xlsx załączonych na wniosku. W tym celu należy skorzystać z modułu xlsx-sheet-handling-module oraz dostarczanego przez niego endpointu */xlsx/v1* - moduł aktualnie dostarczany jest niezależnie, należy wykonać odpowiednią konfiguracje dostępu do usługi w ScriptApi. Do modułu należy przekazać request:

```javascript
{
    content: string
}
```

gdzie w content przekazujemy plik w formie base64. W takiej formie jest przekazywany do serwisu gdy zmapujemy na wejście uploader (w przypadku wielu plików w uploaderze jest to lista). W odpowiedzi otrzymamy mapę z podziałem: arkusz → wiersz → kolumna

```javascript
{
    "arkusz": {
        "1": {
            "A": { "test"
                }
            }
    }
}
```

Przykład:

```javascript
function callService(context) {
    let files = context.getParameters("uploader");
 
    if (files.size() === 0) {
        return [{}];
    }
 
    let header = {};
    let body = {'content': files.get(0)}
 
    try {
        let response = api.rest.v1.post('excelDocument', { pathParams: ['xlsx', 'v1'] }, header , body);
     
        return [{'output': JSON.stringify(response.body)}];
    } catch (error) {
        Logger.info(error );
        return [{'output': 'Wystapil blad'}];
    }
 
}
```

## Pobieranie zawartości Treści <a href="#skrypty-scriptservice-pobieraniezawartoscitresci" id="skrypty-scriptservice-pobieraniezawartoscitresci"></a>

{% hint style="warning" %}
Funkcjonalność dostępna od wersji platformy: **3.332.0**
{% endhint %}

Z poziomu skryptu można pobrać zawartość artefaktu **Treść** (textContent) utworzoną w Eximee Designer, wykorzystując do tego funkcję: `api.repository.v1.textContent`. Funkcja ta zwraca obiekt, który posiada treści dla każdego ze zdefiniowanych tłumaczeń. By pobrać treść dla danego tłumaczenia używamy funkcji `language`. Przykład użycia:

```javascript
const nazwaArtefaktu = "stopka";
const wersjaArtefaktu = "*";
const jezyk = "pl";
 
const artefaktTresci = api.repository.v1.textContent(nazwaArtefaktu, wersjaArtefaktu);
const stopkaPl = artefaktTresci.language(jezyk).text();
```

{% hint style="danger" %}

1. funkcja **`textContent`** rzuca wyjątek jeśli nie znajdzie artefaktu o podanych parametrach
2. funkcja **`language`** rzuca wyjątek jeśli nie znajdzie tłumaczenia w podanym języku
   {% endhint %}

Jeśli nie mamy pewności, że podane przez nas parametry są prawidłowe, możemy obsłużyć wyjątki używając **try catch**:

```javascript
const nazwaArtefaktu = "stopka";
const wersjaArtefaktu = "*";
const jezyk = "pl";
 
let artefaktTresci;
try {
    artefaktTresci = api.repository.v1.textContent(nazwaArtefaktu, wersjaArtefaktu);
} catch (error) {
    return [{'output': "Brak artefaktu o nazwie: " + nazwaArtefaktu + " i wersji: " + wersjaArtefaktu}]
}
 
let stopkaPl;   
try {
    stopkaPl = artefaktTresci.language(jezyk).text();  
} catch (error) {
    return [{'output': "W artefakcie nie znaleziono tłumaczenia dla języka: " + jezyk}];
}
 
return [{'output': stopkaPl}];


```

## Operacje matematyczne w ScriptCode

Więcej informacji w [Operacje matematyczne w ScriptCode](https://docs.eximee.com/budowanie-aplikacji/logika-biznesowa/scriptcode/skrypty-scriptservice/api-skryptow/operacje-matematyczne-w-scriptcode)

## Operacje i dostęp do danych procesu

Więcej informacji w [operacje-i-dostep-do-danych-procesu](https://docs.eximee.com/budowanie-aplikacji/logika-biznesowa/scriptcode/skrypty-scriptservice/api-skryptow/operacje-i-dostep-do-danych-procesu "mention")

## Pobieranie statusów wniosków

Więcej informacji w [Pobieranie statusów wniosków](https://docs.eximee.com/budowanie-aplikacji/logika-biznesowa/scriptcode/skrypty-scriptservice/api-skryptow/pobieranie-statusow-wnioskow)

## Model danych

Więcej informacji w [API modelu danych](https://docs.eximee.com/budowanie-aplikacji/model-danych/wykorzystanie-modelu-danych/api-modelu-danych)

## Inne przykłady

### Zasilenie komponentu Pole wyboru wartości z listy (Combobox) <a href="#skrypty-scriptservice-przykladowyskryptzasilajacykomponentpolewyboruwartoscizlisty-combobox-example" id="skrypty-scriptservice-przykladowyskryptzasilajacykomponentpolewyboruwartoscizlisty-combobox-example"></a>

Skrypt zasila **Pole wyboru wartości** z listy (Combobox) na podstawie przekazanego parametru 'locale'.

Wyjścia **id**, **label**, oraz **description** należy podpiąć pod odpowiednie pola comboboxa, kolejno **id**, **text**, oraz **description**.

Skrypt zasilający combobox:

```javascript
function callService(context) {
    const locale = context.getFirstParameter('locale');
    if (locale === 'pl') {
        return [
            { 'id': 1, 'label': 'Wartosc 1', 'description': 'Opis 1', },
            { 'id': 2, 'label': 'Wartosc 2', 'description': 'Opis 2' }
        ];
    } else if (locale === 'en') {
        return [
            { 'id': 1, 'label': 'Label 1', 'description': 'Description 1', },
            { 'id': 2, 'label': 'Label 2', 'description': 'Description 2' }
        ];
    } else {
        return [
            { 'id': 1, 'label': 'Wartosc domslnego tlumaczenia 1', 'description': 'Opis 1', },
            { 'id': 2, 'label': 'Wartosc domslnego tlumaczenia 2', 'description': 'Opis 2' }
        ];
    }
}
```

### Pobieranie nazwy plików z komponentu Załączniki

Skrypt wykorzystuje metodę **getData()**, która pobiera wartość konkretnego atrybutu dla komponentu o wskazanym id. Dla komponentu **Załączniki** nazwy dodanych plików określane są za pomocą atrybutu **fileNames** i przychodzą z wniosku jako string w formacie JSON (np. *\["name1.png", "name2.png"]*), dlatego konieczne jest przekształcenie tego stringa w obiekt za pomocą metody **JSON.parse**.

{% hint style="warning" %}
**UWAGA!** Metoda **getData()** wykorzystuje id komponentu, więc skrypt nie jest uniwersalny - dla każdego wniosku należy podać odpowiednie id komponentu **Załączniki**:
{% endhint %}

```javascript
function callService(context) {
    const zalacznik1 = JSON.parse(context.getData("@GesUploadFile1", "fileNames"));
    const zalacznik2 = JSON.parse(context.getData("@GesUploadFile2", "fileNames"));
}
```

### Pobieranie wartości Pola wyboru wartości z listy (Comboboxa) z sekcji powtarzalnej <a href="#skrypty-scriptservice-fragmentskryptupobierajacegowartoscipolawyboruwartoscizlisty-comboboxa-zsekcji" id="skrypty-scriptservice-fragmentskryptupobierajacegowartoscipolawyboruwartoscizlisty-comboboxa-zsekcji"></a>

Skrypt wykorzystuje metodę **getData()**, która pobiera wartość konkretnego atrybutu, dla komponentu o wskazanym id. Dla komponentu **Pole wyboru wartości z listy** wartości (etykiety) danych kluczy określane są za pomocą atrybutu **label.**

```javascript
for (let i=0; i<10; i++)  {
        let id = "GesRepeatableSection1.row" + i + ".GesCombobox1";
        let etykieta = context.getData(id, "label");
}
```


---

# Agent Instructions: 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:

```
GET https://docs.eximee.com/budowanie-aplikacji/logika-biznesowa/scriptcode/skrypty-scriptservice/api-skryptow.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
