PosnetServer od wersji 4.3 umożliwia odczyt pamięci fiskalnej. Oznacza to że w wygodny sposób można uzyskać dostęp do historii wystawionych faktur, paragonów, raportów dobowych czy zdarzeń takich jak awarie zasilania czy błędy mechanizmu drukującego.
Odczytu zdarzeń można dokonać za pomocą nowych RESTpoint takich jak:
- POST /raporty/events/dobowy
- POST /raporty/events/custom
- POST /raporty/sellhistory
Wykonujemy je w następujący sposób:
1 2 3 4 5 |
curl -s -XPOST "http://localhost:3050/raporty/sellhistory?fulldebug=true" -H 'Content-type: application/json' -d ' { "dateFrom":"2023-07-31T23:20:00+02:00", "dateTo":"2023-08-29T23:49:59+02:00" }' |
W odpowiedzi otrzymujemy identyfikator tasku, ponieważ skanowanie pamięci fiskalnej może długo trwać. Stąd, bardzo ważnym parametrem requestu jest dobranie odpowiedniego zakresu dat w polach “dateFrom” i “dateTo”. Pole “dateTo” jest opcjonalne i jeśli nie zostało podane to znaczy że wyszukujemy do “teraz”. Jeśli zakres dat będzie bardzo szeroki, skanowanie pamięci może trwać nawet kilkadziesiąt minut, stąd status tasku można sprawdzić za pomocą RESTpoint:
- GET /tasks/get/<identyfikator taska>
- GET/tasks/list
Przykładowa odpowiedź API:
1 |
{"hits":{"task":{"ts":1690880233568,"task":"09be05d1-ace2-48c9-9cf5-d12c9cf9570e","inprogress":true,"progress":86}},"ok":true} |
W momencie gdy “inprogress” zmieni wartość na “false”, wówczas metoda zwraca pełen wynik, przykładowo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
{"hits":{"task":{"ts":1690887918949,"task":"09be05d1-ace2-48c9-9cf5-d12c9cf9570e","inprogress":false,"progress":0,"success":true,"message":null,"result": { "ok": true, "code": 0, "error": "", "results": [ { "header": { "type": "paragon", "date": "2023-08-01T10:27:49Z", "nb": 488, "fisk": 0, "taxid": "5554448899", "prefix": "", "compress": 0, "sw": 0 }, "lines": [ { "na": "Towar 1", "vtn": "A", "pr": 12356, "wa": 12356, "il": 1, "prec": 0, "jedn": "", "desc": "", "storno": 0, "rabatDesc": "", "rabatDescPrint": 0 }, { "na": "Towar 2", "vtn": "A", "pr": 34567, "wa": 34567, "il": 1, "prec": 0, "jedn": "", "desc": "", "storno": 0, "rabatDesc": "", "rabatDescPrint": 0 } ], "footer": { "type": "paragon", "fisk": 0, "cancelled": 0, "nb": 3, "date": "2023-08-01T10:27:50Z", "uniq": "ZCJ 2221117733", "cashNumber": "001", "cashier": "KIEROWNIK", "taxid": "", "taxidPrefix": "", "taxidStyle": 0, "compress": 0, "sw": 0 }, "payments": [ { "cash": 0, "paymentType": "gotowka", "amount": 43923, "name": "", "currency": "PLN" } ], "summary": { "ptu": { "ptu.0": 2300, "wa.0": 43923, "wavat.0": 8213, "ptu.1": 800, "wa.1": 0, "wavat.1": 0, "ptu.2": 500, "wa.2": 0, "wavat.2": 0, "ptu.3": 0, "wa.3": 0, "wavat.3": 0, "ptu.4": -1, "wa.4": 0, "wavat.4": 0, "ptu.5": -2, "wa.5": 0, "wavat.5": 0, "ptu.6": -2, "wa.6": 0, "wavat.6": 0, "currency": "PLN" }, "totals": { "total": 43923, "totalOpak": 43923, "currency": "PLN", "printSection": 0, "sh": 0 } }, "extralines": [ { "id": 2, "text": "987", "sw": 0, "sh": 0, "widthType": 0 }, { "id": 15, "text": "Jan Kowalski", "sw": 0, "sh": 0, "widthType": 0 }, { "id": 39, "text": "FV 12345/2018", "sw": 0, "sh": 0, "widthType": 0 }, { "id": 33, "text": "dodatkowe informacje #1", "sw": 0, "sh": 0, "widthType": 0 }, { "id": 33, "text": "dodatkowe informacje #2", "sw": 0, "sh": 0, "widthType": 0 } ] } ] } }},"ok":true} |
Aby cyklicznie nie odpytywać PosnetServer o aktualny status tasku, podczas wysyłania requestu można zdefiniować strukturę “callback”, aby PosnetServer wysłał wyniki do zewnętrznego serwisu jak tylko task się zakończy. Przykładowo:
1 2 3 4 5 6 7 8 9 |
curl -s -XPOST "http://localhost:3050/raporty/sellhistory?fulldebug=true" -H 'Content-type: application/json' -d ' { "dateFrom":"2023-07-31T23:20:00+02:00", "dateTo":"2023-08-29T23:49:59+02:00", "callback" : { "resultsurl": "http://looo.loo", "resultsurlmethod": "POST" } }' |
Dodatkowo, wykorzystując atrybut “saveResults” można zapisać wyniki do pliku, przykładowo do pliku “/tmp/sellhistory.json”.
1 2 3 4 5 6 7 8 9 10 |
curl -s -XPOST "http://localhost:3050/raporty/sellhistory?fulldebug=true" -H 'Content-type: application/json' -d ' { "saveResults" : "/tmp/sellhistory.json", "dateFrom":"2023-07-31T23:20:00+02:00", "dateTo":"2023-08-29T23:49:59+02:00", "callback" : { "resultsurl": "http://looo.loo", "resultsurlmethod": "POST" } }' |
Optymalizacja
Na dłuższą metę skanowanie pamięci fiskalnej podczas każdego requestu jest niewydajne, stąd warto użyć wbudowanego w PosnetServer cache. Do dyspozycji mamy dwa rodzaje cache: “sections” i “full“. Cache typu “sections” buduje lokalny index plików i zapisuje go w katalogu wskazanym w pliku konfiguracyjnym config.json:
1 2 3 4 5 6 7 |
..... "fiscalmemory" : { "cache" : { "directory" : "fiscalcache" } }, ...... |
Lokalny index to lista identyfikatorów dokumentów wraz ze znacznikiem czasu i dokładną lokalizacją tych danych w pamięci fiskalnej drukarki. Budowanie cache może chwilę potrwać, ale dzięki temu PosnetServer podczas kolejnego requestu o historię dokumentów nie będzie musiał już skanować pamięci fiskalnej żeby odnaleźć dokumenty, gdyż od razu zna ich lokalizacje i czas requestu znacząco się skróci. Komunikacja z drukarką jest niezbędna jedynie do pobrania zawartości paragonu lub faktury. Cache typu “full” również indeksuje pamieć fiskalną na lokalnym dysku ale dodatkowo przechowuje w tym samym katalogu zawartość pamięci fiskalnej. Jeśli zbudowany zostanie cache typu “full”, wyszukiwanie dokumentów odbywa się praktycznie bez komunikacji z drukarką, gdyż wybrany zakres pamieć fiskalnej jest w całości pobrany na dysk. Lokalnym cache można zarządzać za pomocą REStpoint’ów:
- DELETE /cache/clean
- GET /cache/ranges
- POST /cache/update
- POST /cache/build
Aby zindeksować pamięć fiskalną od 2023-07-30 do 2023-08-20, należy wykonać następujący request:
1 2 3 4 5 6 |
curl -s -XPOST "http://localhost:3050/cache/build?fulldebug=true" -H 'Content-type: application/json' -d ' { "dateFrom": "2023-07-30T00:00:00+02:00", "dateTo": "2023-08-20T23:59:59+02:00", "cacheType": "full" }' |
Proces jest czasochłonny, w tym czasie drukarka nie przyjmuje transakcji do wydruku. Nowo fiskalizowane dokumenty nie aktualizują automatycznie cache, stąd należy go odświeżać. Nie jest konieczne przebudowywanie go od początku za każdym razem, wystarczy użyć metody /cache/update aby doczytać nowe, nie indeksowane wcześniej zdarzenia z pamięci fiskalnej. Przykładowo:
1 2 3 4 5 |
curl -s -XPOST "http://localhost:3050/cache/update?fulldebug=true" -H 'Content-type: application/json' -d ' { "dateFrom": "2023-07-30T00:00:00+02:00", "dateTo": "2023-08-30T23:59:59+02:00" }' |
Aby używać cache w naszym przykładzie do wyszukiwania dokumentów, należy ustawić parametr “useCache” na “true” w następujący sposób:
1 2 3 4 5 6 7 8 9 10 11 |
curl -s -XPOST "http://localhost:3050/raporty/sellhistory?fulldebug=true" -H 'Content-type: application/json' -d ' { "useCache" : true, "saveResults" : "/tmp/sellhistory.json", "dateFrom":"2023-07-31T23:20:00+02:00", "dateTo":"2023-08-29T23:49:59+02:00", "callback" : { "resultsurl": "http://looo.loo", "resultsurlmethod": "POST" } }' |
Zachęcamy do używania cache typu “full” (jest on najbardziej efektywny) o ile przechowywanie kopii danych z pamięci fiskalnej na komputerze gdzie uruchomiony jest PosnetServer nie jest wbrew polityce Security naszej firmy. Jeśli jest, to wygodniej używać cache typu “sections”. Ten cache nie zawiera żadnych poufnych danych dotyczących sprzedaży. Składa się jedynie z numeru dokumentu, jego rodzaju i znacznika czasu.
Aby przetestować powyższe polecenia, w katalogu /docs w paczce instalacyjnej umieściliśmy kilka nowych skryptów.
WYDRUK KOPII PARAGONU
Drukarki nie mają funkcjonalności wydruku kopii paragonu, jednak po odczytaniu zawartości pamięci fiskalnej, można wykonać wydruk niefiskalny zbliżony swoim formatem do paragonu. Przykładowy request może wyglądać następująco (uwaga, użyty w przykładzie RESTpoint /raporty/textlines dostępny jest od wersji 5.2):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
curl -X 'POST' \ 'http://localhost:3050/raporty/textlines?fulldebug=true' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "header": 84, "lines": [ " POSNET THERMAL XL2 ONLINE", " POSNET POLSKA S.A.", " ul. Municypalna 33", " 02-281 Warszawa", " www.posnet.com", "NIP 5222628262 nr:55", " PARAGON NIEFISKALNY", "Cukierki 1 x10,00 10,00A", "Ciastka 1 x25,00 25,00A", "Podsuma: 35,00", "OPUST stały klient 15,00 % -5,25", "Podsuma: 29,75", "- - - - - - - - - - - - - - - - - - - ", "OPUSTY ŁĄCZNIE -5,25", "- - - - - - - - - - - - - - - - - - - ", "SPRZEDAŻ OPODATKOWANA A 29,75", "PTU A 23,00 % 5,56", "SUMA PTU 5,56", "SUMA PLN 29,75", "- - - - - - - - - - - - - - - - - - - -", "ROZLICZENIE PŁATNOŚCI", "GOTÓWKA 29,75 PLN", "00018 #001 KIEROWNIK 2018-09-04 11:07", "B2232B44A916FFE6CD4CEB7FB33E76E93EC23D", " {PL} ZBF 1801007587" ] }' |
PYTANIA I ODPOWIEDZI (Q&A)
Q: Jak odróżnić w wynikach eParagony od zwykłych paragonów?
A: Dla drukarki fiskalnej obydwa typy paragonów są równoznaczne, stad w nie ma możliwości aby na podstawie zwróconych wyników określić czy dany paragon był wystawiony jako klasyczny paragon czy eParagon. Jako rozwiązanie, proponujemy dodawanie opisu do paragonu, np. w parametrze “extralines”.