Paginacja, filtry i synchronizacja
Dla: Programista
Przykłady na tej stronie używają adresu . Zmień adres
Listy w API Prynt zwykle działają tak samo: zwracają jedną stronę wyników, łączną liczbę rekordów i informację o kolejnych stronach. Argumenty konkretnej listy, w tym dostępne filtry, pola sortowania i domyślny rozmiar strony, podaje jej strona w referencji API.
Lista ze stronami przyjmuje zwykle argument pagination z dwoma polami:
| Pole | Znaczenie |
|---|---|
page |
Numer strony, od 1. |
pageSize |
Liczba rekordów na stronie, od 1 do 100. Bez niego lista zwraca stronę domyślną. |
Wynik takiej listy to obiekt z polami:
| Pole | Znaczenie |
|---|---|
items |
Rekordy bieżącej strony. |
totalCount |
Liczba wszystkich rekordów spełniających filtr. |
pageInfo.currentPage |
Numer bieżącej strony. |
pageInfo.pageSize |
Rozmiar strony. |
pageInfo.totalPages |
Liczba stron. |
pageInfo.hasNextPage |
Czy jest kolejna strona. |
pageInfo.hasPreviousPage |
Czy jest poprzednia strona. |
Rozmiar strony spoza zakresu API odrzuca błędem API_PAGE_SIZE_EXCEEDED i nie wykonuje zapytania.
Duża strona podnosi też szacowany koszt zapytania: przy 100 rekordach na
stronę wybieraj mniej powiązanych obiektów. Zobacz Limity.
Filtry i sortowanie
Dział zatytułowany „Filtry i sortowanie”- Filtry przyjmuje argument
filter. Klucz widzi tylko filtry opisane w referencji. Filtry po cenach i kosztach wymagają zakresuprices:read. - Sortowanie przyjmuje argument
sortz polemfield(wartość enuma z listą pól sortowania) i kierunkiemdirection:ASCalboDESC.
Daty: chwila z offsetem strefy drukarni
Dział zatytułowany „Daty: chwila z offsetem strefy drukarni”Filtry typu DateTime (np. updatedFrom, occurredFrom, productPackingDateFrom) przyjmują
chwilę w ISO 8601. Dni drukarni liczysz w jej strefie, Europe/Warsaw, więc podawaj granice z
offsetem: +01:00 zimą, +02:00 latem.
Data pakowania produktu (Product.packingDate) to w Prynt początek dnia w strefie drukarni:
pakowanie 3 listopada 2026 ma wartość 2026-11-02T23:00:00Z. Granica 2026-11-03T00:00:00Z
(północ UTC) wypada godzinę później i ten produkt pominie. Cały 3 listopada to
productPackingDateFrom: "2026-11-03T00:00:00+01:00" i
productPackingDateTo: "2026-11-03T23:59:59+01:00". Obie granice są włącznie, a druga obejmuje też
datę pakowania zapisaną z godziną.
Przykład: zamówienia z produktem do spakowania dziś i jutro.
query PackingSoon($from: DateTime!, $to: DateTime!) { orders( filter: { productPackingDateFrom: $from, productPackingDateTo: $to, archived: false } sort: { field: COMPLETION_DATE, direction: ASC } pagination: { page: 1, pageSize: 50 } ) { totalCount items { id displayId completionDate products { id name quantity packingDate } } pageInfo { hasNextPage } }}Zmienne from i to policz w strefie drukarni:
# GNU date (Linux; na macOS gdate z pakietu coreutils). Zapytanie w pliku packing-soon.graphql.FROM=$(TZ=Europe/Warsaw date -d 'today 00:00' -Iseconds) # np. 2026-11-02T00:00:00+01:00TO=$(TZ=Europe/Warsaw date -d 'tomorrow 23:59:59' -Iseconds) # np. 2026-11-03T23:59:59+01:00
jq -n --rawfile query packing-soon.graphql --arg from "$FROM" --arg to "$TO" \ '{query: $query, variables: {from: $from, to: $to}}' | curl -sS https://twoja-drukarnia.prynt.pl/api/v1/graphql \ -H "Authorization: Bearer $PRYNT_API_KEY" \ -H 'Content-Type: application/json' \ --data-binary @-import { DateTime } from 'luxon';
const today = DateTime.now().setZone('Europe/Warsaw').startOf('day');const variables = { from: today.toISO(), // np. 2026-11-02T00:00:00.000+01:00 to: today.plus({ days: 1 }).endOf('day').toISO(), // np. 2026-11-03T23:59:59.999+01:00};from datetime import datetime, time, timedeltafrom zoneinfo import ZoneInfo
warsaw = ZoneInfo("Europe/Warsaw")today = datetime.now(warsaw).date()variables = { # np. 2026-11-02T00:00:00+01:00 i 2026-11-03T23:59:59+01:00 "from": datetime.combine(today, time(0, 0), warsaw).isoformat(), "to": datetime.combine(today + timedelta(days=1), time(23, 59, 59), warsaw).isoformat(),}$warsaw = new DateTimeZone('Europe/Warsaw');$today = new DateTimeImmutable('today', $warsaw);$variables = [ 'from' => $today->format(DATE_ATOM), // np. 2026-11-02T00:00:00+01:00 'to' => $today->modify('+1 day')->setTime(23, 59, 59)->format(DATE_ATOM),];Zapytanie PackingSoon z tymi zmiennymi wysyłasz jak każde inne, zobacz
Szybki start. Biblioteka strefy czasowej sama poda właściwy offset także
w dniu zmiany czasu, kiedy początek i koniec doby mają różne offsety.
- Lista zwraca całe zamówienia, ze wszystkimi produktami. Który produkt spakować, rozstrzygasz po
packingDate. - Warunki
product*(productStatus,productIsFsc,productNameContains, daty pakowania) dotyczą jednego produktu naraz. - Zamówienia z produktem bez daty pakowania zwraca
productHasPackingDate: false. Razem z zakresem dat lista jest pusta, bo ten sam produkt nie może mieć daty i jej nie mieć. - Starsze filtry dat zamówień (
createdFrom,completionFrom,paymentDueDateFromi ich pary…To) przyjmują też samą datę, która oznacza północ UTC. Im też podawaj chwilę z offsetem.
Pobieranie wszystkich rekordów
Dział zatytułowany „Pobieranie wszystkich rekordów”Przechodź po stronach, dopóki pageInfo.hasNextPage jest true:
// Pobiera wszystkie strony listy. `query` to Twoje zapytanie ze zmienną $page,// `field` to nazwa pola listy w odpowiedzi, `post` wysyła żądanie i zwraca `data`.async function fetchAll(post, query, field, variables = {}) { const items = []; for (let page = 1; ; page += 1) { const data = await post(query, { ...variables, page }); const list = data[field]; items.push(...list.items); if (!list.pageInfo.hasNextPage) return items; }}Dane mogą się zmieniać w trakcie przechodzenia po stronach: nowy rekord przesuwa pozostałe o jedną pozycję. Dlatego:
- sortuj po polu, które się nie zmienia, jeśli lista na to pozwala;
- zapisuj rekordy po
id(wstaw albo zaktualizuj), więc rekord pobrany dwa razy niczego nie zepsuje; - powtarzaj pełne przejście okresowo, jeśli musisz wykryć rekordy, które zniknęły z filtra albo zostały usunięte.
Synchronizacja przyrostowa
Dział zatytułowany „Synchronizacja przyrostowa”Lista, która ma filtr po czasie zmiany, pozwala pobierać tylko rekordy zmienione od poprzedniej synchronizacji. Wszystkie takie listy działają tak samo:
| Element | Znaczenie |
|---|---|
Pole updatedAt rekordu |
Kiedy rekord albo cokolwiek w nim ostatnio się zmieniło. Co dokładnie się liczy, opisuje pole w referencji. |
Filtr updatedFrom |
Rekordy zmienione w tej chwili lub później (granica włącznie). |
Sortowanie UPDATED_AT, ASC |
Rekordy w kolejności zmian; rekordy z tym samym czasem zmiany w stałej kolejności według id. |
updatedAt przesuwa tylko prawdziwa zmiana: zapis tych samych wartości (ponowienie, odesłanie do
Prynt tego, co pobrałeś) go nie zmienia, więc synchronizacja w obie strony się nie zapętla. Zmiana
zapisana przez Twoją integrację wraca w kolejnej porcji tak samo jak zmiana z Prynt.
Pierwsza synchronizacja pobiera wszystko: bez updatedFrom albo z updatedFrom: null (tak
najprościej, gdy przekazujesz go zmienną). Kolejne:
- zaczynaj od znacznika minus kilka minut, czyli od najpóźniejszego
updatedAtz poprzedniej synchronizacji. Zapas łapie zmiany zapisane tuż przed nią, a widoczne w API dopiero po niej; - kolejną porcję czytaj od
updatedAtostatniego rekordu, a nie od następnego numeru strony. Rekord zmieniony w trakcie przeskakuje na koniec listy, a przy numerach stron przesunąłby pozostałe. Kolejną stronę z tym samymupdatedFrombierz tylko wtedy, gdy cała strona ma ten samupdatedAt; - zapisuj rekordy po
id: rekord pobrany podwójnie nie szkodzi, a pominięty tak; - zapisz nowy znacznik dopiero po udanym końcu, żeby przerwana synchronizacja powtórzyła się od poprzedniego;
- po wydaniu Prynt, które dodaje pole do istniejącego typu, zrób pełne przejście listy: nowe pole
nie przesuwa
updatedAtrekordów, więc synchronizacja przyrostowa nie przyniesie jego wartości dla rekordów zmienionych wcześniej. Nowe pola zapowiada historia zmian API.
Kilka list w jednym żądaniu
Dział zatytułowany „Kilka list w jednym żądaniu”Jedno zapytanie może pobrać kilka list naraz, każdą z jej własnym filtrem updatedFrom. To jedno
żądanie limitu, a koszt rośnie tylko o pola obiektowe: lista z samymi id,
updatedAt i pageInfo kosztuje 3 punkty bez względu na rozmiar strony. Tak działa sonda zmian,
która co kilkanaście sekund sprawdza kilka list i pobiera szczegóły tylko zmienionych rekordów —
zastępuje subskrypcje, których klucz API nie otwiera. Zobacz przepis Zmiany na żywo w ekranach
integracji.
Ruchy magazynowe: od chwili zdarzenia
Dział zatytułowany „Ruchy magazynowe: od chwili zdarzenia”Ilości i czas ruchu magazynowego (stockMovements) po zapisaniu się nie zmieniają — tak samo cena,
dostawca i dokument dostawy przyjęcia (unitPrice, netValue, supplierId, documentNumber,
deliveredAt), ustawiane raz przy księgowaniu — więc lista ruchów nie ma updatedFrom. Ma filtr occurredFrom i sortowanie OCCURRED_AT: czytaj ją tak
samo, tylko od occurredAt, czyli chwili zaksięgowania ruchu. Zasady są te same: znacznik minus
kilka minut, kolejna porcja od occurredAt ostatniego ruchu, zapis po id (ruch pobrany drugi
raz pomijasz). Stany materiałów (papers, paints, foils) synchronizujesz przez updatedFrom:
każdy ruch przesuwa updatedAt materiału.
Dwie rzeczy zmieniają ruch bez nowego occurredAt, więc synchronizacja przyrostowa ich nie widzi:
usunięcie w Prynt zamówienia, zamówienia zakupu albo dostawcy zeruje w ruchu powiązanie
(orderId, purchaseOrderId, supplierId), a usunięcie materiału usuwa jego ruchy. Okresowe pełne przejście (jak dla
usuniętych rekordów wyżej) wyłapie oba. Stan początkowy karty materiału założonej przed wersją
0.34.0 i ręczne zmiany stanu sprzed wersji 0.28.0 nie są ruchami (stan wpisany przy zakładaniu
nowszej karty jest ruchem CORRECTION od 0) — bieżący stan bierz z listy materiałów, nie z sumy
ruchów.
Produkcja: przez zamówienia, operacje albo zadania
Dział zatytułowany „Produkcja: przez zamówienia, operacje albo zadania”Stan produkcji jest częścią zamówienia: Operation.productionStatus, zadania operacji
(Operation.tasks) i podsumowania production zamówienia, produktu i elementu. Każda zmiana
statusu zadania na hali — rozpoczęcie, wstrzymanie, wznowienie, zakończenie, anulowanie — przesuwa
updatedAt zamówienia, więc stan produkcji synchronizujesz tą samą listą orders z
updatedFrom. Lista tasks ma własny updatedFrom, gdy potrzebujesz samych zadań, np. do
tablicy hali; updatedAt zadania przesuwa każda jego zmiana w Prynt, także taka, której API nie
pokazuje.
Każda operacja ma też własny zegar, Operation.updatedAt. Przesuwa go:
- zmiana samej operacji: ilość, czas, maszyna, pozycja w elemencie, wykonana ilość, zakończenie;
- każda zmiana statusu jej zadania: utworzenie, rozpoczęcie, wstrzymanie, wznowienie, zakończenie, anulowanie.
Zmiana zamówienia, produktu albo elementu nie przesuwa updatedAt operacji (przesuwa updatedAt
zamówienia). Nie przesuwa go też zapis technologii bez zmian. Po pobraniu zmienionego zamówienia
porównaj więc updatedAt jego operacji z zapisanymi u siebie i przelicz tylko te, które się
zmieniły. Operacje zapisane przed wersją 0.33.0 mają updatedAt równy chwili tej aktualizacji.
Same operacje, bez zamówień, synchronizujesz listą operations: ma filtr updatedFrom i
sortowanie UPDATED_AT, jak każda lista wyżej. Zmiana zamówienia (termin, status) nie wraca w niej,
więc obok niej synchronizuj orders — także dlatego, że Operation.readyToStart zmienia się po
zakończeniu innej operacji elementu, bez ruchu updatedAt tej operacji. Pełne przejście listy
operations (bez updatedFrom) rób z sort: { field: UPDATED_AT, direction: ASC }: to sortowanie
idzie indeksem, a domyślne — po terminie zamówienia — musi łączyć operacje z zamówieniami. Jak zbudować z niej ekran maszyny, pokazuje przepis Status
produkcji dla klienta.
Usunięta operacja nie ma już updatedAt, więc nic jej nie zgłosi: znika z element { operations }
zmienionego zamówienia i z listy operations. Okresowe pełne przejście (jak dla usuniętych
rekordów wyżej) wyłapie operacje, których brak przeoczyłeś.
Faktury: dokument też jest zmianą
Dział zatytułowany „Faktury: dokument też jest zmianą”productInvoices i purchaseInvoices mają updatedFrom, a updatedAt faktury przesuwa także
dołączenie dokumentu (file, także nowego w miejsce poprzedniego) albo jego usunięcie. Zapis
faktury bez zmian nie przesuwa updatedAt. Faktura zakupu zapisana przed wersją 0.28.0 ma
updatedAt równy chwili jej dodania.