Praktika · Prekyba ir sandėlis (P07–P10)

P07 · Webhook: e‑komercijos užsakymo būsena

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;
  }
}

P08 · Sujungti pardavimo sąskaitas (rankinis)

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;
}

P09 · Po atsargų judėjimo — rezervacija

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" };

P10 · CSV inventorizacija

GraphQL failų tipai: file(s); scenarijuje — fetchData + dataParser (žr. API doc).

paramsFormSchema

[{ "blockType": "FILEUPLOAD", "meta": { "fieldName": "fileName", "accept": ".csv" } }]

Scenarijus

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 };