Zamówienia
OficjalnyDarmowyJedna lista zamówień ze wszystkich sklepów i marketplace’ów: statusy, płatności, notatki, przesyłki i dokumenty sprzedaży w jednym miejscu.
- Licencja
- Bezpłatny
- Wersja
- 2.23.20
- Kategoria
- Zamówienia
Zamówienia (core.orders)
Moduł zamówień to centralne miejsce, w którym gromadzą się wszystkie zamówienia z Twoich sklepów i integracji. Tutaj obsługujesz je od momentu wpłynięcia aż po wysyłkę: sprawdzasz dane klienta, pakujesz produkty, notujesz płatności, wystawiasz dokumenty sprzedaży i nadajesz przesyłki.
Moduł wymaga włączonego modułu Produkty (core/products) — produkty z zamówień trafiają do wspólnego katalogu.
W sekcji Dostawa możesz wpisać opcjonalną Firmę, np. „Kwiaciarnia Róża”. Nazwa pojawia się nad ulicą i trafia do danych odbiorcy w integracji przewoźnika. Pole jest też dostępne przy tworzeniu zamówienia ręcznego; można je wyczyścić. Firma odbiorcy jest niezależna od firmy klienta i danych do faktury.
Gdzie znajdziesz moduł
| Strona | Co robisz |
|---|---|
| Zamówienia | Lista wszystkich zamówień z filtrami i wyszukiwarką |
| Szczegóły zamówienia | Pełna obsługa pojedynczego zamówienia |
| Statusy zamówień | Konfiguracja statusów i grup statusów |
Lista zamówień
Lista, dane zamówień, liczniki statusów i podsumowanie zaznaczenia odświeżają się automatycznie co 5 sekund. Odświeżanie zachowuje filtry, wyszukiwanie, sortowanie, bieżącą stronę i zaznaczone zamówienia. Jest wstrzymywane w ukrytej karcie, podczas pobierania listy, przeciągania zamówienia, dostosowywania kolumn lub korzystania z otwartego okna dialogowego.
Łączenie zamówień
Po zaznaczeniu co najmniej dwóch zamówień pojawia się Połącz zamówienia. W oknie wybierz zamówienie główne oraz sposób liczenia kosztu wysyłki: suma kosztów wszystkich źródeł (domyślnie) lub koszt zamówienia głównego.
Powstaje dodatkowe zamówienie z nowym numerem i ID. Źródła pozostają bez zmian. Data utworzenia nowego zamówienia to chwila połączenia; nie jest kopiowana ze źródeł. Ponowienie tego samego żądania zachowuje pierwotną datę połączenia. Klient, adres dostawy, dane faktury, status i metoda płatności pochodzą z głównego zamówienia. Produkty (łącznie z zestawami i pakowaniem), płatności, rabaty, paczki i załączniki są kopiowane. Notatka wewnętrzna zawiera krótkie numery źródeł i w drugim wierszu wskazuje zamówienie główne. Przy koszcie dostawy tylko z głównego zamówienia pomijane są rabaty dostawy pozostałych źródeł.
Dokumenty sprzedaży i przesyłki pozostają w swoich rejestrach z oryginalnymi ID. Nowe zamówienie pokazuje je przez zapisane powiązania, więc można nadal pobierać te same pliki dokumentów i etykiet. Powiązania obejmują także dokumenty dodane później do źródeł. Flagi na liście oraz zbiorcze pobieranie etykiet uwzględniają te relacje.
Łączenie wymaga uprawnień orders.view i orders.create, obejmuje maksymalnie 100 zamówień w jednej walucie i odrzuca wybór agregatu razem z jego źródłem. Sumowanie kosztów dostawy wymaga wspólnej stawki VAT dla niezerowych kosztów; przy różnych stawkach można pozostawić koszt głównego zamówienia. Ponowienie tego samego żądania nie tworzy kolejnego zamówienia. Nie uruchamiamy ponownie automatyzacji utworzenia zamówienia ani ingestu produktów.
Zmiana wymaga wspólnego wdrożenia core/orders, core/shipping i core/invoicing. Najpierw należy udostępnić w core/orders metodę getRelatedOrderIds, z której korzystają rejestry dokumentów i przesyłek. Metody formularza i zapisu to odpowiednio getMergeForm i merge; formularz przekazuje stabilne requestId, używane jako ID nowego zamówienia.
Po lewej stronie widzisz listę statusów wraz z liczbą zamówień w każdym z nich — kliknięcie statusu filtruje listę. Statusy są pogrupowane (np. „W realizacji”, „Zakończone”) zgodnie z konfiguracją.
Filtrowanie
Panel filtrów pozwala zawęzić listę m.in. według:
- dat — data złożenia zamówienia oraz data wejścia w bieżący status,
- danych klienta — numer zamówienia, imię i nazwisko, e-mail, telefon,
- dostawy — przewoźnik, miasto, kod pocztowy, kraj,
- produktów — nazwa, SKU, EAN,
- płatności — rodzaj płatności (lista stałych rodzajów), nazwa płatności z integracji,
waluta, kwota od/do, opłacone / nieopłacone,
- faktury — wystawiona / wymagana / brak,
- treści notatki.
Filtry czyścisz jednym przyciskiem Wyczyść filtry.
Co widać na liście
Każdy wiersz pokazuje źródło zamówienia, numer i klienta, status, listę produktów, przewoźnika i płatność, kwotę oraz daty. W kolumnie płatności pod nazwą przysłaną przez integrację widnieje badge z rodzajem płatności. Kolumna FLAGI pokazuje stan zamówienia jednym rzutem oka. Moduł zamówień liczy cztery flagi własne:
| Ikona | Znaczenie |
|---|---|
| 💰 moneta | opłacone / nieopłacone |
| 💵 gotówka | pobranie (COD) / przedpłata |
| 📦 paczka | spakowane / niespakowane |
| 📷 aparat | zdjęcie z pakowania zrobione / brak zdjęcia |
Kolejne flagi dokładają włączone moduły rozszerzające (np. przesyłka z core/shipping, dokument sprzedaży z core/invoicing) przez hook orders.flags. Szare flagi są nieaktywne; po najechaniu na aktywną flagę dociągają się szczegóły (metoda flags.details).
Zamówienie ręczne
Formularz nowego zamówienia otwierasz z listy. Rodzaj płatności wybierasz w nim ze słownika rodzajów płatności — nazwa płatności w zamówieniu bierze się z wybranego rodzaju.
Masowa zmiana statusu
Zaznacz kilka zamówień na liście i zmień im status jedną operacją — przydatne np. przy przekazywaniu partii zamówień do pakowania czy do wysyłki.
Szczegóły zamówienia
Strona szczegółów łączy w jednym miejscu wszystko, co potrzebne do realizacji zamówienia.
Nagłówek i status
U góry widzisz numer zamówienia, klienta oraz aktualny status. Status zmieniasz przyciskiem — wybierasz nowy status z listy, a zmiana jest od razu zapisywana (i może uruchomić automatyzacje, patrz niżej).
Notatki
Pole Notatka pracownika służy do wewnętrznych informacji dla zespołu. Obok niego znajduje się Notatka klienta — treść wiadomości lub prośby pobrana z zamówienia. Notatka klienta jest tylko do odczytu; automatycznie zapisuje się wyłącznie notatka pracownika.
Produkty — dwa widoki
Widok pakowania — roboczy widok dla magazynu:
- każda pozycja pokazuje, ile sztuk zostało już spakowanych z ilu wymaganych,
- skanowanie kodów EAN automatycznie zwiększa licznik spakowanych sztuk,
- ilość można też poprawić ręcznie lub użyć przycisku Pakuj wszystko,
- zestawy (produkty złożone z kilku elementów) rozwijają się na pojedyncze składniki,
z których każdy pakuje się osobno,
- spakowane pozycje podświetlają się na zielono; gdy wszystkie są gotowe, zamówienie
automatycznie oznacza się jako spakowane wraz z datą spakowania,
- dźwięki pakowania potwierdzają dodanie sztuki i ukończenie zamówienia;
błąd zapisu lub próba dopakowania pełnej pozycji mają osobny sygnał. Cofnięcie ilości i ponowne „Pakuj wszystko” bez zmiany pozostają ciche,
- zdjęcia pakowania — wbudowana obsługa kamery pozwala udokumentować zawartość paczki
(zdjęcie robisz przyciskiem lub klawiszem spacji); zdjęcia zostają przy zamówieniu jako dowód na wypadek reklamacji. W oknie zdjęć wybierz Po otwarciu zdjęć → Przeglądanie zdjęć, aby od razu zobaczyć duży podgląd i miniatury bez uruchamiania kamery. Tryb Robienie zdjęć służy pakującym. Wybór zapamiętuje się w localStorage danej przeglądarki (wspólnie dla korzystających z jej profilu), również po przejściu do innego zamówienia i ponownym otwarciu aplikacji. Gdy przeglądarka blokuje zapis, wybór działa do przeładowania widoku.
Widok księgowy — widok do korekty danych handlowych: nazwy, SKU, EAN, ilości, ceny netto i stawki VAT edytujesz bezpośrednio w tabeli. Możesz też dodać nową pozycję lub usunąć istniejącą. Kwoty zamówienia przeliczają się automatycznie.
Przy zestawie przycisk Edytuj składowe otwiera edytor jego składników. Możesz dodawać i usuwać składowe oraz zmieniać nazwę, SKU, EAN, ilość na jeden zestaw, cenę bazową netto i VAT. Zapisz składowe zapisuje całość wyłącznie w tym zamówieniu — katalog i inne zamówienia pozostają bez zmian. Cena sprzedaży zestawu jest zachowana, a jej podział po rabatach przeliczany według nowych składowych. Nowo wystawiana faktura korzysta z tego podziału; już wystawione dokumenty nie są automatycznie zmieniane. Zestaw musi mieć przynajmniej jedną składową — usunięcie całego zestawu wykonuje się przyciskiem Usuń pozycję.
Decyzja o rozbiciu zestawu i katalogowe ceny jego składników pochodzą z core/products. Orders rozdziela rzeczywistą kwotę sprzedaży po rabacie proporcjonalnie do cen brutto składników, zapisuje korektę groszową na ostatniej sztuce i utrwala wynik w wersjonowanym product.priceAllocation. Moduły księgowe pobierają gotowe linie netto/brutto; gdy którykolwiek składnik nie ma ceny, snapshot ma status incomplete i wskazuje brakujące SKU.
Dane klienta, faktura, dostawa
Sekcje z danymi edytujesz „w miejscu” — klikasz ikonę ołówka, poprawiasz pola, zapisujesz ikoną zaznaczenia. Dotyczy to:
- Klient — imię i nazwisko, firma, e-mail, telefon,
- Źródło i płatność — nazwa metody płatności i jej rodzaj (np. pobranie, przelew,
karta); ikoną krzyżyka anulujesz edycję,
- Faktura — dane do faktury (osoba lub firma, NIP, adres); jeśli klient nie prosił
o fakturę, możesz je dopisać,
- Dostawa — adres wysyłki,
- Przewoźnik — nazwa przewoźnika,
- Punkt dostawy — dane paczkomatu / punktu odbioru.
Moduły zależne mogą dołożyć własne akcje obok pola NIP przez hook views.orderInvoiceEdit. Handler zwraca { key, order, view }, gdzie view jest schematem OVE (np. przyciskiem pobierającym dane kontrahenta z zewnętrznego rejestru).
Płatności
Lista płatności zarejestrowanych do zamówienia: kwota, rodzaj płatności, data i autor. Kolumna „Dodane przez” pokazuje imię i nazwisko pracownika lub nazwę instancji integracji (bez nazwy: „System”). Autor pochodzi z kontekstu platformy i nie zmienia się podczas edycji płatności. Starsze płatności bez autora pokazują „Brak danych”. Płatności dodajesz, edytujesz i usuwasz ręcznie. Zamówienie oznacza się jako opłacone automatycznie, gdy suma płatności pokryje kwotę brutto.
Przesyłki i dokumenty sprzedaży
Prawa kolumna karty zamówienia składa się z sekcji dostarczonych przez inne włączone moduły — moduł zamówień sam nie obsługuje ani przesyłek, ani dokumentów księgowych. Gdy żaden taki moduł nie jest włączony, kolumna zostaje pusta.
Przesyłki (moduł przesyłek, core/shipping) — możesz nadać przesyłkę u przewoźnika dostępnego dla zamówienia albo wgrać własną etykietę wraz z numerem listu przewozowego. Przy zamówieniu widzisz listę przesyłek ze statusem, śledzeniem i pobraniem etykiety.
Dokumenty sprzedaży (moduł fakturowy, core/invoicing) — dostępne jest szybkie wystawianie dokumentów (faktura, paragon, proforma — zależnie od konfiguracji). Wystawione dokumenty wyświetlają się na liście przy zamówieniu, z podglądem pliku w oknie przeglądarki.
Statusy zamówień
Statusy to Twój własny przepływ pracy — decydujesz, przez jakie etapy przechodzi zamówienie. Przy pierwszym uruchomieniu moduł zakłada zestaw domyślny:
Nowe → W przygotowaniu → W realizacji → Wysłane → Dostarczone oraz Anulowane.
Na stronie statusów możesz:
- dodawać, edytować i usuwać statusy,
- nadać każdemu kolor (widoczny na liście zamówień) i pozycję decydującą
o kolejności wyświetlania,
- archiwizować statusy, których już nie używasz — znikają z list wyboru,
ale historyczne zamówienia zachowują poprawne dane,
- grupować statusy w grupy statusów (np. „W toku”, „Zakończone”), co porządkuje
boczny panel na liście zamówień; grupę można też ukryć w interfejsie.
Rodzaj płatności
Integracje przysyłają nazwy płatności w dowolnej postaci — „Płatność elektroniczna”, „Za pobraniem”, „przelew tradycyjny”. Żeby dało się na tym pracować, moduł nadaje każdemu zamówieniu dodatkowo stały rodzaj płatności ze swojego słownika: Pobranie, Gotówka, Przelew bankowy, Karta płatnicza, Płatność online, Płatność odroczona, Inna oraz Nieznana — ten ostatni dostają nowe, jeszcze nierozpoznane nazwy płatności.
Rodzaj płatności widać na liście zamówień jako badge pod nazwą przysłaną przez integrację; można po nim filtrować listę i użyć go jako warunku w automatyzacjach. Przypisywaniem nazw płatności do metod księgowych zajmuje się moduł wFirma na swojej stronie ustawień.
Źródła zamówień
Każde zamówienie zna swoje pochodzenie — moduł integracji (np. sklep PrestaShop) albo Zamówienie ręczne, jeśli utworzył je pracownik w systemie. Źródło widać na liście i w szczegółach zamówienia; identyfikator zamówienia w systemie źródłowym można skopiować jednym kliknięciem, co pomaga przy reklamacjach i uzgodnieniach ze sklepem.
Historia zdarzeń
Najważniejsze zmiany w zamówieniach moduł zapisuje do wspólnej historii firmy (Ustawienia → Historia). Wpis jest niezmienny: niesie gotowy opis, autora zmiany (albo „system”, gdy wykonała ją automatyzacja lub integracja) i relację do zamówienia, którego dotyczy.
| Kod zdarzenia | Kiedy powstaje |
|---|---|
ORDER_CREATED | nowe zamówienie — ręczne, kopia albo z integracji; opis niesie nazwę źródła |
ORDER_STATUS_CHANGED | zmiana statusu, także masowa (wpis dla każdego zamówienia), ze starą i nową nazwą statusu |
ORDER_PAYMENT_ADDED | dopisanie płatności (kwota, waluta, sposób); poprawka istniejącej pozycji nie tworzy wpisu |
ORDER_PAYMENT_METHOD_CHANGED | ręczna zmiana nazwy lub rodzaju płatności zamówienia, ze starą i nową wartością |
ORDER_DELIVERY_CARRIER_CHANGED | zmiana przewoźnika |
ORDER_SHIPPING_ADDRESS_CHANGED | zmiana adresu dostawy albo punktu odbioru |
ORDER_CUSTOMER_CHANGED | zmiana danych klienta, z listą zmienionych pól |
ORDER_NOTE_CHANGED | zmiana albo usunięcie notatki pracownika lub notatki klienta |
ORDER_WHOLE_PACKED | zamówienie spakowane w całości (skan, korekta ilości, „Pakuj wszystko”) |
ORDER_DELETED | usunięcie zamówienia |
Każdy wpis wskazuje relację core/orders → order → identyfikator zamówienia, więc historię pojedynczego zamówienia da się odfiltrować po tej trójce. Opisy zapisujemy w dwóch językach (pl, en) — panel pokazuje wersję zgodną z językiem użytkownika. Zapis wymaga SDK @orbito/api-lib w wersji 3.10.0 i rdzenia z rejestrem historii.
Przycisk Historia w szczegółach zamówienia otwiera modal z jedną osią czasu, czytaną wprost ze wspólnej historii rdzenia (History.list, SDK 3.12.0 i rdzeń z odczytem historii) po relacji do zamówienia. Poza wpisami tego modułu widać w nim więc także zdarzenia innych modułów, które zapisują relację do zamówienia — np. utworzenie przesyłki (core/shipping) czy dokumentu sprzedaży (core/invoicing). Każdy wpis pokazuje opis, datę, autora (albo „System”) i źródło (nazwę instalacji modułu). Modal ładuje najnowsze 200 wpisów; gdy jest ich więcej, informuje o tym, a pełną historię da się przejrzeć w Ustawienia → Historia.
Automatyzacje
Moduł udostępnia gotowe elementy do budowania automatyzacji. Wszystkie dotyczą wyłącznie zamówień — statusy przesyłek czy dokumentów sprzedaży opisują akcje modułów, które nimi zarządzają.
Wyzwalacze — uruchamiają scenariusz:
- Nowe zamówienie, Opłacone zamówienie, Zamówienie spakowane,
- Status zamówienia zmieniony (wybierasz statusy przy konfiguracji),
- Zamówienie wymaga faktury, Zmiana dostawy, Dodanie płatności do zamówienia.
Akcje — wykonują operacje dotyczące zamówienia:
- Zmień status zamówienia (v2) i Przywróć poprzedni status zamówienia,
- Dodaj płatność do zamówienia (pozostała kwota, pełna wartość albo stała kwota),
- Dodaj prezent do zamówienia,
- Dodaj powiadomienie — zapisuje wspólny alert firmy z linkiem do zamówienia,
- Zrób zdjęcie pakowania — zleca jedno zdjęcie w widoku pakowania.
Akcja add_notification wymaga ORDER_ID oraz parametru message — treści od 1 do 2000 znaków (zwykły tekst, bez szablonów). Numer zamówienia i link do karty są dodawane automatycznie. Wpis z kodem AUTOMATION_NOTIFICATION trafia do dzwonka oraz Ustawienia → Problemy przez Problems.report.
Ta sama treść dla tego samego zamówienia i automatyzacji ma stały problemKey. Ponowienie lub kolejne uruchomienie odświeża istniejący wpis i przywraca status oczekujący, zamiast tworzyć duplikat; inna treść, automatyzacja lub zamówienie tworzy osobny wpis. Jest to alert wspólny dla firmy, bez odbiorcy osobistego. Błąd zapisu (także null z SDK) zatrzymuje bieg z błędem. Akcja nie zmienia zamówienia i po poprawnym zapisie przechodzi do kolejnego kroku.
Warunki — rozgałęziają scenariusz: stan spakowania, zapisane zdjęcie pakowania, status zamówienia, opłacenie, metoda płatności, rodzaj płatności ze słownika, dostawa (przewoźnik, punkt/drzwi, pobranie, kraj), źródło zamówienia, produkt w zamówieniu.
Zapisano zdjęcie pakowania (check_packing_photo) wybiera „Tak”, gdy w załącznikach zamówienia jest zdjęcie pakowania; samo zlecenie wykonania zdjęcia nie wystarcza.
Oczekiwania — wstrzymują scenariusz i wracają do niego co 30 sekund: Czekaj aż zamówienie zostanie spakowane oraz Czekaj aż zamówienie zostanie opłacone.
Typowe zastosowania: po opłaceniu zamówienia automatycznie wystaw fakturę, po spakowaniu przenieś zamówienie do „Wysłane”, po wejściu w wybrany status wyślij powiadomienie.
Klucze zdarzeń i zmienne szablonów wiadomości (2.16.0)
Od SDK 4.0 klucze zdarzeń innych modułów mają prefiks modułu. Akcja Czekaj aż zamówienie zostanie opłacone (dokument) wymaga ORDER_ID oraz core/invoicing:INVOICE_ID (wyzwalacz „Nowy dokument sprzedaży” z core/invoicing). Własne klucze (ORDER_ID, ORDER_STATUS…) pozostają krótkie. Akcje czytają zamówienie wyłącznie z ORDER_ID.
Moduł udostępnia szablonom wiadomości dwie grupy zmiennych. Obie wymagają ORDER_ID w zdarzeniu automatyzacji:
core/orders:customer—email,phone,fullName(dane klienta zamówienia),core/orders:order—number,total-to-pay(brutto minus wpłaty, nie mniej niż 0),
currency, date (data złożenia, DD.MM.YYYY HH:mm, w strefie czasowej firmy) oraz lista items z polami name, quantity, price (cena brutto za sztukę).
Kwoty mają postać tekstu z dwoma miejscami po przecinku, np. 149.97. Przykład pętli po pozycjach: {{#core/orders:order.items}}{{ name }} x {{ quantity }}{{/core/orders:order.items}}.
Uprawnienia
Dostęp do modułu regulują uprawnienia nadawane rolom użytkowników:
| Uprawnienie | Zakres |
|---|---|
| Podgląd zamówień | przeglądanie listy i szczegółów zamówień |
| Edycja zamówień | zmiana danych, pakowanie, płatności, zmiana statusu |
| Tworzenie zamówień | ręczne zakładanie nowych zamówień |
| Podgląd statusów | wgląd w listę statusów i grup |
| Zarządzanie statusami | dodawanie, edycja i archiwizacja statusów oraz grup |
| Podgląd mapowania płatności | wgląd w tabelę mapowania płatności (payment_mapping.view) |
| Zarządzanie mapowaniem płatności | przypisywanie rodzajów płatności do nazw z integracji (payment_mapping.edit) |
Pracownik magazynu potrzebuje zwykle podglądu i edycji zamówień; konfigurację statusów warto zostawić osobom zarządzającym procesem.
Rozszerzanie widoków zamówień (dla twórców modułów)
Prawa kolumna strony /details/:orderId to blok type: dynamic wołający metodę getOrderDetailsBlock. Metoda emituje hook views.orderDetails, zbiera fragmenty widoku od modułów rozszerzających i skleja je w jeden widok. Tym samym wzorcem działa kolumna flag na liście zamówień — metoda search emituje hook orders.flags. Zależność jest jednostronna — core.orders nie zna modułów rozszerzających i działa poprawnie, gdy żadnego z nich nie ma.
Hooks — emitowane przez moduł
views.orderDetails
Kontrakt hooka jest własnością core.orders. Obecni konsumenci: core.shipments (fragment „Przesyłki”) i core.invoicing (fragment „Dokumenty sprzedaży”).
// argument hooka
{ orderId: 'string', order: object } // order — surowy dokument zamówienia (bez wzbogacania)
// odpowiedź handlera: jeden fragment, tablica fragmentów albo null/undefined (brak fragmentu)
{
key: 'string', // stabilny identyfikator fragmentu (zwykle kod modułu)
title: 'string', // opcjonalny — diagnostyka i logi; nagłówek ma sam fragment (karta)
order: 'number', // kolejność sklejania rosnąco; brak → 100
view: { type: ... } // czysty root widget OVE
}
Zasady sklejania (src/lib/order-details-block.js):
null/undefinedw odpowiedziach to poprawny brak fragmentu — bez ostrzeżenia,- fragment bez
key(niepusty string) albo bezview.type(string) jest odrzucany
z Log.warn('Orders: odrzucono fragment widoku zamówienia', { key, reason }),
- duplikat
key→ wygrywa pierwszy fragment, kolejny jest odrzucany (ostrzeżenie jak wyżej), - sortowanie rosnąco po
order(domyślnie100), remis → kolejność odpowiedzi handlerów, - fragmenty trafiają jeden pod drugim do widoku
flex(id: orderDetailsBlock,
direction: column, gap: 3); brak fragmentów → view: null, a blok pokazuje pusty komunikat.
orders.flags
Kontrakt hooka jest własnością core.orders. Hook dokłada flagi do kolumny FLAGI na liście zamówień. Emitowany jest raz na stronę wyników metody search (≤ 100 zamówień) oraz raz dla jednego zamówienia przy pobieraniu szczegółów flagi (flags.details). Obecni konsumenci: core.shipping (flaga shipment) i core.invoicing (flaga invoice).
// argument hooka
{
orderIds: ['<id>', ...],
// lekka projekcja, żeby handler nie musiał wołać z powrotem core/orders
// (wywołanie zwrotne w trakcie hooka może zakleszczyć kontenery)
orders: [{ _id: '<id>', invoice: { isNeeded: bool }, isPaid: bool, isPacked: bool, delivery: { isCod: bool } }],
}
// odpowiedź handlera: jeden opis flagi, tablica opisów albo null/undefined (brak flagi)
{
key: 'shipment', // stabilny, unikalny identyfikator (string, wymagany)
label: 'Przesyłka', // etykieta dla operatora (string, wymagany)
icon: 'truck-delivery', // ikona Tabler bez prefiksu `ti-` (string, wymagany)
order: 30, // kolejność w wierszu, rosnąco; brak → 100
inactive: { title: 'Brak przesyłki', summary: 'Nie utworzono przesyłki dla zamówienia' }, // opcjonalne
states: {
'<orderId>': {
active: true,
tone: 'success', // success | info | warning | muted
title: 'Przesyłka utworzona',
summary: 'Kurier: DPD\nNumer przesyłki: 0001234567',
// Opcjonalne, neutralne elementy prezentacyjne listy. Emitent podaje
// referencję pliku w swoim buckecie; core.orders nie zna jego modułu.
listItems: [{
label: 'DPD Kurier',
title: 'Śledź przesyłkę 0001234567',
url: 'https://tracking.example/0001234567',
image: { instanceId: '<carrier-instance-id>', name: 'logo.jpg', alt: 'DPD' },
}],
},
},
}
Zasady sklejania (src/lib/order-flags.js):
null/undefinedw odpowiedziach to poprawny brak flagi — bez ostrzeżenia,- opis bez
key,labelalboicon(niepuste stringi) jest odrzucany
z Log.warn('Orders: odrzucono flagę zamówienia', { key, reason }),
- duplikat
key→ wygrywa pierwszy opis, kolejny jest odrzucany (ostrzeżenie jak wyżej), - klucze flag natywnych (
payment,cod,packed,photo) są zarezerwowane — opis
zewnętrzny o takim kluczu jest odrzucany,
- brak wpisu w
statesdla zamówienia → flaga nieaktywna z opisem zinactive
(albo samą etykietą), tone: muted,
tonespoza listy →muted,listItemsjest opcjonalne (maks. 10 elementów);urlprzyjmuje wyłącznie HTTP(S),
a image jest referencją pliku { instanceId, name, alt }, nigdy bajtami/base64,
- sortowanie rosnąco po
order(domyślnie100), remis → najpierw flagi natywne
(payment 10, cod 20, packed 40, photo 50), dalej kolejność odpowiedzi handlerów,
- szczegóły są eager —
titleisummaryprzychodzą w tej samej odpowiedzi hooka,
więc popover flagi nie wykonuje drugiego kontraktu,
- awaria hooka (wyjątek, timeout) nie zabiera listy zamówień: zostają same flagi natywne,
a powód trafia do Log.warn.
Wiersz metody search dostaje flags: [{ key, label, icon, active, tone, title, summary, imageDataUrl }] posortowane po order. imageDataUrl jest puste na liście — podgląd zdjęcia z pakowania dowozi dopiero flags.details.
Ogólny opis zaczepów widokowych: orbito-doc/docs/widoki/rozszerzanie-widokow.md (publikowane na https://orbito.pl/docs).
Zmienna globalna ordersReturnTarget
Kontrakt jest własnością core.orders. Moduł, który przyprowadza operatora na kartę zamówienia (navigate na core/orders → details/<id>), zostawia w zmiennej globalnej OVE ordersReturnTarget opis miejsca powrotu. Karta zamówienia pokazuje wtedy przycisk „Wróć do …” prowadzący z powrotem do tego modułu — bez znajomości jego kodu.
# na stronie modułu linkującego, tuż przed nawigacją na kartę zamówienia
- action: setGlobalVar
key: ordersReturnTarget
value:
module: core/shipping # kod modułu, do którego wraca przycisk
page: shipments # strona w tym module
label: przesyłek # dopełniacz do tytułu „Wróć do przesyłek”
- action: navigate
module: core/orders
page: details/{{ ... }}
Zasady:
- wartość to obiekt
{ module, page, label }albonull(brak celu powrotu); - cel ustawia moduł linkujący, tuż przed
navigatena kartę zamówienia; - cel kasuje (
value: null) każda strona, która jest celem powrotu — przy wejściu na nią
(onLoad), żeby przycisk nie został po poprzedniej wizycie; robi to także sama karta zamówienia zaraz po powrocie;
- brak
modulew zmiennej → karta zamówienia pokazuje zwykłe „Wróć do zamówień”; - lista zamówień ustawia przy kliknięciu wiersza własny cel
{ module: core/orders, page: orders, label: zamówień }.
Metoda bloku
| Metoda | Parametry | Uprawnienie | Wynik |
|---|---|---|---|
getOrderDetailsBlock | orderId (string, wymagany) | orders.view | { view, fragments } — view to sklejony root flex (albo null, gdy nie ma fragmentów), fragments to [{ key, title, order }] bez schematów, do diagnostyki. Nieznane zamówienie → błąd Order not found (hook nie jest wtedy emitowany). |
flags.details | orderId (string, wymagany), flag (klucz flagi), requestId (opcjonalny) | orders.view | { requestId, orderId, flag, tone, titleBase64, summaryBase64, imageDataUrl } — szczegóły jednej flagi dla popovera listy. Klucz natywny liczy się lokalnie, każdy inny przechodzi przez hook orders.flags. Brak opisu flagi → tone: muted i podsumowanie „Brak danych”. |
Kontrakt workflow pakowania
Metody workflow.* są wąskim kontraktem modułowym dostępnym przez hooki orders.workflow.* dla uwierzytelnionych modułów dowolnego autora. Nie ma listy dozwolonych kodów modułów-klientów. Każde wywołanie wymaga tożsamości nadanej przez Core w kontekście hooka (caller.moduleCode i poprawne caller.instanceId). Protokół orbito.contract/1 najpierw odkrywa dostawcę przez hook z sufiksem .providers, a następnie kieruje żądanie do konkretnej instancji. Pola caller, permissions, userId i system w payloadzie są odrzucane.
Adapter hooka zachowuje jawne ograniczenia uprawnień dostarczone przez platformę. Workflow sprawdza wymagane uprawnienie i przekazuje do operacji lokalnej minimalny kontekst: orders.view dla odczytu, orders.edit dla operacji pakowania lub uprawnienie podglądu statusów dla ich listy. Identyfikator pracownika pochodzi wyłącznie z kontekstu dostarczonego przez Core. Dotychczasowe metody RPC pozostają dostępne dla istniejących klientów; nowe integracje korzystają z hooków.
| Metoda | Parametry | Wynik |
|---|---|---|
workflow.getOrder | orderId | wynik getById oraz packingFingerprint |
workflow.searchOrders | query?, statusId?, statusIds?, page?, perPage?, sortBy?, sortDirection? | wynik search; każdy rekord zawiera packingFingerprint |
workflow.listStatuses | brak | aktywne statusy jako [{ id, name }], posortowane według pozycji |
workflow.adjust | orderId, productIndex, packIndex?, delta, expectedFingerprint | wynik packing.adjust oraz nowy packingFingerprint |
workflow.scan | orderId, ean, expectedFingerprint | wynik packing.scan oraz nowy packingFingerprint |
workflow.addPhoto | orderId, image, expectedFingerprint | wynik photos.add (w tym fid) oraz packingFingerprint |
workflow.updateStaffNote | orderId, staffNote | zapis notatki wewnętrznej; tekst może być pusty i ma maksymalnie 10 000 znaków |
workflow.updateDelivery | orderId oraz pola adresu dostawy i punktu dostawy | aktualizacja wyłącznie dozwolonych pól dostawy; każde pole ma maksymalnie 500 znaków |
packingFingerprint jest nieprzezroczystym tokenem wersji stanu pakowania. Konsument przekazuje ostatnio otrzymany token jako expectedFingerprint; brak lub różnica daje odpowiednio EXPECTED_PACKING_FINGERPRINT_REQUIRED albo ORDER_PACKING_STALE. workflow.addPhoto ponownie ładuje zamówienie i zwraca PACKING_INCOMPLETE, jeżeli brakuje fizycznych pozycji albo którakolwiek z nich nie ma dodatniej, skończonej ilości i pełnego stanu pakowania. Po zapisie zdjęcia metoda jeszcze raz porównuje fingerprint. Jeżeli pakowanie zmieniło się podczas uploadu, zwraca ORDER_PACKING_STALE; historyczny załącznik może pozostać przy zamówieniu, ale caller nie dostaje potwierdzenia, że zdjęcie opisuje bieżący stan.
Kontrola fingerprintu i zapis są dwiema operacjami, ponieważ starsze publiczne metody pakowania nie obsługują atomowego warunku wersji. Chroni to przed wysłaniem już nieaktualnego formularza, ale starszy interfejs może zmienić zamówienie pomiędzy kontrolą a zapisem. Pełna ochrona przed takim wyścigiem wymagałaby wspólnego CAS albo blokady respektowanej przez wszystkie ścieżki zapisu.
Metody wyszukiwania zamówień
Obie metody dzielą ten sam zestaw filtrów (src/lib/order-query.js), więc moduł wołający uczy się ich raz.
| Metoda | Parametry | Uprawnienie | Wynik |
|---|---|---|---|
search | filtry listy zamówień (query, statusId/statusIds, source, zakresy dat, dane klienta, produkty, płatność), _id (jedno zamówienie), _ids (lista identyfikatorów), page, perPage (max 100), sortBy, sortDirection | orders.view | { data, pagination } — zamówienia wzbogacone o status i źródło |
searchIds | te same filtry co search + limit (domyślnie 500, max 1000) | orders.view | { ids, total, limit } — same identyfikatory, sort createdAt malejąco |
_ids—{ $in: [...] }po identyfikatorach zamówień; wygrywa z_id, gdy podane są oba.
Lista bez poprawnego identyfikatora (albo pusta) daje zero wyników, a nie pominięcie filtra — tak samo jak błędne _id. Przydatne do dociągania kontekstu zamówień partiami (pamiętaj o perPage ≤ 100).
searchIds— lekkie przełożenie frazy użytkownika na listę zamówień (np. filtr frazy
na liście przesyłek). total liczony jest bez limitu, więc total > ids.length oznacza, że wołający trafił w limit i powinien zawęzić filtry.
Profil źródła zamówień
Moduł źródłowy (np. integracja sklepu) rejestruje wygląd swojego źródła metodą source.register. Profil jest przypisany do instancji wołającego modułu (ctx.caller), więc parametry nie niosą kodu modułu ani instancji.
| Parametr | Opis |
|---|---|
name | nazwa źródła na liście i karcie zamówienia (domyślnie nazwa instancji) |
iconDataUrl | ikona jako data:image/...;base64 (png, jpeg, webp, gif, ico; max 45 KB) |
iconSourceUrl | adres, z którego pobrano ikonę (http/https) |
externalIdLabel | etykieta identyfikatora zamówienia w źródle, np. 'ID Allegro' albo mapa językowa { pl: 'ID Allegro', en: 'Allegro ID' } (klucze pl, en, pl-PL…; każda wartość 1–40 znaków). Bez niej karta pokazuje „ID źródła” |
Zależności modułowe
Moduł zależy wyłącznie od core/products (module.json). Ani strony OVE, ani backend modułu nie wołają metod innych modułów — pilnują tego testy test/page-module-refs.test.js (strony) i test/module-refs.test.js (src/, methods/, index.js); w obu dozwolone są tylko core/orders i core/products. Integracje trafiają do modułu wyłącznie przez hooki: karta zamówienia przez views.orderDetails i blok type: dynamic na stronie /details/:orderId, flagi listy przez orders.flags. Nawigacja między stronami modułu to action: navigate z module: core/orders i stroną details/<id> albo orders. Jedyny wyjątek to przycisk powrotu na karcie zamówienia: bierze module i page z szablonu {{ $global.ordersReturnTarget.* }}, więc kod obcego modułu nie występuje w schemacie.
Personalizacja widoku listy zamówień
Ikona kolumn w pasku listy otwiera tryb edycji. Kolumny można ukrywać i przywracać checkboxami oraz przesuwać za uchwyt w panelu, przeciągając nagłówek tabeli lub przyciskami strzałek. Checkbox zaznaczania zamówień pozostaje na początku, a co najmniej jedna kolumna danych musi pozostać widoczna. Kolumna Notatki pokazuje razem notatkę klienta i notatkę wewnętrzną; pełna treść jest dostępna po najechaniu.
Ponowne kliknięcie tej samej ikony (w edycji: dyskietka) zapisuje widok. Anuluj lub Escape w panelu odrzuca zmiany. Domyślny układ przywraca kolumny w roboczym podglądzie — również wymaga zapisu ikoną. Opuszczenie strony bez zapisu odrzuca roboczy układ. Niedostępny localStorage pozostawia panel otwarty z komunikatem błędu zapisu.
Ustawienia przechowywane są wyłącznie lokalnie, osobno dla użytkownika, pod kluczem orbito.ui.v1.core-orders.orders:columns:<encodeURIComponent(userId)>. ID pochodzi z kontekstu uwierzytelnionego wywołania listViewContext (uprawnienie orders.view). Bez tego ID nie odczytujemy ani nie zapisujemy wspólnych ustawień. Układ używa stabilnych identyfikatorów kolumn, usuwa nieznane i zduplikowane wpisy oraz automatycznie uwzględnia nowe kolumny. Zmiana kolejności przez CSS grid zachowuje elementy OVE i indeksy natywnego sortowania przy odświeżaniu danych.
Źródłem kontrolera jest src/list-layout.js. Po jego zmianie należy uruchomić node scripts/sync-list-layout.js, aby zaktualizować skrypt osadzony w pages/list-v2.yaml.
Daty — strefa czasowa firmy
Daty zamówień, płatności, flag, historii i listy produktów do zebrania są prezentowane w strefie czasowej firmy (Core.getCompany().timezone, domyślnie Europe/Warsaw; helpery Time z SDK). Ręczne daty płatności bez offsetu oraz granice filtrów dziennych są interpretowane w tej strefie. Strefa jest pobierana przy każdym wywołaniu metody, więc zmiana w ustawieniach firmy działa od razu. Edycja kwoty bez zmiany daty zachowuje dokładny znacznik czasu. Daty z jawnym offsetem zachowują swój moment w UTC. Wyjątek: formularz płatności na karcie zamówienia nadal podpowiada bieżący czas w Europe/Warsaw.
Zmiana uwzględnia czas letni i zimowy. Nie wykonuje migracji istniejących danych.
Uzupełnianie danych źródłowych i nazwy płatności (2.14.18)
Zachowano autouzupełnianie brakujących danych odbiorcy przez source.completeData z wersji 2.14.17 i bezpieczne uzupełnianie NIP-u przez source.updateLabels. Weryfikacja kwot, VAT, ręcznych korekt oraz zmian danych pozostaje niezależna.
Wycofano wybór nazwy płatności z mapowania wFirma i związany z nim hook. Lista oraz szczegóły pokazują zapisane paymentMethod. Własne nazwy dla marketplace ustawia się w konfiguracji konkretnej instancji Mirakl 0.1.18, w sekcji „Nazwy płatności”. Usunięte ustawienie wyświetlania nie wpływa już na widok zamówień.
2.18.1 — źródłowe produkty marketplace
Kontrakt importu przyjmuje externalImport.productSource = marketplace: nazwa, zdjęcie i podatki są faktami źródłowej transakcji; katalog uzupełnia dane i jest właścicielem BOM-u, bez zapisu do niego podczas importu. Dotychczasowy tryb catalog zachowuje swoją semantykę.
Hook orders.source.repairImportedProducts naprawia niezatwierdzone pozycje techniczne starego importu. Wymaga uwierzytelnionej instancji będącej właścicielem zamówienia, zgodnych poprzednich danych i identycznych sum źródłowych. Blokada i warunkowy zapis chronią równoległe zmiany; zatwierdzone dane, historia i ręczne korekty nie są nadpisywane.
Wersja 2.18.3 dodaje marketplaceProductImages i tryb imagesOnly kontraktu orders.source.repairImportedProducts. Uzupełnia tylko puste miniatury własnych zamówień źródła, sprawdza identyfikatory pozycji i chroni zapis porównaniem poprzedniej tablicy produktów. Nie zmienia danych finansowych ani istniejących zdjęć.
Opisy importu i wpłat (2.18.4)
Kontrakt orders.source.updateLabels obsługuje opcjonalne paymentEntry (transactionId, method, previousMethods) i removeStaffNoteLines. Uwierzytelniony moduł-źródło może zmienić nazwę jednej istniejącej wpłaty oraz usunąć dokładnie wskazane wiersze notatki wyłącznie we własnym zamówieniu. Kontrola poprzednich wartości zachowuje równoległe i ręczne zmiany. Operacja nie dodaje wpłat, nie zmienia kwot, dat ani stanu opłacenia i nie emituje zdarzeń sprzedaży. Obsługę ogłasza orders.import.capabilities.sourcePresentation.
Wypełniacz osoby na fakturze (2.18.5)
orders.source.updateLabels przyjmuje opcjonalne previousInvoiceNaturalPerson. Usuwa tylko niezmienioną wartość złożoną z podkreśleń, myślników i spacji. Nie zmienia firmy, NIP ani rzeczywistej nazwy osoby. Obsługę ogłasza sourceRecipientPlaceholders.
Katalog produktów z marketplace (2.18.6)
Nowe importy z productSource: marketplace tworzą brakujące SKU przez standardowe core/orders → core/products. Hook orders.source.syncCatalog umożliwia uwierzytelnionej instancji źródła uzupełnienie katalogu dla istniejącego zamówienia. Przy poprawnych danych finansowych tworzone są tylko brakujące kartoteki i uzupełniane puste productId. Stan pakowania, BOM zamówienia, kwoty i wpłaty pozostają bez zmian. Istniejące kartoteki nie są nadpisywane. Flaga możliwości: marketplaceCatalogSync.
Opcjonalne productMetadata: [{sourceId, sku, ean}] tego hooka uzupełnia wyłącznie puste EAN-y dopasowanych pozycji marketplace. Dostawca ponownie waliduje sumę kontrolną EAN/GTIN, odrzuca sprzeczne kody i nie modyfikuje składników BOM ani istniejących EAN-ów. Uzupełnienie jest niezależne od zatwierdzenia finansowego. Zapis pozycji chroni compare-and-set i odczyt potwierdzający; konflikt edycji zwraca synced: false, metadataSynced: false. metadataSynced potwierdza dopasowanie wszystkich przekazanych metadanych. Możliwość deklaruje flaga sourceProductMetadata. Nowe kartoteki otrzymują uzupełniony EAN; istniejące kartoteki zachowują swoje dane.
2.18.7
- Szczegóły zamówienia wyświetlają sam numer NIP bez dodatkowego prefiksu.
2.18.8
- Kontrakt
orders.source.restoreRemovedprzywraca dokument własnej instancji źródła podczas jawnej ponownej synchronizacji. Zachowuje identyfikator, ręczne dane, płatności i pakowanie; nie powtarza automatyzacji utworzenia. Nie przywraca rekordów scalonych ani cudzych kont.
2.18.9
orders.source.prepareReimportprzydziela deterministyczną tożsamość nowego importu po usunięciu; aktywny dokument jest zwracany bez duplikowania. Nowe ID oddziela wpłaty, historię, pakowanie, notatki i dokumenty poprzedniego importu. Metoda jest tylko do odczytu, sprawdza źródło i instancję oraz blokuje odtwarzanie scalonych dzieci.orders.source.updateLabelsuzupełnia brakujący punkt odbioru i typ dostawy atomowo, zachowując ręczne wybory użytkownika.- Stare wpisy we wspólnej historii platformy pozostają przy usuniętym ID. Nie są usuwane dokumenty ani przesyłki należące do innych modułów.
Zarządzanie osobistymi szablonami filtrów
Osobiste szablony filtrów można wybrać w panelu filtrów, zmienić ich nazwę i kryteria, nadpisać albo zapisać jako nowy. Dla wybranego szablonu bez zmian przycisk pokazuje „Usuń filtr”; usunięcie szablonu nie czyści aktywnych kryteriów listy. filters.get, filters.options, filters.picker, filters.controls, filters.update i filters.delete wymagają orders.view i właściciela z ctx.userId. Odczyty i zapisy są ograniczone przez ownerUserId; nazwa jest unikalna wśród szablonów użytkownika.
orders.source.syncCatalog przyjmuje opcjonalne sourcePrices: true: idempotentnie dopisuje tożsamość źródła i ceny kanałowe do istniejących SKU. Flaga możliwości idempotentSourceCatalogPrices oznacza bezpieczne ponowienie po utracie odpowiedzi. Wymaga core/products ≥1.2.3; nie zmienia oryginalnych/ręcznych danych katalogu, BOM ani finansów i pakowania zamówienia.
Stany magazynowe przy pozycjach
Otwarte zamówienie dodaje neutralne sloty views.productInventory przy SKU w widoku pakowania i księgowym. Dostawcy są odkrywani hookiem, a każdy odczyt inventory.stock.getBySkus wskazuje konkretne ID instancji. Kilka kont pozostaje rozdzielonych; bez integracji miejsce jest puste. Lista zamówień nie pobiera stanów.
inventoryOrderView odczytuje wyłącznie własne zamówienie i tworzy natywne sloty inventoryView dla unikalnych SKU przez bezpieczne znaczniki danych. Kontroler inicjalizuje natywne widoki OVE z SKU kodowanym URI; schemat odpowiedzi nie rośnie o kolejne widoki, więc duże zamówienie nie przekracza limitu zdalnego schematu. Zapotrzebowanie obejmuje wszystkie powtórzenia SKU oraz składniki pomnożone przez ilość zestawów. Kontroler src/order-inventory.js kopiuje bezpieczny zwykły tekst tych slotów do obu prezentacji pozycji. Sam nie wykonuje żadnych zapytań ani nie uruchamia odświeżania okresowego. Po zmianie kontrolera uruchom node scripts/sync-order-inventory.js.
