Przejdź do głównej zawartości

CashChequePrinting przy anulowaniu

Powiadomienie o drukowaniu paragonu przy płatności
CashChequePrinting,
umożliwiające rozszerzenie markup paragonu w nagłówku i stopce, od wersji SyrvePOS 8.5.1 będzie również generowane przy anulowaniu (zwrocie) zamówienia.

Przykład:

public sealed class CashChequePrintingHandler : IDisposable
{
private readonly IDisposable subscription;

public CashChequePrintingHandler()
{
subscription = PluginContext.Notifications.CashChequePrinting.Subscribe(OnCashChequePrinting);
}

private static CashCheque OnCashChequePrinting(Guid orderId)
{
PluginContext.Log.Info("On cash cheque printing subscription.");

var order = PluginContext.Operations.GetOrderById(orderId);
var message = order.Status == OrderStatus.Closed
? $"Zamówienie #{order.Number} storno."
: $"Zamówienie #{order.Number} zapłata.";

return new CashCheque
{
BeforeCheque = new XElement(Tags.Center, message),
AfterCheque = new XElement(Tags.QRCode, message)
};
}

public void Dispose()
{
try
{
subscription.Dispose();
}
catch (RemotingException)
{
// nic do zrobienia przy utracie połączenia
}
}
}

Zwroty produktów i zamówień z zamkniętych zmian kasowych

Teraz możliwe jest zwracanie produktów lub zamówień z zamkniętych zmian kasowych nie tylko z UI SyrvePOS, ale także z API V8.

W jednej z poprzednich wiadomości
mówiliśmy o sposobach pobierania zamówień z zamkniętych zmian kasowych.
Teraz, jeśli zajdzie taka potrzeba, możesz dostosować listę dań takiego zamówienia i zwrócić je, wywołując metodę
StornoPastOrder.

Jeśli potrzebujesz zwrócić towary, które nie są powiązane z konkretnym zamówieniem, możesz użyć metody
StornoPastOrderItems,
wcześniej generując listę towarów items do zwrotu.
PastOrderItem.Price oraz
PastOrderItem.SumWithoutDiscounts
nie są używane; można je pozostawić puste podczas przekazywania do metody.

Możesz również określić z API rozmiar dania, jeśli jest on obsługiwany.
Każdy z przekazanych items może być oznaczony jako modyfikator lub danie główne
(PastOrderItem.IsMainDish).
Podobnie jak w UI i bez ścisłych kontroli zgodności z typem pozycji z karty.
Jednak modyfikator nie może być pierwszym elementem listy.
Ponadto danie oznaczone jako modyfikator nie może mieć rozmiaru.
Każdy PastOrderItem
musi wskazywać miejsce przygotowania oraz typ miejsca przygotowania.

Obecnie zwrot jest możliwy tylko na domyślnym rejestratorze fiskalnym bieżącego terminala.
Zmiana kasowa musi być otwarta i musi być wystarczająca ilość gotówki na zwroty gotówkowe.

Typ płatności do storna można uzyskać za pomocą
GetPaymentTypesToStornoPastOrderItems.
Możesz także zwrócić typ płatności wtyczki
(z zaznaczeniem canProcessPaymentReturnWithoutOrder równym true, przekazywanym do
RegisterPaymentSystem).

Typ usunięcia do storna można uzyskać za pomocą
GetRemovalTypesToStornoPastOrderItems.
Typ usunięcia może być

Przy storno z odpisem sprawdzana jest obecność niestandardowego typu płatności "Zwrot od klienta".

Oddział musi należeć do bieżącej grupy, a oddział musi posiadać magazyn.

System podatkowy jest przekazywany tylko, jeśli został pobrany przez
GetTaxationSystemsToStornoPastOrderItems.

Przy storno z odpisem sprawdzane jest prawo F_STRN (Zwrot płatności).
Przy storno bez odpisu sprawdzane jest prawo F_SWWOFF (Zwrot płatności na paragon bez zwrotu do magazynu).

Przykłady:

private void StornoPastOrder()
{
var pastOrder = PluginContext.Operations.GetPastOrders().First();
var paymentType = pastOrder.Payments.First();

// rt.WriteoffType.HasFlag(WriteoffType.Cafe) - storno z odpisem
// rt.WriteoffType == WriteoffType.None - storno bez odpisu
var removalType = PluginContext.Operations.GetRemovalTypesToStornoPastOrderItems().First(rt => rt.WriteoffType.HasFlag(WriteoffType.Cafe));
var section = pastOrder.RestaurantSection;
var orderType = pastOrder.OrderType;
var taxationSystem = PluginContext.Operations.GetTaxationSystemsToStornoPastOrderItems().Select(ts => (TaxationSystem?)ts).FirstOrDefault();

PluginContext.Operations.StornoPastOrder(
PluginContext.Operations.GetCredentials(),
pastOrder,
paymentType,
removalType,
section,
orderType,
null,
taxationSystem,
null);
}

private void StornoProducts()
{
var paymentType = PluginContext.Operations.GetPaymentTypesToStornoPastOrderItems().First(pt => pt.Name.Contains("SampleApiPayment"));

// rt.WriteoffType.HasFlag(WriteoffType.Cafe) - storno z odpisem
// rt.WriteoffType == WriteoffType.None - storno bez odpisu
var removalType = PluginContext.Operations.GetRemovalTypesToStornoPastOrderItems().First(rt => rt.WriteoffType.HasFlag(WriteoffType.Cafe));
var section = PluginContext.Operations.GetTerminalsGroupRestaurantSections(PluginContext.Operations.GetHostTerminalsGroup()).First();
var orderType = PluginContext.Operations.GetOrderTypes().FirstOrDefault(ot => ot.OrderServiceType == OrderServiceTypes.Common);
var taxationSystem = PluginContext.Operations.GetTaxationSystemsToStornoPastOrderItems().Select(ts => (TaxationSystem?)ts).FirstOrDefault();

var activeProducts = PluginContext.Operations.GetActiveProducts()
.Where(product => product.Template == null &&
(product.Type == ProductType.Dish || product.Type == ProductType.Modifier || product.Type == ProductType.Goods || product.Type == ProductType.ForPurchase))
.ToList();

PluginContext.Operations.StornoPastOrderItems(
PluginContext.Operations.GetCredentials(),
GetPastOrderItems(activeProducts).ToList(),
paymentType,
removalType,
section,
orderType,
null,
taxationSystem,
null);
}

private IEnumerable<PastOrderItem> GetPastOrderItems(IReadOnlyList<IProduct> activeProducts)
{
var product = activeProducts.First(p => p.Name.Contains("Tea"));
yield return new PastOrderItem
{
IsMainDish = true,
Product = product,
ProductSize = PluginContext.Operations.GetProductSizes().FirstOrDefault(ps => ps.Name.Contains("S")),
Amount = 2,
SumWithDiscounts = 100.5m,
Price = 0, // nieużywane w StornoPastOrderItems
SumWithoutDiscounts = 0, // nieużywane w StornoPastOrderItems
};

product = activeProducts.First(p => p.Name.Contains("Cream"));
yield return new PastOrderItem
{
IsMainDish = false,
Product = product,
ProductSize = null,
Amount = 2,
SumWithDiscounts = 0m,
Price = 0, // nieużywane w StornoPastOrderItems
SumWithoutDiscounts = 0, // nieużywane w StornoPastOrderItems
};

product = activeProducts.First(p => p.Name.Contains("Puree"));
yield return new PastOrderItem
{
IsMainDish = true,
Product = product,
ProductSize = null,
Amount = 1,
SumWithDiscounts = 90m,
Price = 0, // nieużywane w StornoPastOrderItems
SumWithoutDiscounts = 0, // nieużywane w StornoPastOrderItems
};

product = activeProducts.First(p => p.Name.Contains("Bottle"));
yield return new PastOrderItem
{
IsMainDish = true,
Product = product,
ProductSize = null,
Amount = 2,
SumWithDiscounts = -15m,
Price = 0, // nieużywane w StornoPastOrderItems
SumWithoutDiscounts = 0, // nieużywane w StornoPastOrderItems
};
}

Właściwości niestandardowe (ProductTags) zostały ustawione dla produktu (IProduct)

W API V8 właściwości niestandardowe zostały udostępnione dla produktów IProduct.ProductTags, a także stało się możliwe pobranie wszystkich właściwości użytkownika oraz ich grup za pomocą wywołań GetProductTags oraz GetProductTagGroups.

Pobieranie konkretnych właściwości niestandardowych po ID GetProductTagById, TryGetProductTagById.

Pobieranie konkretnych grup właściwości niestandardowych po ID GetProductTagGroupById, TryGetProductTagGroupById.

Uzyskanie grupy dla konkretnej właściwości niestandardowej jest dostępne przez właściwość IProductTag.Group.

Adres sąsiedniego terminala

W API V8Preview2 stało się możliwe poznanie adresu sąsiedniego terminala.

Dodano metodę TryGetTerminalAddress, która zwraca adres danego terminala. Wartość zwracana może być adresem IPv4/IPv6, nazwą domeny lub nazwą NetBIOS.