Prace nad celym modelem: cesty, ukazka tela a smycka nad seznamem
Odesilatel posila cely model. Objednavka ze Shoptetu ma zanoreni, ceny
v podobjektech a seznam polozek - a dosud sel napojit jen plochy seznam
skalarnich poli, takze items[] neslo pouzit vubec.
- Odkaz v sablone muze byt cesta: {{data.order.billingAddress.city}},
{{data.order.items[0].name}}, {{st_faktura.invoiceId}}. Overuje se prvni
cast odkazu, takze ploche odkazy funguji dal presne jako driv.
- Cele telo je v kontextu i v puvodnim tvaru. Deklarovane parametry maji
pri shode jmen prednost.
- Spoustec si pamatuje ukazku skutecneho tela. Server z ni odvodi model,
tedy seznam cest i s typy, a ten se v krocich klika misto opisovani.
Tlacitko doplni z hodnot v ukazce parametry pro podminky.
- Novy krok Pro kazdou polozku: projde seznam a za kazdou polozku vykona
vnoreny podstrom. Uvnitr je item a index, po skonceni krok.results se
seznamem vysledku. Kazdy vysledek nese i puvodni polozku - radek
objednavky potrebuje jak ID z CRM, tak mnozstvi z puvodnich dat.
Strop 200 polozek, mimo seznam krok selze s tim, co tam misto nej je.
- Prevod Za kazdou polozku seznamu v klikacim editoru mapovani. Engine ho
umel, sel ale napsat jen rucnim JSONem.
- Typograficke uvozovky a sipka z kodu pryc.
Overeno nad skutecnym modelem objednavky: 23 cest vcetne
data.order.items[].unitPrice.withoutVat, sablony s cestou i s indexem,
smycka nad dvema polozkami s posbiranymi vysledky.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fc0c2ff6c7
commit
9b18531d3e
+34
-5
@@ -798,6 +798,13 @@ const stepSchema: z.ZodType<FlowStep> = z.lazy(() =>
|
||||
// Klic je ID pole z katalogu, hodnota sablona. Overuje se nize.
|
||||
inputs: z.record(z.string()).optional(),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string().min(1),
|
||||
kind: z.literal('foreach'),
|
||||
/** Cesta k seznamu v datech, napr. `data.order.items`. */
|
||||
path: z.string().trim().min(1, 'Smyčka musí mít cestu k seznamu.').max(200),
|
||||
steps: z.array(stepSchema),
|
||||
}),
|
||||
z.object({
|
||||
id: z.string().min(1),
|
||||
kind: z.literal('condition'),
|
||||
@@ -849,6 +856,19 @@ const flowSchema = z.object({
|
||||
serviceId: z.string().min(1),
|
||||
operationId: z.string().min(1),
|
||||
fields: z.array(fieldSchema),
|
||||
/**
|
||||
* Ukazka skutecneho tela. Odvozuje se z ni model, viz data/model.ts.
|
||||
*
|
||||
* Strop je kvuli tomu, ze se uklada s automatizaci a cte pri kazdem
|
||||
* nacteni - cele katalogy sem nepatri.
|
||||
*/
|
||||
sample: z
|
||||
.unknown()
|
||||
.optional()
|
||||
.refine(
|
||||
(value) => value === undefined || JSON.stringify(value).length <= 100_000,
|
||||
'Ukázka těla je moc velká, vejde se 100 kB.',
|
||||
),
|
||||
/** Jak casto se ma sluzba obvolavat. Plati jen u spoustecu, co se ptaji. */
|
||||
intervalSec: z.number().int().min(10).max(86_400).optional(),
|
||||
// Token generuje server. Cokoliv od klienta se ignoruje.
|
||||
@@ -910,7 +930,7 @@ async function validateFlowReferences(
|
||||
const names = new Set<string>();
|
||||
for (const field of flow.trigger.fields) {
|
||||
if (names.has(field.name)) {
|
||||
problems.push(`Parametr „${field.name}" je uvedený dvakrát.`);
|
||||
problems.push(`Parametr "${field.name}" je uvedený dvakrát.`);
|
||||
}
|
||||
names.add(field.name);
|
||||
}
|
||||
@@ -927,13 +947,22 @@ async function validateFlowReferences(
|
||||
problems.push(`Podmínka odkazuje na neexistující parametr (${step.fieldId}).`);
|
||||
} else if (!operatorAllowedForType(step.operator, field.type)) {
|
||||
problems.push(
|
||||
`Operátor "${step.operator}" nelze použít na parametr „${field.name}" typu ${field.type}.`,
|
||||
`Operátor "${step.operator}" nelze použít na parametr "${field.name}" typu ${field.type}.`,
|
||||
);
|
||||
}
|
||||
await walk(step.yes);
|
||||
await walk(step.no);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (step.kind === 'foreach') {
|
||||
if (step.path.trim().length === 0) {
|
||||
problems.push('Smyčka musí mít cestu k seznamu, například data.order.items.');
|
||||
}
|
||||
await walk(step.steps);
|
||||
continue;
|
||||
}
|
||||
|
||||
const action = findOperation(step.serviceId, step.operationId, 'action');
|
||||
if (!action) {
|
||||
problems.push(`Akce ${step.serviceId}/${step.operationId} neexistuje v katalogu.`);
|
||||
@@ -946,7 +975,7 @@ async function validateFlowReferences(
|
||||
for (const key of Object.keys(step.inputs ?? {})) {
|
||||
if (!allowed.has(key)) {
|
||||
problems.push(
|
||||
`Akce ${step.serviceId}/${step.operationId} nemá nastavitelné pole „${key}".`,
|
||||
`Akce ${step.serviceId}/${step.operationId} nemá nastavitelné pole "${key}".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -965,12 +994,12 @@ async function validateFlowReferences(
|
||||
parsed = JSON.parse(raw);
|
||||
} catch (err) {
|
||||
const detail = err instanceof Error ? err.message : 'neplatný JSON';
|
||||
issues.push(`Pole „${input.label}" není platný JSON: ${detail}`);
|
||||
issues.push(`Pole "${input.label}" není platný JSON: ${detail}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (input.kind === 'mapping') {
|
||||
issues.push(...validateRules(parsed, `pole „${input.label}"`));
|
||||
issues.push(...validateRules(parsed, `pole "${input.label}"`));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,13 @@ webhookRouter.post('/:token', (req, res) => {
|
||||
* pod `_body`. Diky tomu se v sablonach pise `{{orderId}}` bez ohledu na
|
||||
* to, jak hluboko to odesilatel schoval, a zaroven se nic neztrati.
|
||||
*/
|
||||
payload: { ...values, _body: body },
|
||||
/*
|
||||
* Krome pojmenovanych hodnot i **cele telo v puvodnim tvaru**, takze
|
||||
* `{{data.order.billingAddress.city}}` funguje, aniz by to nekdo predem
|
||||
* vypsal jako parametr. Deklarovane hodnoty maji prednost: kdyz si nekdo
|
||||
* pojmenuje parametr stejne jako klic v tele, plati jeho.
|
||||
*/
|
||||
payload: { ...body, ...values, _body: body },
|
||||
})
|
||||
.then((item) => {
|
||||
console.info(
|
||||
@@ -283,13 +289,13 @@ function readPayload(
|
||||
if (value === undefined || value === null) {
|
||||
if (field.required) {
|
||||
const where = field.path && field.path !== field.name ? ` (cesta ${field.path})` : '';
|
||||
problems.push(`Chybí povinný parametr „${field.name}"${where}.`);
|
||||
problems.push(`Chybí povinný parametr "${field.name}"${where}.`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!matchesType(value, field.type)) {
|
||||
problems.push(`Parametr „${field.name}" má mít typ ${field.type}.`);
|
||||
problems.push(`Parametr "${field.name}" má mít typ ${field.type}.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user