GraphQL: saleOrder atnaujinimas; idempotency pagal išorinį externalOrderId.
const extId = initial?.webhookPayload?.externalOrderId;
const newStatus = initial?.webhookPayload?.statusCode;
if (!extId || !newStatus) throw new UserError("Trūksta webhook laukų");
const found = await rql(`
SELECT id, documentNo FROM saleOrders
WITH companyId = ${companyId}
WHERE ext.externalOrderId = ${toString(extId)}
`);
const so = found?.content?.[0];
if (!so) {
await log.warn("Webhook: nerastas saleOrder extId=" + extId);
output = { message: "Ignored (not found)", documentsCount: 0 };
} else {
try {
await mutate("updateSaleOrderStatus", { saleOrderId: so.id, statusCode: newStatus });
await log.info("SO " + so.documentNo + " → " + newStatus);
output = { message: "Atnaujinta", documentsCount: 1 };
} catch (error) {
await log.error(error?.message ?? String(error));
throw error;
}
}
GraphQL: saleInvoice mutacijų grupė (tikslus merge vardas — SDL).
const ids = initial?.ids ?? [];
if (ids.length < 2) throw new UserError("Pažymėkite bent dvi sąskaitas");
await log.info("Sujungiama sąskaitų: " + ids.length);
try {
const res = await mutate("mergeSaleInvoices", { saleInvoiceIds: ids, strategy: initial?.strategyCode ?? "SUM_LINES" });
await log.info(JSON.stringify(res));
output = { message: "Sąskaitos sujungtos", documentsCount: 1, mergeResult: res };
} catch (error) {
await log.error("mergeSaleInvoices: " + (error?.message ?? error));
throw error;
}
GraphQL: inventoryStock, inventoryMovement.
const movementId = initial?.inventoryMovementId ?? initial?.id;
if (!movementId) throw new UserError("Nėra movement konteksto");
const lines = await rql(`
SELECT lines.itemId, lines.qtyBase FROM inventoryMovements
WITH companyId = ${companyId} WHERE id = ${toString(movementId)}
`);
await log.info("Eilučių: " + (lines?.content?.length ?? 0));
for (const line of lines?.content ?? []) {
try {
await mutate("reserveInventoryStock", { itemId: line.itemId, qtyBase: line.qtyBase, channelId: initial.channelId });
} catch (error) {
await log.error("Rezervacija item " + line.itemId + ": " + error?.message);
}
}
output = { message: "Rezervacijos apdorotos", executionStatus: "WARNING" };
GraphQL failų tipai: file(s); scenarijuje — fetchData + dataParser (žr. API doc).
[{ "blockType": "FILEUPLOAD", "meta": { "fieldName": "fileName", "accept": ".csv" } }]
const resp = await fetchData(undefined, { url: initial.fileName.publicLink, method: "GET", raw: false });
const rows = await dataParser.csvToJson(resp.body, { valuesSeparator: ";", rowsSeparator: "\n", firstRowHeaders: true });
await log.info("CSV eilučių: " + rows.length);
let ok = 0;
for (const row of rows) {
try {
await mutate("applyInventoryCountingRow", { row }); // iliustratyvus vardas
ok++;
} catch (error) {
await log.error(JSON.stringify({ row, err: error?.message }));
}
}
output = { message: "Inventorizacija", documentsCount: ok };