Klient drukarni chce wiedzieć, co dzieje się z jego zamówieniem: czy już się drukuje, ile zostało i kiedy będzie gotowe. Ten przepis zasila taki widok w panelu klienta albo w sklepie internetowym: pobiera zamówienia, w których coś się zmieniło od poprzedniego razu — także zadanie na hali, które ruszyło, stanęło albo się skończyło — i zapisuje dla każdego status do pokazania klientowi.
Czego potrzebujesz
Dział zatytułowany „Czego potrzebujesz”- Klucz z zakresami
orders:readiproduction:read.orders:readdaje zamówienia,production:read— stan ich produkcji. Bezproduction:readpolaproductioniproductionStatusnie istnieją w schemacie klucza, a zapytanie z nimi API odrzuca błędemAPI_SCOPE_MISSING. - Klienta API z przepisu Obsługa błędów i ponowień. Kod niżej wysyła żądania przez niego.
- Miejsce na znacznik synchronizacji (np. plik albo wiersz w bazie) i tabelę statusów zamówień, jeden wiersz na zamówienie, zastępowany przy każdej zmianie.
Skąd wiadomo, że produkcja się zmieniła
Dział zatytułowany „Skąd wiadomo, że produkcja się zmieniła”Stan produkcji jest częścią zamówienia, więc nie potrzebujesz osobnej listy zadań:
Operation.productionStatusmówi, gdzie stoi operacja:NOT_STARTED(nic jeszcze nie zrobiono; zadanie może być już zaplanowane),IN_PROGRESS(ktoś teraz nad nią pracuje),PAUSED(praca wstrzymana albo część ilości zrobiona, a reszta czeka) alboCOMPLETED.productionzamówienia, produktu i elementu podsumowuje ich operacje: status całości, liczbę operacji (operationCount,completedOperationCount) ipercent— jaką część pracy już zrobiono. Status całości toIN_PROGRESS, gdy coś trwa albo gdy część operacji jest zakończona, a reszta czeka na swoją kolej;PAUSED— gdy któraś operacja stanęła w połowie (wstrzymane zadanie albo część ilości zrobiona), a nic nie trwa.percentważy operacje planowanym czasem maszyn — szacunkiem drukarni (timePerUnitSeconds × quantitykażdej operacji), a nie czasem zmierzonym na hali. Operacja bez szacunku waży tyle, co średnia operacja z szacunkiem, a gdy żadna go nie ma, każda waży tyle samo; 100 pojawia się dopiero po zakończeniu wszystkich operacji.remainingSecondsto planowany czas tego, co zostało, policzony tylko z operacji z szacunkiem.- Każda zmiana statusu zadania — rozpoczęcie, wstrzymanie, wznowienie, zakończenie, anulowanie —
przesuwa
updatedAtzamówienia. Listaordersz filtremupdatedFromzwraca więc każde zamówienie, w którym coś się zmieniło na hali, tak samo jak zamówienie zmienione w biurze. - Każda operacja ma też własny zegar
updatedAt, a listaoperations— filtrupdatedFrom. Przydaje się, gdy potrzebujesz samych operacji, np. do ekranu przy maszynie (sekcja Widok maszyny niżej).
-
Pierwsza synchronizacja pobiera wszystkie zamówienia:
updatedFromjest wtedy pusty. Zamówienia zarchiwizowane i zakończone dawno temu możesz pominąć filtremarchived: falsealbo po statusie. -
Zapisuj status po identyfikatorze zamówienia: wstaw wiersz albo zastąp go w całości. Zamówienie pobrane dwa razy niczego nie psuje.
-
Kolejną porcję zaczynaj od
updatedAtostatniego zamówienia, a po udanym końcu zapisz znacznik: najpóźniejszyupdatedAt. Następna synchronizacja zaczyna od znacznika minus 5 minut. Szczegóły algorytmu: Paginacja, filtry i synchronizacja.
Co pokazać klientowi
Dział zatytułowany „Co pokazać klientowi”Status zamówienia (Order.status) zmienia drukarnia: przyjmuje zamówienie, a potem oznacza je jako
gotowe albo wysłane. Hala bywa szybsza: zamówienie wciąż ma status ACCEPTED, a pierwsze zadanie
już ruszyło. Dlatego kod pokazuje klientowi etap z obu źródeł:
| Etap dla klienta | Kiedy |
|---|---|
| Przyjęte | CREATED albo ACCEPTED, a produkcja nie ruszyła (production.status = NOT_STARTED) |
| W produkcji | IN_PRODUCTION albo ACCEPTED z rozpoczętą produkcją — z procentem percent |
| Gotowe | READY |
| Wysłane | SENT; RECEIVED — odebrane |
| Anulowane | CANCELLED |
production.status = PAUSED w zamówieniu, które jest w produkcji, oznacza, że praca stanęła w
połowie operacji i nic teraz nie trwa: zadanie wstrzymano albo zrobiono część ilości, a reszta czeka
na maszynę albo na kolejną zmianę. Kod zaznacza to w statusie (paused), żeby klient nie zobaczył
zatrzymanego paska postępu bez wyjaśnienia. Przerwa między operacjami (druk skończony, foliowanie
jeszcze nie ruszyło) to zwykły tok produkcji: status pozostaje IN_PROGRESS.
Zadania produkcyjne, gdy potrzebujesz szczegółów
Dział zatytułowany „Zadania produkcyjne, gdy potrzebujesz szczegółów”Lista tasks pokazuje zadania hali — po jednym na każde podjęcie pracy nad operacją — z
terminem, początkiem i końcem pracy (startedAt, completedAt) i maszyną (machineId; nazwy
maszyn da słownik machines z zakresem reference:read). Filtruj ją po operacji, maszynie albo
statusie, a z orders:read także po zamówieniu (orderId); ma też własny updatedFrom. Nazwa
zadania (title) zawiera numer zamówienia, więc — jak operacja zadania — wymaga orders:read. API
nie pokazuje, kto pracował nad zadaniem, ani ile czasu mu to zajęło: dane pracowników drukarni nie
wychodzą przez klucz.
Zadanie wskazuje zamówienie, produkt i element przez swoją operację:
operation { element { name } product { name } order { displayId } }. Działa to także dla zadania
operacji podjętej ponownie — po zakończeniu części ilości hala zaczyna nowe zadanie, a poprzednie
dalej wskazuje tę samą operację.
Funkcja synchronizacji przyjmuje znacznik z poprzedniego razu (null przy pierwszym) i zapis
statusu, a zwraca nowy znacznik. Zapisz go dopiero po udanym końcu: przerwana synchronizacja
powtórzy się wtedy od poprzedniego.
Przykłady pokazują adres zastępczy. Wpisz adres swojej drukarni, żeby go podmienić.
Wymaga curl, jq i skryptu prynt-call.sh z przepisu
Obsługa błędów i ponowień w tym samym katalogu. Każdy status
wypisuje jako jedną linię JSON, a znacznik trzyma w pliku ostatnia-synchronizacja-produkcji.txt.
#!/usr/bin/env bash# production-status.sh — jedna synchronizacja statusów produkcji (curl, jq; prynt-call.sh z przepisu# „Obsługa błędów i ponowień”): zamówienia zmienione od poprzedniej synchronizacji — także te, na# których hala zaczęła, wstrzymała albo skończyła pracę — jako status dla klienta drukarni. Każdy# status wypisuje jako linię JSON, którą zapisujesz u siebie po `orderId`:# ./production-status.sh >>statusy.ndjson# Znacznik trzyma w pliku ostatnia-synchronizacja-produkcji.txt i zapisuje go dopiero na końcu.set -euo pipefail
marker_file=ostatnia-synchronizacja-produkcji.txtsince=$(cat "$marker_file" 2>/dev/null || true)body=$(mktemp) result=$(mktemp)trap 'rm -f "$body" "$result"' EXIT
# Zamówienia zmienione od ostatniego razu — każda zmiana statusu zadania na hali też przesuwa# `Order.updatedAt` — ze stanem produkcji całego zamówienia i jego produktów (production:read).# 20 zamówień na stronę: z produktami i ich postępem mieści się w limicie kosztu zapytania.query='query ChangedOrdersProduction($from: DateTime, $page: Int!) { orders( filter: { updatedFrom: $from } sort: { field: UPDATED_AT, direction: ASC } pagination: { page: $page, pageSize: 20 } ) { items { id displayId status completionDate updatedAt production { status percent remainingSeconds } products { id number name status production { status percent } } } pageInfo { hasNextPage } }}'
# Status zamówienia dla klienta drukarni: etap (z jego statusu, a w produkcji — ze stanu# produkcji; przyjęte, na którym hala już zaczęła pracę, jest „W PRODUKCJI”), procent pracy# zrobionej na maszynach i produkty.client_status='{ "CREATED": "PRZYJĘTE", "ACCEPTED": "PRZYJĘTE", "IN_PRODUCTION": "W PRODUKCJI", "READY": "GOTOWE", "SENT": "WYSŁANE", "RECEIVED": "ODEBRANE", "CANCELLED": "ANULOWANE"} as $stages| (.status == "IN_PRODUCTION" or (.status == "ACCEPTED" and .production.status != "NOT_STARTED")) as $making| { orderId: .id, number: .displayId, stage: (if $making then $stages.IN_PRODUCTION else $stages[.status] end), paused: ($making and .production.status == "PAUSED"), percent: .production.percent, plannedCompletion: .completionDate, products: [.products[] | { number, name, status, percent: .production.percent }] }'
from=null latest=$since page=1if [[ -n $since ]]; then # Zapas na zmiany zapisane tuż przed poprzednią synchronizacją: 5 minut wcześniej. from=$(jq -n --arg since "$since" '$since | capture("^(?<time>[^.]+?)(?<ms>\\.[0-9]+)?Z$") | ((.time + "Z") | fromdateiso8601 - 300 | todateiso8601 | rtrimstr("Z")) + (.ms // ".000") + "Z"')fiwhile :; do jq -n --arg query "$query" --argjson from "$from" --argjson page "$page" \ '{ query: $query, variables: { from: $from, page: $page } }' >"$body" ./prynt-call.sh "$body" >"$result" jq -c ".data.orders.items[] | $client_status" "$result" # Czasy z API mają jeden format (np. 2026-10-05T10:41:02.000Z), więc porównujemy je jako tekst. latest=$(jq -r --arg latest "$latest" '[$latest, .data.orders.items[].updatedAt] | map(select(. != "")) | max // ""' "$result") [[ $(jq -r '.data.orders.pageInfo.hasNextPage' "$result") == true ]] || break last=$(jq -c '.data.orders.items[-1].updatedAt' "$result") # Dalej czytamy od czasu ostatniego zamówienia, nie od kolejnego numeru strony; kolejną stronę # bierzemy tylko wtedy, gdy cała strona ma ten sam czas zmiany. if [[ $last == "$from" ]]; then page=$((page + 1)) else from=$last page=1 fidoneecho "$latest" >"$marker_file"./production-status.sh >>statusy.ndjson # wczytaj linie do panelu klienta: po orderId// production-status.mjs — Node.js 18+, klient API z przepisu „Obsługa błędów i ponowień”import { pryntRequest } from './prynt-client.mjs';
// Zapas na zmiany zapisane tuż przed poprzednią synchronizacją, a widoczne dopiero po niej.const OVERLAP_MS = 5 * 60 * 1000;
// Zamówienia zmienione od ostatniego razu — każda zmiana statusu zadania na hali też przesuwa// `Order.updatedAt` — ze stanem produkcji całego zamówienia i jego produktów (production:read).// 20 zamówień na stronę: z produktami i ich postępem mieści się w limicie kosztu zapytania.const CHANGED_ORDERS = `query ChangedOrdersProduction($from: DateTime, $page: Int!) { orders( filter: { updatedFrom: $from } sort: { field: UPDATED_AT, direction: ASC } pagination: { page: $page, pageSize: 20 } ) { items { id displayId status completionDate updatedAt production { status percent remainingSeconds } products { id number name status production { status percent } } } pageInfo { hasNextPage } }}`;
/** Etap zamówienia dla klienta: z jego statusu, a w produkcji — ze stanu produkcji. */const STAGES = { CREATED: 'PRZYJĘTE', ACCEPTED: 'PRZYJĘTE', IN_PRODUCTION: 'W PRODUKCJI', READY: 'GOTOWE', SENT: 'WYSŁANE', RECEIVED: 'ODEBRANE', CANCELLED: 'ANULOWANE',};
/** * Status zamówienia do pokazania klientowi drukarni, np. w panelu sklepu: etap, procent pracy * zrobionej na maszynach i produkty. Zamówienie przyjęte, na którym hala już zaczęła pracę, jest * „W PRODUKCJI”, choć drukarnia jeszcze nie przestawiła jego statusu. */export function clientStatus(order) { const started = order.production.status !== 'NOT_STARTED'; const inProduction = order.status === 'IN_PRODUCTION' || (order.status === 'ACCEPTED' && started); return { orderId: order.id, number: order.displayId, stage: inProduction ? STAGES.IN_PRODUCTION : STAGES[order.status], paused: inProduction && order.production.status === 'PAUSED', percent: order.production.percent, plannedCompletion: order.completionDate, products: order.products.map((product) => ({ number: product.number, name: product.name, status: product.status, percent: product.production.percent, })), };}
const later = (a, b) => (a === null || Date.parse(b) > Date.parse(a) ? b : a);
/** * Pobiera zamówienia zmienione od `since` (ISO 8601; `null` przy pierwszej synchronizacji: * wszystkie) i przekazuje status każdego (`clientStatus`) do `save`, które zapisuje go po * `orderId` (wstaw albo zastąp). Zwraca znacznik do następnej synchronizacji: najpóźniejszy * `updatedAt`, jaki widziała. Zapisz go dopiero po udanym końcu. */export async function syncProductionStatus(since, save) { let from = since === null ? null : new Date(Date.parse(since) - OVERLAP_MS).toISOString(); let latest = since; for (let page = 1; ; ) { const { orders } = await pryntRequest({ query: CHANGED_ORDERS, variables: { from, page } }); for (const order of orders.items) { await save(clientStatus(order)); latest = later(latest, order.updatedAt); } if (!orders.pageInfo.hasNextPage) return latest; const last = orders.items.at(-1).updatedAt; // Dalej czytamy od czasu ostatniego zamówienia, a nie od kolejnego numeru strony; kolejną // stronę bierzemy tylko wtedy, gdy cała strona ma ten sam czas zmiany. if (last === from) { page += 1; } else { from = last; page = 1; } }}import { readFile, writeFile } from 'node:fs/promises';import { syncProductionStatus } from './production-status.mjs';
const MARKER = 'ostatnia-synchronizacja-produkcji.txt';const since = (await readFile(MARKER, 'utf8').catch(() => '')).trim() || null;const next = await syncProductionStatus( since, async (status) => saveStatus(status), // Twoja funkcja: wstaw albo zastąp wiersz po status.orderId);if (next) await writeFile(MARKER, next);# production_status.py — Python 3.9+, klient API z przepisu „Obsługa błędów i ponowień”from datetime import datetime, timedelta, timezone
from prynt_client import prynt_request
# Zapas na zmiany zapisane tuż przed poprzednią synchronizacją, a widoczne dopiero po niej.OVERLAP = timedelta(minutes=5)
# Zamówienia zmienione od ostatniego razu — każda zmiana statusu zadania na hali też przesuwa# `Order.updatedAt` — ze stanem produkcji całego zamówienia i jego produktów (production:read).# 20 zamówień na stronę: z produktami i ich postępem mieści się w limicie kosztu zapytania.CHANGED_ORDERS = """query ChangedOrdersProduction($from: DateTime, $page: Int!) { orders( filter: { updatedFrom: $from } sort: { field: UPDATED_AT, direction: ASC } pagination: { page: $page, pageSize: 20 } ) { items { id displayId status completionDate updatedAt production { status percent remainingSeconds } products { id number name status production { status percent } } } pageInfo { hasNextPage } }}"""
# Etap zamówienia dla klienta: z jego statusu, a w produkcji — ze stanu produkcji.STAGES = { "CREATED": "PRZYJĘTE", "ACCEPTED": "PRZYJĘTE", "IN_PRODUCTION": "W PRODUKCJI", "READY": "GOTOWE", "SENT": "WYSŁANE", "RECEIVED": "ODEBRANE", "CANCELLED": "ANULOWANE",}
def client_status(order): """Status zamówienia do pokazania klientowi drukarni: etap, procent pracy zrobionej na maszynach i produkty. Zamówienie przyjęte, na którym hala już zaczęła pracę, jest „W PRODUKCJI”, choć drukarnia jeszcze nie przestawiła jego statusu.""" started = order["production"]["status"] != "NOT_STARTED" in_production = order["status"] == "IN_PRODUCTION" or (order["status"] == "ACCEPTED" and started) return { "orderId": order["id"], "number": order["displayId"], "stage": STAGES["IN_PRODUCTION"] if in_production else STAGES[order["status"]], "paused": in_production and order["production"]["status"] == "PAUSED", "percent": order["production"]["percent"], "plannedCompletion": order["completionDate"], "products": [ { "number": product["number"], "name": product["name"], "status": product["status"], "percent": product["production"]["percent"], } for product in order["products"] ], }
def _instant(value): return datetime.fromisoformat(value.replace("Z", "+00:00"))
def _iso(instant): return instant.astimezone(timezone.utc).isoformat(timespec="milliseconds").replace("+00:00", "Z")
def sync_production_status(since, save): """Pobiera zamówienia zmienione od `since` (ISO 8601; None przy pierwszej synchronizacji) i przekazuje status każdego (`client_status`) do `save`, które zapisuje go po `orderId`. Zwraca znacznik do następnej synchronizacji — zapisz go dopiero po udanym końcu.""" start = None if since is None else _iso(_instant(since) - OVERLAP) latest, page = since, 1 while True: orders = prynt_request(CHANGED_ORDERS, {"from": start, "page": page})["orders"] for order in orders["items"]: save(client_status(order)) if latest is None or _instant(order["updatedAt"]) > _instant(latest): latest = order["updatedAt"] if not orders["pageInfo"]["hasNextPage"]: return latest last = orders["items"][-1]["updatedAt"] # Dalej czytamy od czasu ostatniego zamówienia, nie od kolejnego numeru strony; kolejną # stronę bierzemy tylko wtedy, gdy cała strona ma ten sam czas zmiany. if last == start: page += 1 else: start, page = last, 1from pathlib import Path
from production_status import sync_production_status
marker = Path("ostatnia-synchronizacja-produkcji.txt")since = marker.read_text().strip() if marker.exists() else None# save_status: Twoja funkcja zapisu statusu (po orderId)next_marker = sync_production_status(since or None, save_status)if next_marker: marker.write_text(next_marker)<?php// ProductionStatus.php — PHP 8.1+, klient API z przepisu „Obsługa błędów i ponowień”require_once __DIR__ . '/PryntClient.php';
final class ProductionStatus{ // Zapas na zmiany zapisane tuż przed poprzednią synchronizacją, a widoczne dopiero po niej. private const OVERLAP = 'PT5M';
// Zamówienia zmienione od ostatniego razu — każda zmiana statusu zadania na hali też przesuwa // `Order.updatedAt` — ze stanem produkcji całego zamówienia i jego produktów (production:read). // 20 zamówień na stronę: z produktami i ich postępem mieści się w limicie kosztu zapytania. private const CHANGED_ORDERS = <<<'GRAPHQL' query ChangedOrdersProduction($from: DateTime, $page: Int!) { orders( filter: { updatedFrom: $from } sort: { field: UPDATED_AT, direction: ASC } pagination: { page: $page, pageSize: 20 } ) { items { id displayId status completionDate updatedAt production { status percent remainingSeconds } products { id number name status production { status percent } } } pageInfo { hasNextPage } } } GRAPHQL;
// Etap zamówienia dla klienta: z jego statusu, a w produkcji — ze stanu produkcji. private const STAGES = [ 'CREATED' => 'PRZYJĘTE', 'ACCEPTED' => 'PRZYJĘTE', 'IN_PRODUCTION' => 'W PRODUKCJI', 'READY' => 'GOTOWE', 'SENT' => 'WYSŁANE', 'RECEIVED' => 'ODEBRANE', 'CANCELLED' => 'ANULOWANE', ];
public function __construct(private readonly PryntClient $prynt = new PryntClient()) { }
/** * Status zamówienia do pokazania klientowi drukarni: etap, procent pracy zrobionej na * maszynach i produkty. Zamówienie przyjęte, na którym hala już zaczęła pracę, jest * „W PRODUKCJI”, choć drukarnia jeszcze nie przestawiła jego statusu. */ public static function clientStatus(array $order): array { $started = $order['production']['status'] !== 'NOT_STARTED'; $inProduction = $order['status'] === 'IN_PRODUCTION' || ($order['status'] === 'ACCEPTED' && $started); return [ 'orderId' => $order['id'], 'number' => $order['displayId'], 'stage' => $inProduction ? self::STAGES['IN_PRODUCTION'] : self::STAGES[$order['status']], 'paused' => $inProduction && $order['production']['status'] === 'PAUSED', 'percent' => $order['production']['percent'], 'plannedCompletion' => $order['completionDate'], 'products' => array_map(fn (array $product) => [ 'number' => $product['number'], 'name' => $product['name'], 'status' => $product['status'], 'percent' => $product['production']['percent'], ], $order['products']), ]; }
/** * Pobiera zamówienia zmienione od $since (ISO 8601; null przy pierwszej synchronizacji) i * przekazuje status każdego (clientStatus) do $save, które zapisuje go po `orderId`. Zwraca * znacznik do następnej synchronizacji — zapisz go dopiero po udanym końcu. */ public function sync(?string $since, callable $save): ?string { $from = $since === null ? null : (new DateTimeImmutable($since)) ->sub(new DateInterval(self::OVERLAP)) ->setTimezone(new DateTimeZone('UTC')) ->format('Y-m-d\TH:i:s.v\Z'); $latest = $since; $page = 1; while (true) { $orders = $this->prynt->request(self::CHANGED_ORDERS, ['from' => $from, 'page' => $page])['orders']; foreach ($orders['items'] as $order) { $save(self::clientStatus($order)); if ($latest === null || new DateTimeImmutable($order['updatedAt']) > new DateTimeImmutable($latest)) { $latest = $order['updatedAt']; } } if (!$orders['pageInfo']['hasNextPage']) { return $latest; } $last = end($orders['items'])['updatedAt']; // Dalej czytamy od czasu ostatniego zamówienia, nie od kolejnego numeru strony; kolejną // stronę bierzemy tylko wtedy, gdy cała strona ma ten sam czas zmiany. if ($last === $from) { $page++; } else { $from = $last; $page = 1; } } }}<?phprequire __DIR__ . '/ProductionStatus.php';
$markerFile = __DIR__ . '/ostatnia-synchronizacja-produkcji.txt';$since = is_file($markerFile) ? trim(file_get_contents($markerFile)) : '';$next = (new ProductionStatus())->sync( $since === '' ? null : $since, fn (array $status) => saveStatus($status), // Twoja funkcja: wstaw albo zastąp wiersz po orderId);if ($next !== null) { file_put_contents($markerFile, $next);}Widok maszyny: lista operacji
Dział zatytułowany „Widok maszyny: lista operacji”Ekran przy maszynie albo tablica działu pokazuje, co maszyna ma do zrobienia — także operacje, nad
którymi nikt jeszcze nie pracuje, więc nie mają zadania. Takie operacje zwraca lista operations
(zakres orders:read):
- gdzie leży operacja: maszyna (
machineId), element, produkt i zamówienie (elementId,productId,orderId), archiwum zamówienia (orderArchived) i jego status (orderStatus,orderStatusIn); - stan produkcji (
productionStatus,productionStatusIn) — tylko z zakresemproduction:read. Filtr działa dokładnie jak poleproductionStatusoperacji. Bez tego zakresu API odrzuca zapytanie z tym filtrem błędemAPI_SCOPE_MISSING; - kolejność: bez
sortlista idzie po terminie zamówienia (completionDate), od najbliższego, a zamówienia bez terminu są na końcu (ORDER_COMPLETION_DATE). Operacje z tym samym terminem mają stałą kolejność wedługid, więc strony się nie nakładają.
Każda operacja zna swoje miejsce w zamówieniu: elementId, productId i orderId są w niej od
razu, a element, product i order pobierzesz jako obiekty. readyToStart (zakres
production:read) mówi, czy hala może ją już zacząć — szczegóły niżej, w Czy operację można
zacząć.
query MachineView($machineId: ID!, $page: Int!) { operations( filter: { machineId: $machineId orderArchived: false orderStatusIn: [CREATED, ACCEPTED, IN_PRODUCTION] productionStatusIn: [NOT_STARTED, PAUSED, IN_PROGRESS] } sort: { field: ORDER_COMPLETION_DATE, direction: ASC } pagination: { page: $page, pageSize: 40 } ) { totalCount pageInfo { hasNextPage } items { id description quantity quantityCompleted unit sequenceOrder productionStatus updatedAt element { name } product { id name packingDate } order { displayId status completionDate isDeadline clientId } readyToStart } }}Status zamówienia nadaje biuro: przyjmuje zamówienie, a potem oznacza je jako gotowe albo wysłane.
Hala bywa szybsza — zamówienie CREATED może już być w produkcji. Dlatego pracę maszyny wybiera
stan produkcji (productionStatusIn), a orderStatusIn: [CREATED, ACCEPTED, IN_PRODUCTION] tylko
odcina zamówienia gotowe, wysłane i anulowane. Bez CREATED ekran zgubiłby zamówienia, które hala
zaczęła przed biurem.
Lista działa w dwóch trybach:
- Ekran maszyny na żywo. Backend Twojej aplikacji co mniej więcej 15 sekund pobiera dla każdej maszyny jedną albo dwie strony po 40 operacji. Limit integracji to domyślnie 120 żądań na minutę: dziesięć ekranów po dwie strony co 15 sekund to 80 żądań na minutę, więc zostaje zapas na synchronizację. Klucz zostaje w backendzie — przeglądarka ekranu pyta Twój serwer, nie Prynt.
- Lustro operacji. Lista z
updatedFromi sortowaniemUPDATED_AT(same pola proste, bez obiektów) pobiera tylko operacje zmienione od poprzedniej synchronizacji — np. do tablicy działu albo raportów z własnej bazy.Operation.updatedAtprzesuwa zmiana samej operacji i każda zmiana statusu jej zadania. Zmiana zamówienia (termin, status) go nie przesuwa, więc synchronizuj teżorderszupdatedFrom. Usunięta operacja nie zgłasza się wupdatedFrom: znika z ekranu na żywo, a z lustra usunie ją okresowe pełne przejście — bezupdatedFrom, ale zsort: { field: UPDATED_AT, direction: ASC }, bo to sortowanie idzie indeksem. Szczegóły: Paginacja, filtry i synchronizacja.
Czy operację można zacząć
Dział zatytułowany „Czy operację można zacząć”Czytaj readyToStart (zakres production:read). To ta sama reguła, której używa kolejka maszyn w
Prynt: operację można zacząć, gdy wszystkie wcześniejsze operacje jej elementu (o niższej pozycji
sequenceOrder) są skończone — zakończone (endedAt) z całą ilością.
- Pozycje materiałowe — papier, karton albo narzędzie wydawane z magazynu i każda operacja na maszynie magazynu — nie mają zadania i niczego nie wstrzymują: reguła je pomija.
readyToStartmoże byćfalse, choć poprzednia operacja maproductionStatus=COMPLETED: hala zakończyła ją bez całej ilości.previousOperationpokaże wtedy, na co operacja czeka.- Operacja bez pozycji (
sequenceOrder= null, starsze dane) zawsze jest gotowa. readyToStartzmienia się, gdy hala skończy inną operację elementu — bez ruchuupdatedAttej operacji. Przesuwa się wtedyOrder.updatedAt, więc lustro operacji synchronizuj razem zorders(updatedFrom)i po zmianie zamówienia odśwież jego operacje.
Co dalej
Dział zatytułowany „Co dalej”- Szczegóły dla działu obsługi klienta:
Operation.productionStatusiOperation.tasksw zamówieniu (order(id:)) pokażą, która operacja stoi i od kiedy. - Status i pliki w jednym widoku: produkt w statusie
FILES_TO_CHECKalboWAITING_FOR_CLIENT_RESPONSEczeka na pliki albo odpowiedź klienta — przepis Pliki do zamówienia pokazuje, jak je wysłać. - Zamówienie ze sklepu: przepis Zamówienie ze sklepu internetowego zakłada zamówienie, którego status potem pokazujesz.