Przejdź do głównej zawartości

Technologia zamówienia

Dla: Programista

Technologia zamówienia mówi, jak drukarnia wykona produkt: z jakich elementów się składa, na jakich maszynach i w jakiej kolejności powstaje, na jakim arkuszu i z ilu użytków. W API czytasz ją zakresem orders:read razem z zamówieniem, a pojedynczą operację zmieniasz zakresem orders:write (niżej). Nazwy maszyn, formatów i typów podają słowniki, do których potrzebujesz zakresu reference:read.

Technologia jest częścią zamówienia: order i orders zwracają ją na trzech poziomach.

Poziom Co zawiera
Produkt (Order.products) Nazwa, nakład (quantity, unit), kategoria (categoryId).
Element (Product.elements) Część wykonywana osobno, np. okładka albo środek: nazwa, typ (elementTypeId) i technologia z kalkulacji (spec).
Operacja (Element.operations, w kolejności prac) Maszyna (machineId), ilość i jednostka (quantity, unit), czas na jednostkę, typ operacji (operationTypeId), uszlachetnienie (finishingTypeId), profil kolorów (colorProfileId) i komentarze (comments).
query OrderTechnology($id: ID!) {
order(id: $id) {
id
displayId
products {
id
name
quantity
elements {
id
name
elementTypeId
spec {
printFormatId
printWidthMm
printHeightMm
purchaseFormatId
purchaseToPrintDivisor
upsPerSheet
printScheme
colorsFront
colorsBack
pressMachineId
printSheetsGross
}
operations {
id
machineId
description
quantity
unit
comments {
label
value
}
}
}
}
}
}

Maszynę, na której operacja będzie wykonana, zawsze podaje Operation.machineId. Technologia zmienia się razem z zamówieniem, więc synchronizujesz ją tą samą listą orders z filtrem updatedFrom (Paginacja, filtry i synchronizacja). Elementy i operacje zapisuj u siebie po id.

Element zamówienia utworzonego z kalkulacji ma w polu spec (ElementSpec) kopię technologii, z którą drukarnia go wyceniła:

  • arkusz drukowy: format ze słownika (printFormatId) i jego wymiary w milimetrach (printWidthMm, printHeightMm);
  • arkusz zakupowy: format kupowany u dostawcy (purchaseFormatId, purchaseWidthMm, purchaseHeightMm) i liczba arkuszy drukowych z jednego zakupowego (purchaseToPrintDivisor);
  • użytki: w poprzek i wzdłuż arkusza (upsColumns, upsRows) i razem na arkuszu (upsPerSheet);
  • druk: schemat (PrintScheme: SIMPLEX dla 4+0, SHEETWISE dla F/F, WORK_AND_TURN dla F/O), kolory na obu stronach i Pantone, formy i płyty;
  • arkusze: netto, makulatura i brutto, arkusze zakupowe do kupienia, przeloty przez maszynę i masa papieru;
  • papier: nazwa, rodzaj i gramatura, tak jak zapisała je kalkulacja;
  • maszyna z wyceny (pressMachineId): maszyna, na której kalkulacja zaplanowała druk. Produkcja może wykonać druk na innej, więc maszynę operacji bierz z Operation.machineId.

Wymiary arkusza są podane zawsze, gdy kalkulacja wskazała arkusz: takie, jakie zapisała kalkulacja, a gdy zapisała sam format, wymiary tego formatu ze słownika. Przy rozmiarze niestandardowym printFormatId i purchaseFormatId są null, a wymiary zostają. Kopia nie zawiera cen papieru.

Kopii nikt nie edytuje. Gdy drukarnia wyceni produkt inną kalkulacją, produkt dostaje nowe elementy z nowymi id i nową kopią, a Order.updatedAt się przesuwa. Dwie wartości Prynt wylicza jednak przy odczycie z bieżącego słownika formatów: wymiary arkusza, który kalkulacja podała samym formatem, i purchaseToPrintDivisor, gdy kalkulacja zostawiła go automatyczny. Zmiana formatu w słowniku może je zmienić bez przesunięcia Order.updatedAt, więc odświeżaj je razem ze słownikiem formatów.

spec jest null, gdy element nie ma technologii z kalkulacji: drukarnia wpisała go w Prynt ręcznie, utworzyła go integracja (createOrder, createProduct) albo zamówienie zostało przejęte z poprzedniego systemu drukarni (zobacz niżej). Zawsze obsłuż null.

Na typach zamówienia są tylko identyfikatory. Nazwy i parametry podają słowniki zakresu reference:read:

Identyfikator Słownik
Operation.machineId, ElementSpec.pressMachineId machines; bez filtra isActive lista zawiera też maszyny wycofane.
ElementSpec.printFormatId, ElementSpec.purchaseFormatId referenceData(type: SHEET_FORMAT): wymiary (widthMm, heightMm), rodzaj (kind), format, z którego arkusz jest cięty (parentId), i ile arkuszy z niego powstaje (divisor).
Element.elementTypeId referenceData(type: ELEMENT_TYPE)
Operation.operationTypeId, finishingTypeId, colorProfileId referenceData(type: OPERATION_TYPE), FINISHING_TYPE, COLOR_PROFILE
Product.categoryId referenceData(type: PRODUCT_CATEGORY)

Trzymaj kopię słowników u siebie i odświeżaj ją co jakiś czas. Czytaj je z includeInactive: true: starsze zamówienia mogą wskazywać pozycje, których drukarnia już nie używa.

Te same identyfikatory podasz, tworząc zamówienie (createOrder): typ elementu w OrderProductElementInput.elementTypeId, a typ operacji, uszlachetnienie i profil kolorów w OrderProductOperationInput (operationTypeId, finishingTypeId, colorProfileId). Wszystkie są opcjonalne.

query SheetFormats {
referenceData(type: SHEET_FORMAT, includeInactive: true) {
id
code
name
widthMm
heightMm
kind
parentId
divisor
isActive
}
}

Pola widthMm, heightMm, kind, parentId i divisor mają wartość tylko w słowniku SHEET_FORMAT; w pozostałych słownikach są null.

Zamówienia przejęte z poprzedniego systemu drukarni nie mają technologii z kalkulacji: spec ich elementów jest null. Format i papier takiego elementu są w komentarzach jego operacji (Operation.comments), pod etykietami zapisanymi tak, jak w starym systemie:

Etykieta (label) Co zawiera
Format druku Arkusz drukowy, np. B2, A2+ albo wymiary 469x643.
Format zakupu Arkusz zakupowy, np. B1.
Format arkusza (legacy) Arkusz zakupowy z opisu pracy w starym systemie.
Format produktu (legacy) Format użytku netto, np. A4 (210x297).
Rodzaj papieru Papier, np. KREDA MAT.
Gramatura papieru Gramatura w g/m², np. 115.

Te same etykiety mają też operacje zamówienia utworzonego z kalkulacji przejętej z poprzedniego systemu. spec takiego elementu istnieje, ale bywa niepełny: stary system nie zawsze zapisał dane tak, żeby Prynt je rozpoznał. Dlatego czytaj komentarze przy każdym elemencie, nie tylko gdy spec jest null:

  • format druku bierz najpierw z komentarza Format druku, a gdy go nie ma, ze spec. Komentarz zapisuje format zmieniony po wycenie, więc ma pierwszeństwo;
  • pozostałe wartości bierz ze spec, a gdy ich tam nie ma, z komentarzy.

Zasady odczytu:

  • Przeszukaj komentarze wszystkich operacji elementu, w kolejności operacji. Etykiety Format produktu (legacy) i Format arkusza (legacy) są przy pierwszej operacji, pozostałe przy operacji, przy której zapisano je w starym systemie. Ta sama etykieta może wystąpić przy kilku operacjach: bierz pierwszą wartość.
  • Arkusz zakupowy z opisu pracy ma pierwszeństwo. Gdy element ma i Format arkusza (legacy), i Format zakupu, bierz pierwszy, nawet jeśli oba są przy tej samej operacji.
  • Porównuj etykiety bez wielkości liter i bez białych znaków. Stary system zapisywał tę samą etykietę różnie, np. Format druku, FORMAT DRUKU albo format druku.
  • Wartości to tekst wpisany przez drukarnię, a nie identyfikatory słownika. Bywają zdublowane (KREDA MAT KREDA MAT) albo mają jednostkę (115 g). Dopasowanie do referenceData(type: SHEET_FORMAT) (np. po code albo name) rób u siebie i przygotuj się na wartości bez odpowiednika, np. wymiary w milimetrach.
// Etykieta starego systemu (bez wielkości liter i białych znaków) → [pole, pierwszeństwo].
// Przy tym samym polu wygrywa niższe pierwszeństwo, a przy równym — wcześniejsza operacja.
const LEGACY_LABELS = new Map([
['formatdruku', ['printFormat', 0]],
['formatarkusza(legacy)', ['purchaseFormat', 0]],
['formatzakupu', ['purchaseFormat', 1]],
['formatproduktu(legacy)', ['productFormat', 0]],
['rodzajpapieru', ['paper', 0]],
['gramaturapapieru', ['paperGrammage', 0]],
]);
const labelKey = (label) => label.toLowerCase().replace(/\s+/g, '');
// Format i papier elementu z komentarzy jego operacji, jako tekst ze starego systemu.
// `element` to element z zapytania z `operations { comments { label value } }`.
function legacyTechnology(element) {
const found = new Map(); // pole → { value, priority }
for (const operation of element.operations) {
for (const { label, value } of operation.comments) {
const entry = LEGACY_LABELS.get(labelKey(label));
const text = value.trim();
if (!entry || text === '') continue;
const [field, priority] = entry;
const current = found.get(field);
if (!current || priority < current.priority) found.set(field, { value: text, priority });
}
}
return Object.fromEntries([...found].map(([field, { value }]) => [field, value]));
}
// Przykład: { printFormat: 'B2', purchaseFormat: 'B1', paper: 'KREDA MAT', paperGrammage: '115' }

Mutacja updateOperation zmienia jedną operację zamówienia, np. przenosi ją z karty zlecenia na inną maszynę. Potrzebujesz zakresu orders:write. Zmienisz maszynę (machineId), opis, ilość i jednostkę, czas na jednostkę (timePerUnitSeconds), cenę (price) oraz typ operacji, uszlachetnienie i profil kolorów. Cenę wysyłasz bez dodatkowego zakresu, ale odczytasz ją w odpowiedzi tylko z prices:read.

mutation ChangeOperation($id: ID!, $input: UpdateOperationInput!) {
updateOperation(id: $id, input: $input) {
id
machineId
quantity
unit
timePerUnitSeconds
updatedAt
}
}

Zmienne, które przenoszą operację na inną maszynę:

{
"id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d02",
"input": { "machineId": "4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b" }
}

Zasady zapisu:

  • To łatka. Pole, którego nie wysyłasz, zostaje bez zmian. null czyści tylko opis (description) i identyfikatory słowników (operationTypeId, finishingTypeId, colorProfileId). W pozostałych polach API odrzuca null błędem walidacji, tak jak w innych mutacjach zmiany (Zapisy i idempotencja).
  • Maszynę wybierasz z listy machines z filtrem isActive: true. Wycofanej maszyny ani maszyny bez domyślnego typu zadania klucz nie wybierze (odmowy niżej).
  • Czas z kalkulacji. Operacja z kalkulacji ma szacunek czasu maszyny: przygotowanie i przebieg. Nowy timePerUnitSeconds zastępuje go iloczynem timePerUnitSeconds × quantity. Nowa sama quantity zostawia przygotowanie, a przebieg liczy dla nowej ilości. Po zmianie maszyny, czasu albo ilości Prynt przelicza termin realizacji zamówienia.
  • Ilość nie większa niż wykonana (quantityCompleted) kończy operację: productionStatus zmienia się na COMPLETED.
  • Kolejka maszyny. Operacja przeniesiona na inną maszynę znika z pozycji przypiętych w kolejce starej maszyny. Na nowej maszynie drukarnia może ją przypiąć w Prynt.
  • Cena i ilość po zaokrągleniu. Prynt trzyma cenę z dokładnością do 2 miejsc po przecinku, a ilość do 3. Wartość z większą liczbą miejsc zaokrągla, zanim porówna ją z zapisaną, więc np. cena 3.3000000000000003 (wynik 1.1 * 3 w JavaScripcie) przy zapisanej 3.30 niczego nie zmienia.
  • Zegary i historia tylko przy prawdziwej zmianie. Zmiana przesuwa Operation.updatedAt i Order.updatedAt, a w historii zamówienia w Prynt pojawia się wpis z integracją jako autorem. Zapis tych samych wartości niczego nie zmienia, nawet zegarów. Dlatego ponowienie po zerwanym połączeniu jest bezpieczne także bez nagłówka Idempotency-Key, a synchronizacja w dwie strony się nie zapętla. Z nagłówkiem mutacja działa jak każda inna (Zapisy i idempotencja).

Odmowa przychodzi ze statusem HTTP 200 i błędem w errors, a kod i sub-kod są w extensions. Operacja zostaje bez zmian.

Sub-kod Kiedy Co zrobić
OPERATION_IN_PRODUCTION (CONFLICT) Zmieniasz maszynę operacji, której zadanie produkcyjne czeka na start, jest przydzielone, trwa albo jest wstrzymane. Stan zadania podaje params.taskStatus (PENDING, ASSIGNED, IN_PROGRESS, PAUSED), a jego maszynę params.machineName. Pokaż użytkownikowi, że maszynę zmieni, gdy hala zakończy albo anuluje zadanie w Prynt. Zakończone zadania zostają przy maszynie, na której je wykonano, a kolejne zadanie weźmie nową maszynę. Tę samą regułę ma edycja produktu w Prynt.
MACHINE_INACTIVE (BAD_REQUEST) Maszyna jest wycofana z użycia (Machine.isActive to false). Nazwę podaje params.machineName. Wybierz maszynę z machines(filter: { isActive: true }).
MACHINE_NO_DEFAULT_TASK_TYPE (BAD_REQUEST) Maszyna nie ma domyślnego typu zadania, więc hala nie zacznie na niej operacji. Nazwę podaje params.machineName. Wybierz inną maszynę albo poproś drukarnię, żeby ustawiła typ zadania tej maszyny w Prynt.
bez sub-kodu (VALIDATION) Zamówienie jest zarchiwizowane. Zarchiwizowane zamówienie jest tylko do odczytu. Przywrócić je może drukarnia w Prynt.
  • Nie dodasz ani nie usuniesz operacji ani elementu w istniejącym produkcie. Technologię nowego produktu podajesz w createOrder.
  • Nie przeniesiesz operacji do innego elementu i nie zmienisz kolejności operacji.
  • Nie zakończysz operacji ręcznie: kończy ją hala, kończąc zadanie (endedAt jest tylko do odczytu).
  • Nie zmienisz technologii z kalkulacji (Element.spec).