Tema 3 · ERP objektų išvedimas

Kaip išvesti ERP objektus: Apollo, ERP Reports, JSON transformacija ir failas

Tema 3 pradedama nuo to, kuo baigėme Temoje 2: mokiniai jau žino, kad pirkimo sąskaitų techninis duomenų šaltinis yra purchaseInvoices, o sąskaitos eilutės gaunamos per lines. Šioje temoje tą patį duomenų kelią pakartosime per Apollo Sandbox, tada perkelsime į ERP Report scriptą, išvesime JSON, „išflatinsime“ eilutes, papildysime duomenis antra užklausa ir paruošime failą parsisiuntimui.

1. Temos darbo eiga ir siekiamas rezultatas

Visi žingsniai remiasi tuo pačiu verslo klausimu: kaip iš pirkimo sąskaitų ištraukti antraštę, tiekėją, prekes, kiekius ir sumas, o tada šiuos duomenis paruošti ataskaitai ar failui.

Etapas Ką darome Siekamas rezultatas
1. Apollo Query Schema Reference skiltyje susirandame purchaseInvoices Query ir jo grąžinamus laukus. Mokinys supranta, kokius laukus gali pasirinkti užklausoje ir mato JSON atsakymą.
2. ERP Report scriptas Sukuriame naują ERP Report scriptą ir padarome tokią pačią purchaseInvoices užklausą per rql. Ekrane matomas žalias JSON per output = { data: ... }.
3. Flat JSON Su JavaScript ciklais iš sąskaitos ir jos eilučių padarome vieno lygio masyvą. Kiekviena prekės eilutė tampa viena JSON eilute su dokumento ir prekės laukais.
4. Antra užklausa ir apjungimas Iš pirmos užklausos paimame itemId reikšmes, užklausiame products ir apjungiame rezultatą. Flat eilutės papildomos tikru prekės kodu / pavadinimu iš prekės kortelės.
5. Failas Iš suformatuotų duomenų suformuojame CSV failą ir grąžiname parsisiuntimo nuorodą. Mokinys turi failą, kurį gali parsisiųsti į savo kompiuterį.

2. Priminimas: kaip Apollo įrankyje susirasti Query

Apollo Sandbox pasiekiamas adresu https://erp.test.rivile.cloud/graphql-gen3. Naudokite tą pačią naršyklę, kurioje esate prisijungę prie Rivile ERP TEST aplinkos, kad sesija būtų atpažinta.

  1. Atidarykite Schema Reference.
  2. Paieškoje įveskite purchaseInvoices.
  3. Atverkite Query aprašą ir pasižiūrėkite argumentus: size, filtrai, puslapiavimas ar kiti jūsų versijoje matomi parametrai.
  4. Atverkite grąžinamo tipo laukus ir pasižymėkite: dokumento datą, numerį, būseną, tiekėjo laukus ir eilučių kolekciją.
  5. Jei lauko pavadinimas skiriasi nuo pavyzdžio, naudokite tą, kurį rodo schema. Pavyzdžiai mokymuose yra šablonai, o galutinis autoritetas yra jūsų TEST schema.
Kontrolinis sąrašas Apollo lange
  • Ar radote Query purchaseInvoices?
  • Ar suprantate, kur yra puslapiavimo atsakymas (content, totalElements, page ar analogas)?
  • Ar radote sąskaitos eilučių lauką (lines ar analogą)?
  • Ar radote tiekėjo informaciją: clientId, clientName, įterptą client objektą ar kitus jūsų schemos laukus?

3. Praktinė užduotis Apollo aplinkoje: purchaseInvoices

Užduotis: Apollo aplinkoje susirasti Query purchaseInvoices ir padaryti užklausą, kuri grąžintų: dokumento datą, dokumento numerį, dokumento būseną, tiekėjo informaciją, prekių informaciją, kiekius ir sumas.

query PurchaseInvoicesForTraining($companyId: UUID) {
    purchaseInvoices(companyId: $companyId) {
        content {
            id
            docDate
            opDate
            documentNo
            statusId
            status {
                name
            }
            clientId
            clientName
            client {
                id
                code
                name
            }
            lines {
                id
                itemId
                itemName
                qtyBase
                price
                amount
                amountWithTax
            }
        }
        totalElements
        totalPages
    }
}

Variables:

{
  "companyId": "12e405fc-3487-4360-836d-855ab8500bfa"
}

Jei Apollo rodo, kad jūsų aplinkoje purchaseInvoices argumentai ar laukai vadinasi kitaip, koreguokite pavyzdį pagal schemą. Pvz. būsenos laukas gali būti status, statusId ar susijęs objektas; tiekėjas gali būti clientName / clientId arba įterptas client.

Siekamas rezultatas: mokinys turi veikiantį GraphQL Query ir JSON atsakymą, kuriame aiškiai matoma sąskaitos antraštė ir eilučių masyvas.

4. Kitas etapas: duomenų ištraukimas per ERP Reports

Toliau tą pačią užduotį perkeliame į ERP Report scriptą. Tikslas — susikurti naują reportą, jame padaryti PurchaseInvoice užklausą ir rezultatą išvesti į ekraną JSON formatu.

  1. ERP TEST aplinkoje sukurkite naują ERP Report / Custom Report pagal dėstytojo parodytą vietą.
  2. Report script dalyje pasiruoškite companyId ir rql užklausą.
  3. Rezultatą grąžinkite per output = { data: ... }.
  4. Nenaudokite log.info kaip duomenų išvedimo būdo reporto peržiūroje.
const invoicePage = await rql(`
  SELECT id, docDate, opDate, documentNo, statusId, status.name, clientId, clientName,
         lines.item.code, lines.item.name,
         lines.itemName, lines.qtyBase, lines.price, lines.amount, lines.amountWithTax
  FROM purchaseInvoices
  WITH companyId = ${companyId} 
  size = 10
`);

const purchaseInvoiceData = invoicePage?.content ?? [];

output = {
    initial: initial,
    companyId: `${companyId}`,
    data: purchaseInvoiceData,
};

Siekamas rezultatas: reporto peržiūroje matomas žalias JSON masyvas su pirkimo sąskaitomis ir jų eilutėmis.

5. Užduotis: purchaseInvoices rezultato transformacija į flat JSON

Dabar iš hierarchinės struktūros (sąskaita → eilutės) padarome vieno lygio masyvą. Kiekviena sąskaitos eilutė tampa viena eilute, kurioje pakartojama dokumento informacija ir pridedami prekės laukai.

Flat rezultato laukai: Dokumento Data, Dokumento Numeris, Prekės kodas, Prekės pavadinimas, Kiekis, Kaina, Suma su PVM.

const flatRows = [];

for (const inv of purchaseInvoiceData) {
    for (const line of inv.lines ?? []) {
        flatRows.push({
            dokumentoData: inv.docDate ?? inv.opDate,
            dokumentoNumeris: inv.documentNo,
            busena: inv.statusName ?? inv.statusId,
            tiekejas: inv.clientName,
            prekesId: line.itemId,
            prekesKodas: line.itemCode ?? line.productCode ?? line.itemId,
            prekesPavadinimas: line.itemName,
            kiekis: line.qtyBase,
            kaina: line.price,
            sumaSuPvm: line.amountWithTax,
        });
    }
}

output = {
    data: flatRows,
};

Siekamas rezultatas: mokinys pamato, kaip su JavaScript ciklu galima „flatinti“ duomenis: nebelieka įdėtinio lines masyvo, o kiekviena prekė tampa atskira ataskaitos eilute.

6. Užduotis: antra užklausa ir duomenų apjungimas

Dažna praktinė situacija: pirmoje užklausoje turime tik prekės ID arba nepilną prekės informaciją. Tada iš pirmos užklausos rezultato paimame itemId reikšmes, padarome antrą užklausą į products ir apjungiame duomenis į naują JSON.

const productIds = [
  ...new Set(
    flatRows
      .map((row) => row.prekesId)
      .filter(Boolean)
  ),
];

let products = [];

if (productIds.length > 0) {
  const productFilter = productIds.map((id) => toString(id)).join(", ");

  const productsPage = await rql(`
    SELECT id, code, name
    FROM products
    WITH companyId = ${companyId} size = ${productIds.length}
    WHERE id IN (${productFilter})
  `);

  products = productsPage?.content ?? [];
}

const productsById = new Map(
  products.map((product) => [product.id, product])
);

const enrichedRows = flatRows.map((row) => {
  const product = productsById.get(row.prekesId);

  return {
    dokumentoData: row.dokumentoData,
    dokumentoNumeris: row.dokumentoNumeris,
    busena: row.busena,
    tiekejas: row.tiekejas,
    prekesKodas: product?.code ?? row.prekesKodas,
    prekesPavadinimas: product?.name ?? row.prekesPavadinimas,
    kiekis: row.kiekis,
    kaina: row.kaina,
    sumaSuPvm: row.sumaSuPvm,
  };
});

output = {
  data: enrichedRows,
};

Jei jūsų RQL versijoje IN (...) sintaksė neveikia, tą patį mokymo tikslą galima pasiekti paprasčiau: pasirinkite vieną itemId ir padarykite antrą užklausą tik jam, arba naudokite dėstytojo parodytą filtravimo sintaksę pagal jūsų aplinkos RQL taisykles.

Siekamas rezultatas: mokinys supranta, kaip viena užklausa tampa įėjimu kitai užklausai, o kelių šaltinių rezultatai apjungiami į vieną JSON masyvą.

7. Užduotis: iš suformatuotų duomenų padaryti failą ir parsisiųsti

Paskutinis žingsnis — iš enrichedRows pasidaryti failą. Mokymams pradedame nuo CSV, nes jo struktūra aiški: pirmoje eilutėje antraštės, toliau — suformatuotos duomenų eilutės.

const headers = [
  "Dokumento Data",
  "Dokumento Numeris",
  "Būsena",
  "Tiekėjas",
  "Prekės kodas",
  "Prekės pavadinimas",
  "Kiekis",
  "Kaina",
  "Suma su PVM",
];

const esc = (value) =>
  '"' + String(value ?? "").replace(/"/g, '""') + '"';

const csvLines = [headers.join(";")];

for (const row of enrichedRows) {
  csvLines.push([
    row.dokumentoData,
    row.dokumentoNumeris,
    row.busena,
    row.tiekejas,
    row.prekesKodas,
    row.prekesPavadinimas,
    row.kiekis,
    row.kaina,
    row.sumaSuPvm,
  ].map(esc).join(";"));
}

const csvText = csvLines.join("\n");

const uploadedFile = await fileService.uploadFile(
  csvText,
  "purchase-invoices.csv",
  {
    fileType: "ATTACHMENT",
    isTemporary: true,
    generatePublicLink: true,
  }
);

output = {
  data: {
    rows: enrichedRows,
    file: {
      id: uploadedFile.id,
      fileName: "purchase-invoices.csv",
      publicLink: uploadedFile.publicLink,
      internalLink: uploadedFile.internalLink,
    },
  },
};

Jei konkrečiame Report kontekste fileService.uploadFile dar nėra leidžiamas, laikinai grąžinkite csvText per output.data. Tuomet mokymų tikslas lieka tas pats: pirma suformuojame turinį, vėliau jį prijungiame prie patvirtinto failų API.

Siekamas rezultatas: reporto rezultato JSON turi rows masyvą ir file.publicLink, per kurį failą galima atsisiųsti.

Teorijos santrauka

  • Pradedame nuo Apollo, nes ten matome Query pavadinimą, argumentus ir grąžinamus laukus.
  • ERP Report scriptas tą pačią idėją perkelia į vykdomą JavaScript kodą ir rezultatą rodo per output.data.
  • Flat transformacija paverčia hierarchiją „sąskaita → eilutės“ į vieno lygio ataskaitos eilutes.
  • Antra užklausa leidžia papildyti rezultatą trūkstamais žinyno duomenimis, pvz. tikru prekės kodu.
  • Failo generavimas yra paskutinis duomenų kelio etapas: paruoštas masyvas → CSV / Excel → parsisiuntimo nuoroda.

Savarankiškas darbas

  1. Apollo aplinkoje paleiskite §3 Query ir išsisaugokite vieną JSON atsakymo pavyzdį.
  2. ERP Report scripte išveskite neapdorotą purchaseInvoices rezultatą per output.data.
  3. Padarykite flatRows transformaciją su laukais: Dokumento Data, Dokumento Numeris, Prekės kodas, Prekės pavadinimas, Kiekis, Kaina, Suma su PVM.
  4. Pridėkite antrą užklausą į products ir papildykite rezultatą prekės kodu / pavadinimu iš prekės kortelės.
  5. Suformuokite CSV tekstą ir, jei leidžia aplinka, įkelkite jį per fileService.uploadFile.