Przejdź do głównej zawartości

Zwrot zamówienia (anulowanie)

Obecnie możliwy jest zwrot zamówień nie tylko z poziomu UI Syrve POS,
ale także z API V8Preview7. W tym celu należy wywołać metodę StornoOrder.

W ten sposób zamknęliśmy pętlę płatności z poziomu API, w której dostępny jest teraz pełen zestaw działań:

Aby zwrócić zamówienie, wtyczka musi obsługiwać transakcje płatnicze.
Pracownik, którego
ICredentials
przekazujemy do metody odwracania zamówienia, musi posiadać prawo F_STRN (Wykonaj zwrot).
Zmiana kasy, w której zamówienie zostało opłacone, musi być otwarta i należeć do aktualnego terminala, ponieważ odwrócenie odbywa się lokalnie.
W kasie powinno być wystarczająco dużo gotówki, jeśli zamówienie zostało opłacone gotówką.
Wszystkie płatności podlegające zwrotowi muszą obsługiwać cichą płatność.

Szczegóły dotyczące nieudanego odwrócenia, które mogą skutkować odrzuceniem wyjątku PaymentActionFailedException,
zostały połączone ze szczegółami dotyczącymi nieudanej płatności,
w związku z czym pole PaymentActionFailedException.Reason
jest teraz wypełniane w metodzie StornoOrder.
Lista PaymentActionFailedExceptionReason
została rozszerzona o nowe elementy:

  • SomeOfCafeSessionsIsClosed,
  • StornoOrderFailed,
  • StornoNotSupported,
  • OrderStatusIsNotClosed,
  • OrderCloseAndStornoOnDifferentTerminalNotSupported,
  • DeliveryOrderStatusIsCanceled

Spośród których

  • PaymentsProcessingCanceled,
  • PaymentsProcessingFailed,
  • BeforeDoChequeOperationFailed,
  • ChequeTaskProcessorFailed,
  • CashRegisterOperationFailed

posiadają określoną właściwość PaymentActionFailedException.Details,
która będzie zawierać komunikat wyjątku wygenerowany przez inną wtyczkę w

Powód nieudanego odwrócenia (PaymentActionFailedException.Reason)
CashForChangeNotEnough został przemianowany na CashNotEnough.

Chciałbym również zaznaczyć, że teraz możliwe jest usunięcie opłaconego zamówienia. Przykładowy schemat wywołań dla zamkniętego zamówienia wyglądałby następująco:

var order = PluginContext.Operations.GetOrders().Last(o => o.Status == OrderStatus.Closed);
var credentials = PluginContext.Operations.AuthenticateByPin("777");

// Anulujemy zamówienie i zwracamy płatność
order = PluginContext.Operations.StornoOrder(order, credentials);

// Zwrot przedpłat, jeśli były uwzględnione w zamówieniu
foreach (var orderPayment in order.Payments)
{
PluginContext.Operations.UnprocessPayment(order, orderPayment, credentials);
order = PluginContext.Operations.GetOrderById(order.Id);
}

// Usuwanie wydrukowanych pozycji zamówienia
if (order.Items.Count > 0)
{
PluginContext.Operations.DeletePrintedOrderItems(
"powód",
WriteoffOptions.WriteoffToCafe(PluginContext.Operations.GetActiveRemovalTypes().First(rt => rt.WriteoffType.HasFlag(WriteoffType.Cafe))),
order,
order.Items,
credentials);
order = PluginContext.Operations.GetOrderById(order.Id);
}

// Usuwanie zamówienia
PluginContext.Operations.DeleteOrder(order, credentials);

Śledzenie, z której dostawy powstała bieżąca dostawa lub do której została przeniesiona podczas transferu do nowego punktu.

Począwszy od V8Preview7, do zamówienia dostawy IDeliveryOrder dodano nowe właściwości, które są wypełniane podczas przenoszenia dostawy z punktu do punktu: identyfikator nowej dostawy utworzonej w celu przeniesienia bieżącej oraz identyfikator grupy nowej dostawy. Identyfikator starej dostawy, z której powstała bieżąca dostawa, oraz identyfikator grupy starej dostawy.

Podczas przenoszenia dostawy z punktu do punktu, stara dostawa zmienia status na „Anulowana”, a w nowym punkcie tworzona jest nowa dostawa poprzez sklonowanie danych. Pole MovedToDeliveryId starej dostawy jest wypełniane identyfikatorem nowej dostawy. Pole MovedToTerminalGroupId jest wypełniane identyfikatorem grupy, do której przeniesiono bieżącą dostawę.

Dla nowej dostawy w polu MovedFromDeliveryId przechowywany jest identyfikator starej dostawy, a w polu MovedFromTerminalGroupId identyfikator grupy, z której pochodzi bieżąca dostawa – jeśli dostawa nie została przeniesiona do innego punktu, wszystkie wymienione właściwości mają wartość null.

Właściwość MovedToDeliveryId istniała w zamówieniu dostawy IDeliveryOrder już przed V8Preview7, ale pod inną nazwą – MovedDeliveryId. W V8Preview7 została przemianowana na MovedToDeliveryId.

Aby zmienić dowolne z czterech wymienionych powyżej pól dostawy, do API dodano metodę ChangeDeliveryMoveIds.

Wydanie V8Preview7

Wydano wersję pośrednią V8Preview7.
Ten SDK jest obsługiwany od wersji 8.6.5 do wersji 8.9.1.
Dowiedz się więcej o wersjach API tutaj.

Uwierzytelnianie użytkownika bez kodu PIN

W API V8Preview7 możesz teraz potwierdzać akcje dla użytkowników bez PIN-u. Jednak wymaga to specjalnej licencji.

Każda instancja wtyczki musi mieć swój unikalny ClientId typu Guid.
Podczas uruchamiania wtyczka powinna pobrać slot licencyjny z modułu 21057201,
wywołując metodę ILicensingService.AcquireSlot
i przekazując swój ClientId.
Wynik wykonania metody powinien zostać zapamiętany przez wtyczkę i wyświetlony przy jej zakończeniu.
Ten schemat licencjonowania jest opisany szczegółowo w artykule "Licencjonowanie", rozdział "Opłata za zewnętrzne połączenie z wtyczką".

Następnie, aby uwierzytelnić się bez kodu PIN, należy wywołać metodę
IOperationService.AuthenticateByUser,
przekazując do niej użytkownika IUser
oraz ClientId danej instancji wtyczki, która używa licencji z modułu 21057201.
Metoda ta zwróci obiekt ICredentials,
za pomocą którego można kontynuować pracę jak dotychczas
(podobnie jak w metodzie IOperationService.AuthenticateByPin).

W związku z tym klient musi wystawić tyle slotów dla modułu 21057201, ile jest instancji wtyczek (wtyczki mogą być różne), które korzystają z uwierzytelniania użytkownika bez kodu PIN.

Więcej szczegółów o błędzie płatności

API V8Preview7 uczyniło analizę błędów płatności jeszcze wygodniejszą.

Metody PayOrder oraz PayOrderAndPayOutOnUser mogą wygenerować wyjątek PaymentActionFailedException w przypadku wystąpienia błędu podczas przetwarzania płatności. Dotychczas twórcy wtyczek mieli do dyspozycji jedynie komunikat błędu Exception.Message, co było niewygodne do pracy i klasyfikacji.

W nowej wersji w PaymentActionFailedException dodano właściwość Reason — klasyfikowalną przyczynę błędu, która nie może być null, jeśli wyjątek został rzucony z metod PayOrder lub PayOrderAndPayOutOnUser. Przy czym Reason może przyjmować następujące wartości z PaymentActionFailedExceptionReason:

/// <summary>
/// Powód rzucenia <see cref="PaymentActionFailedException"/>.
/// </summary>
[PublicAPI]
public enum PaymentActionFailedExceptionReason
{
OrderNotFound,
CannotLockOrder,
OrderStatusIsNotOpened,
BanquetOrderNotSupported,

DeliveryOrderStatusIsUnconfirmed,
DeliveryOrderHasPurchases,
DeliveryOrderPrepayAndCloseOnDifferentTerminalNotSupported,

PayInTypeIsIncorrect,
PayOutTypeIsIncorrect,
PayOutOnUserFailed,

CafeSessionNotFound,
CashRegisterNotFound,
OnlyVirtualCashRegisterForPurchasesSupported,

UserNotFound,
UserPersonalSessionNotOpened,
NoUserPermissionsToPayAsWaiter,
NoUserPermissionsToPayOthersOrder,
NoUserPermissionsToApprovePointsAccural,
UserCashDrawerNotFound,

PaymentTypeNotSpecified,
PaymentTypeNotConfigured,
UncombinablePaymentTypes,
UncombinablePaymentTypesFiscalNonFiscal,
AutomaticPaymentTypeNotFound,
NotProcessedNotSilentPaymentsNotSupported,
PayOrderFailed,
CannotPrintOrder,
CannotEditStopList,
OrderBillOperationFailed,
PaymentsProcessingCanceled,
PaymentsProcessingFailed,
BeforeDoChequeOperationFailed,
ChequeTaskProcessorFailed,
CashRegisterOperationFailed,

MoreThanOnePaymentsWithChange,
ChangeSumEqualToPaymentsWithChangeSum,
ChangeSumGreaterThanPaymentsWithChangeSum,

PaymentSumNotEnough,
PaymentSumNotIntegral,
PaymentSumTooLarge,
CashForChangeNotEnough,

BillOrderBeforePayment,
SplitOrderBeforePayment,

CookingPlacesWithEmptyStores,
TimePayProductsInOrder,

ChequeSmsSendingNotSupported,
ChequeEmailSendingNotSupported,
ChequeSettlementPlaceNotSupported,
}

Z których tylko

  • OrderBillOperationFailed,
  • PaymentsProcessingCanceled,
  • PaymentsProcessingFailed,
  • BeforeDoChequeOperationFailed,
  • ChequeTaskProcessorFailed,
  • CashRegisterOperationFailed

posiadają nową właściwość PaymentActionFailedException.Details, która będzie zawierać komunikat wyjątku wygenerowany przez inną wtyczkę w

Więcej informacji w zamówieniach z zamkniętych zmian kasowych

API V8Preview7 dodało informacje o tym, czy bieżące zamówienie zostało usunięte lub storno, informacje o tym, z którego zamówienia bieżące zamówienie zostało storno, a także listę zamówień wchodzących w skład tej samej grupy co bieżące zamówienie.

  • PastOrder.Deleted
    — czy zamówienie zostało usunięte;
  • PastOrder.Storned
    — czy zamówienie zostało storno na zmianie kasowej, na której zostało opłacone, lub czy bieżące zamówienie jest zamówieniem zwracającym zamówienie z zamkniętej zmiany kasowej (uwaga: jeśli oryginalne zamówienie nie zostało storno na zmianie kasowej, na której zostało opłacone, a zostało zwrócone tylko z zamkniętej zmiany kasowej, ta właściwość będzie równa false);
  • PastOrder.SourceOrderInfo
    — informacje o zamówieniu, z którego bieżące zamówienie zostało skopiowane podczas anulowania lub zwracania z zamkniętej zmiany kasowej;
  • PastOrder.GroupOrderInfo
    — informacje o zamówieniu, do grupy którego należy bieżące zamówienie
    (tutaj znajdą się informacje albo o zamówieniu, z którego bieżące zamówienie zostało skopiowane podczas anulowania,
    albo o zamówieniu, którego dodatkowym zamówieniem jest bieżące zamówienie,
    albo o zamówieniu, które było pierwsze w wyniku podziału na 2 kasy,
    jeśli wymienione oryginalne zamówienia same były pierwsze w grupie;
    albo o bieżącym zamówieniu, jeśli jest pierwsze (lub jedyne) w grupie,
    a jeśli oryginalne zamówienie samo było częścią grupy, to grupa bieżącego zamówienia będzie grupą oryginalnego zamówienia);
  • PastOrder.GroupPastOrders
    — lista zamówień wchodzących w tę samą grupę co bieżące zamówienie
    (zamówienia mające tę samą właściwość GroupOrderInfo, co bieżące zamówienie).

Aby zatem zrozumieć, czy bieżące zamówienie zostało przynajmniej raz anulowane, należy sprawdzić jego właściwość
Storned,
jeśli jest równa false, to dodatkowo trzeba sprawdzić, czy wśród zamówień zgrupowanych znajdują się takie, które odnoszą się do bieżącego przez właściwość
SourceOrderInfo:

if (pastOrder.Storned || pastOrder.GroupPastOrders.Any(o => o.SourceOrderInfo?.OrderId == pastOrder.OrderId)
// To zamówienie zostało już anulowane.

Przy próbie ponownego zwrotu
(StornoPastOrder)
już anulowanego zamówienia Syrve POS sprawdzi nowe prawo CAN_STORN_CLOSED_ORDERS_AGAIN ("F_STRNA", "Ponowny zwrot zamówienia z zamkniętej zmiany kasowej").

Tworzenie zamówień kuchennych z API

Do API V8Preview7 dodano metodę CreateKitchenOrder, która pozwala na tworzenie zamówienia kuchennego za pomocą API.

To zamówienie kuchenne nie będzie zawierać „części kelnerskiej”, więc wszystkie transakcje fiskalne muszą być realizowane przez systemy zewnętrzne.

CreateKitchenOrder pozwala na utworzenie pustego zamówienia kuchennego. Może to być przydatne w przypadkach, gdy trzeba przenieść dane zewnętrzne pomiędzy punktami (AddOrUpdateKitchenOrderExternalData, TryGetKitchenOrderExternalDataByKey).

Nie można dodawać dań do zamówień kuchennych utworzonych przez API. Jednak takie zamówienie kuchenne można oczyścić ze wszystkich dań. W tym celu dodano metodę DeleteKitchenOrderItems. Metoda ta działa tylko dla zamówień utworzonych przez API.

Dodatkowo, aby łatwiej rozróżnić, czy jest to standardowe zamówienie kuchenne, czy utworzone przez CreateKitchenOrder, w IKitchenOrder dodano pole IsExternal.

Drukowanie na niestandardowej drukarce

Do API V8Preview7 dodano nową metodę GetPrintingDeviceInfos, która zwraca listę obiektów z interfejsem PrintingDeviceInfo.

Ten interfejs przechowuje dwa pola: Id - unikalny identyfikator urządzenia do drukowania oraz FriendlyName - ustawiany w Syrve Office w Administracja => Ustawienia sprzętu. FriendlyName został stworzony dla wygody twórcy wtyczki, aby łatwo było określić, z którym urządzeniem drukującym się pracuje.

Lista urządzeń zwracana przez GetPrintingDeviceInfos może zawierać nie tylko drukarki, ale także rejestratory fiskalne z funkcją drukowania. Na tej liście mogą znajdować się urządzenia nie tylko z aktualnej grupy restauracji, ale także z innych, a także takie, które nie zostały przypisane do żadnej konkretnej grupy.

Drukowanie dokumentu na dowolnej z tych drukarek jest możliwe za pomocą metody Print .

Możliwość pracy z dowolnymi zsynchronizowanymi danymi

Począwszy od API V8PreviewV7, możliwa stała się praca z dowolnymi danymi. Dane te są na żywo i synchronizowane między terminalami dla wtyczek z określonym moduleId.

AddOrUpdateCustomData - dodawanie/aktualizacja danych według klucza. Wprowadzono ograniczenia dotyczące rozmiaru danych, liczby kluczy oraz długości klucza zapisywanych przez wtyczki. Długość klucza nie przekracza 512 znaków. Długość wartości nie przekracza 32768 znaków. Liczba kluczy, które wtyczka może zapisać, nie przekracza 1024.

TryGetCustomData - pobieranie danych według klucza. Jeśli dla takiego klucza nie ma danych, zwracana jest wartość null.

TryRemoveCustomData - usuwanie danych według klucza. Jeśli dane nie zostały znalezione, zwracana jest wartość false.

ClearCustomData - usuwanie wszystkich kluczy zapisanych przez wtyczkę.

GetAllCustomData - pobranie wszystkich danych dla wtyczki.

Istnieje automatyczne czyszczenie danych, które następuje po zamknięciu zmiany kasowej. Jeśli dane nie były używane przez pewien czas (domyślnie 3 dni, kontrolowane przez opcję w config.xml - customDataObsolescenceDuration), wtyczka zostanie o tym powiadomiona poprzez subskrypcję BeforeCustomDataClear. W powiadomieniu wtyczka otrzymuje słownik klucz-dane, do których nie miała dostępu przez długi czas. W odpowiedzi wtyczka powinna zwrócić klucze, które chce zachować. Jeśli wtyczka nie subskrybuje powiadomienia, „stare” dane zostaną usunięte. Ostatnia aktualizacja dostępu do danych jest wywoływana przez następujące wywołania: AddOrUpdateCustomData, TryGetCustomData, GetAllCustomData.