Definovatelný business objekt kompletně přes REST API

Celý postup popsaný v návodu Jak vytvořit definovatelnou agendu - tedy založení business objektu, jeho vlastních položek i vizuální agendy - lze provést i čistě prostřednictvím Web API, bez jediného kliknutí v uživatelském rozhraní. To umožňuje celé řešení zabudovat do automatizovaného nasazení nebo skriptu, případně jej takto nechat sestavit i nástrojem umělé inteligence.

Přehled endpointů

Třem agendám z GUI postupu odpovídají tři API endpointy:

Agenda v GUI API endpoint
Definice business objektů /busobjdefs
Definovatelné položky /userfielddefs
Definice agend /sitedefs

Postup je potřeba dodržet ve stejném pořadí jako v GUI - nejprve business objekt, pak jeho položky, nakonec agenda nad hotovým business objektem.

1. Založení business objektu

Odpovídá kapitole Vytvoření definovatelného business objektu.

POST http://localhost:80/demodata/busobjdefs

Tělo požadavku (příklad číselníkového objektu):

{
    "name": "ApiNavodAgenda",
    "description": "Ukázková agenda založená přes API",
    "tablename": "ApiNavodAgendas",
    "botype": "roll",
    "apiendpoint": "apinavodagendas"
}

Odpověď obsahuje mimo jiné vygenerované CLSID nové třídy - budete jej potřebovat v dalších krocích.

Hodnota botype odpovídá typu z GUI: empty (Prázdný objekt), roll (Číselníkový objekt), document (Doklad), row (Řádek). U řádkového objektu se navíc uvádí headerclsid (CLSID hlavičkového objektu) a volitelně isrowscollection (odpovídá volbě Kolekce řádků, viz kapitola Vytvoření řádkového objektu). Identifikaci propojení s přílohami nastavíte polem reldeftodocument - hodnotu 0 systém při uložení nahradí prvním volným číslem z vyhrazeného rozsahu (stejně jako v GUI).

2. Založení vlastních položek

Odpovídá kapitole Doplnění vlastních položek.

POST http://localhost:80/demodata/userfielddefs

Tělo požadavku - hlavička odkazuje na CLSID business objektu z kroku 1, položky se zadávají jako pole rows:

{
    "clsid": "<clsid business objektu z kroku 1>",
    "rows": [
        {
            "fieldname": "POZNAMKA",
            "fielddisplaylabel": "Poznámka",
            "fielddisplayhint": "Poznámka",
            "extrafield": true,
            "fieldkind": 0,
            "fielddatatype": 1,
            "editmethod": 0,
            "hasforeignkey": false,
            "issortable": true,
            "useindynsql": true
        }
    ]
}

Pole extrafield odpovídá volbě Extra z GUI - viz kapitola o volbě Extra a prefixech X_/U_ v návodu Doplnění vlastních položek (u definovatelného business objektu ji nechávejte vždy zatrženou). Pro položku typu odkaz do číselníku s cizím klíčem (viz příklad v tomtéž návodu) přidejte hasforeignkey: true.

Pozor na pole velikosti: fielddisplaywidth je jen vizuální šířka sloupce, nikoli skutečná délka uložených dat - tou je pole fieldsize. Bez explicitně zadaného fielddbtype a fieldsize (jak je uvedeno ve výchozím příkladu výše) systém vytvoří pole s výchozí délkou 10 znaků - hodnoty kratší než tato délka se navíc při uložení zprava doplní mezerami na pevnou délku 10 (typ "Identifikátor", pevná délka).

3. Založení definice agendy

Odpovídá kapitole Vytvoření definovatelné agendy.

POST http://localhost:80/demodata/sitedefs
{
    "boclsid": "<clsid business objektu z kroku 1>",
    "name": "ApiNavodAgenda",
    "caption": "Ukázková agenda založená přes API",
    "description": "Vytvořeno podle návodu na založení DBO přes API"
}

Odpověď obsahuje vygenerované siteclsid nové agendy.

4. Použití nového endpointu

Nově vytvořený business objekt (a jeho apiendpoint z kroku 1) je - na rozdíl od postupu přes GUI - dostupný ihned, bez restartu aplikačního serveru. Při ověřování fungoval zápis přes nový endpoint úspěšně okamžitě po založení definice agendy v kroku 3, bez jakéhokoli čekání. Nový záznam do něj založíte standardně:

POST http://localhost:80/demodata/apinavodagendas
{
    "code": "NAVOD",
    "name": "Ukázkový záznam",
    "X_POZNAMKA": "Zalozeno"
}

Hodnota vlastní položky nesmí přesáhnout její definovanou délku (viz krok 2) - jinak systém vrátí chybu validace s popisem, která položka a proč selhala.

Poznámky k použití
  • Práva k nové agendě (záložka Práva k objektům, kapitola První spuštění a kontrola agendy) je potřeba nastavit zvlášť - tento návod se týká jen založení definic samotných.
  • Řadu dokladů pro dokladový typ (kapitola Řada dokladů jako chráněný objekt) tento návod neřeší - založte ji stejně jako v GUI postupu, případně doplňte podle stejného principu přes API endpoint řad dokladů.
  • Stejný princip (API namísto GUI) lze použít i pro přenos řešení mezi spojeními popsaný v návodu Přenos definovatelného řešení mezi spojeními pomocí instalační sady - místo importu instalační sady byste v cílovém spojení zopakovali stejné tři API požadavky.
  • Pro přístup do API musí mít použitý uživatel na svém detailu (agenda Uživatelé) zatrženou volbu Umožnit přístup do API na spojení a odpovídající licenci - bez toho API vrátí chybu "Uživatel nemá povoleno přihlášení z Webového API".
Skill pro AI nástroje ke stažení

Pokud pro rozšiřování systému ABRA Flores využíváte AI asistenta pro programování (např. Claude Code, GitHub Copilot, Codex apod.), můžete si stáhnout hotový "skill" - shrnutí celého tohoto postupu ve formátu, který si takový nástroj umí sám načíst a použít. Stačí pak asistentovi zadat požadavek v přirozeném jazyce (např. "vytvoř mi agendu Reklamace s hlavičkou obsahující firmu a řádky se skladovou kartou a počtem") a nechat ho, ať potřebné definice založí sám přes API popsané výše.

Skill si můžete stáhnout zde. Uložte jej do vašeho AI nástroje jako soubor SKILL.md ve složce pojmenované např. abra-definable-objects-api (u Claude Code typicky do .claude/skills/abra-definable-objects-api/SKILL.md) - přesný způsob instalace se může lišit podle konkrétního nástroje, řiďte se jeho dokumentací.

Pro přehled je celý obsah tohoto skillu i přímo zde:

---
name: abra-definable-objects-api
description: Create custom ABRA Gen business objects, fields, and agendas entirely through the REST API - no manual GUI work. Use whenever asked to add a new custom entity/table/agenda to an ABRA Gen system programmatically.
---

# ABRA Gen Definable Objects via REST API

## What this does

ABRA Gen supports fully custom, code-free business objects ("definovatelné business objekty") - your own database table, fields, and a user-facing agenda - created without any ABRA programming. This skill lets you, an AI coding assistant, build one end-to-end purely via HTTP calls to the ABRA Gen REST API, from a plain-language request such as "add a Complaints registry where each header has a company reference and rows have a stock item, quantity, and price."

## Before you start

1. Confirm the API base URL and connection name you're working against, e.g. `http://<host>:<port>/<connection>/...`.
2. Confirm the account you'll authenticate as has:
   - the checkbox **"Umožnit přístup do API na spojení"** (Allow API access on this connection) checked on its user record (agenda **Uživatelé**), and
   - a compatible license slot (Concurrent licensing needs a "Nevizuální uživatel API" license; Named-user licensing needs a "Uživatelská" or "Integrační" API license).

   Without this, every call fails with `403` and `"Uživatel nemá povoleno přihlášení z Webového API"`, even for an administrator account. **This has to be granted once via the desktop client by someone with administrator rights - there is no way to enable it through the API itself.** If you hit this error, explain exactly this to the user and ask them to check it, rather than trying other workarounds.
3. Every request below needs standard HTTP authentication (Basic auth, or whatever login method your system uses) and the headers `Accept: application/json` plus a non-empty `User-Agent`. Don't send `Content-Type: application/json` on a request with no body - it can be rejected with `406`.

## The three building blocks

Always in this order - each depends on the previous one:

1. **The business object itself** → `POST /<connection>/busobjdefs`
2. **Its custom fields** → `POST /<connection>/userfielddefs` (first call for a given class) or `PUT /<connection>/userfielddefs/<id>` (to add more fields later to a class that already has some)
3. **The user-facing agenda** → `POST /<connection>/sitedefs`

Once all three exist, the new object's own REST endpoint is live immediately - no server restart needed, no waiting.

### 1. Create the business object

```
POST /<connection>/busobjdefs
```
```json
{
    "name": "Reklamace",
    "description": "Reklamace",
    "tablename": "Reklamaces",
    "botype": "document",
    "apiendpoint": "reklamace"
}
```

`botype` is one of:

- `empty` - a bare object with just a name.
- `roll` - behaves like a register/číselník (has Code + Name).
- `document` - a document-style header object (can have a numbering series and rows).
- `row` - a child row object belonging to a header; also requires `"headerclsid": "<header's clsid>"`, and `"isrowscollection": true` if this is the header's *main* row collection (only one row-type object per header may have this flag).

To let the object support file attachments, add `"reldeftodocument": 0` (the server assigns a real number automatically on save).

The response contains the new object's `clsid` - keep it, you'll need it in the next two steps.

### 2. Add custom fields

```
POST /<connection>/userfielddefs
```
```json
{
    "clsid": "<clsid from step 1>",
    "rows": [
        {
            "fieldname": "FIRMA",
            "fielddisplaylabel": "Firma",
            "fielddisplayhint": "Firma",
            "extrafield": true,
            "fieldkind": 0,
            "fielddatatype": 1,
            "editmethod": 0,
            "hasforeignkey": true
        }
    ]
}
```

Key properties:

- **`extrafield: true`** - always set this for a field on a definable object's own table. Leaving it `false` routes the value through a legacy shared system table instead of the object's own table, defeating the purpose of having a dedicated custom object - there's essentially never a reason to use `false` here.
- **`fielddatatype`** - the business data type: `1` = text ("Znaky"), `2` = whole number, `3` = decimal number (others exist for dates/booleans/etc.). If unsure, try `1` for text and adjust based on the validation error you get back (see "When something goes wrong" below).
- **`hasforeignkey: true`** - use for a reference field (a value that must point to an existing record of some other register, e.g. a company). Valid together with `fielddatatype: 1` and a "Číselník" edit method - it enforces at the database level that the value must exist in the target register and can't be deleted while referenced.
- The field's actual name in created records is automatically prefixed (e.g. `X_FIRMA` for an Extra field named `FIRMA`) - don't add the prefix yourself.

To add more fields to an object that already has a `userfielddefs` entry (you already made the call above once for this `clsid`), use `PUT /<connection>/userfielddefs/<id>` instead (`id` is in the response of the first call), with the same `rows` array shape containing just the new field(s).

**Known limitation - don't try to set a custom field size or precision in the same request as the field's database type.** Sending `fieldsize` (or `fieldprecision`) together with an explicit database-type property in one request reliably fails validation ("FieldSize is not editable...") across text, integer, and decimal fields, and it can't be fixed afterwards either - field size is locked once a field is saved, the same as in the desktop client. **Practical approach: create fields with their default size/precision through this API.** If a customer genuinely needs a longer text field or a specific decimal precision, create that one field through the ABRA Gen desktop client instead, where this restriction doesn't apply. Don't spend time trying to work around this purely via API calls - it currently isn't possible.

### 3. Create the agenda

```
POST /<connection>/sitedefs
```
```json
{
    "boclsid": "<clsid from step 1>",
    "name": "Reklamace",
    "caption": "Reklamace",
    "description": "Evidence reklamací"
}
```

The response contains a `siteclsid` for the new agenda.

### 4. Use it

```
POST /<connection>/<apiendpoint from step 1>
```
```json
{
    "code": "R0001",
    "name": "První reklamace",
    "X_FIRMA": "<id of an existing company record>"
}
```

This works immediately - no restart, no waiting.

## Rows / child records

If the header object has a row-type child object (created with `botype: "row"`, `headerclsid` pointing at the header, and `isrowscollection: true`), its own custom fields are created exactly the same way as the header's (step 2, using the row object's own `clsid`). New row records for a specific header record are created via `POST /<connection>/<apiendpoint>/<header id>/rows`.

To give different rows of the same collection different visible columns depending on some value (e.g. a "text row" vs. a "stock item row"), mark one integer-valued field on the row object with `"ismultigridlayoutident": true` (only one field per header object may have this set) - its value then picks which desktop-client column layout is shown for that particular row.

## Attachments

If the object has `reldeftodocument` set (step 1), files can be attached to its records the same way as with any ABRA Gen document:

```
POST /<connection>/Documents
```
```json
{
    "Category_ID": "<a document category id>",
    "DocQueue_ID": "<a numbering series id for the Documents agenda>",
    "Contents": [{"Description": "...", "FileName": "invoice.pdf", "DataAsBytes": "<base64-encoded file content>"}]
}
```

Then attach the resulting document's `id` to a record:

```
PUT /<connection>/<apiendpoint>/<record id>/attachments
```
```json
["<document id>"]
```

`GET` the same URL to list attached documents, `DELETE` with the same body to detach. This works on business object types other than just document-type ones (confirmed directly on a register/"roll" type object too).

## Rights

None of the above makes the new agenda visible to any user except one with the Supervisor privilege. To grant rights to a role, set them under **Role → Práva k funkcím → Definovatelné agendy** in the desktop client - this isn't currently something to automate through this cookbook; do it manually, or ask the customer's administrator to do it.

## Numbering series (document type only)

If you created a `document`-type object, it also needs a numbering series ("Řada") before real records can be meaningfully created, the same as any other document type in the system. Set it up the normal way for the ABRA Gen edition in use; when created for a definable document type, the series' own type is pre-filled correctly.

## When something goes wrong

ABRA Gen's validation errors are specific and worth reading rather than guessing around:

```json
{
  "description": "Chyba při validaci objektu \"...\": <field-specific message>",
  "details": { "validation": { "errors": { "values": [
    { "<fieldname>": { "@description": "...", "@displaylabel": "..." } }
  ]}}}
}
```

`@displaylabel` names the exact property that's the problem (in the system's configured language), and `@description` explains why. Adjust just that one property and retry rather than restarting the whole approach from scratch - most first attempts at a field type you haven't used before need one or two rounds of this.

## What this cookbook deliberately doesn't cover

- Printed report / DynSQL customization for a new agenda.
- Transferring a definable object between two systems/connections (a separate, GUI-driven "instalační sada" mechanism).
- The desktop client's visual "definovatelný formulář" designer.

If a task grows to need one of those, say so explicitly to the user rather than guessing at API calls this cookbook hasn't confirmed.

Skill obsahuje pouze obecný, technický postup nad API - neřeší práva k agendě ani specifika vašeho konkrétního řešení. Před nasazením do provozu vždy postupujte podle doporučení v tomto návodu, tedy nejprve vše ověřte v testovacím spojení.