iiko / front.api.sdk

iikoFront Api SDK (part of iikoRMS)
34 stars 22 forks source link

Передача в фискальный регистратор данных платежной операции при оплате заказа #525

Closed shute276 closed 3 weeks ago

shute276 commented 2 months ago

Используется плагин фискального регистратора CheckboxCashRegisterUA (2.1.7.10398). Разработан плагин, который отвечает за оплату заказа в определенной платежной системе. Как передать в фискальный регистратор данные платежной транзакции, чтобы отразить их в фискальном чеке?

rengal commented 2 months ago

Можно при оплате сохранить произвольные данные, а в нужный момент получить эти данные, используя методы SetCustomData и GetCustomData

public class MyPaymentProcessor : IPaymentProcessor
{
    public string PaymentSystemKey => "MyPaymentTypeSystemKey";

    public void Pay(decimal sum, [NotNull] IOrder order, [NotNull] IPaymentItem paymentItem, Guid transactionId, [NotNull] IPointOfSale pointOfSale, IUser cashier,
        IOperationService opService, IReceiptPrinter printer, IViewManager viewManager, IPaymentDataContext context)
    {
        //Выполнить операции в обработчике Pay
        //...

        //Записать данные
        var serializedArgs = ... //сериализовать кастомные данные
        context.SetCustomData(serializedArgs);       
    }
}

Чтобы передать сохраненные данные в фискальный регистатор, необходимо в методе DoCheque запросить эти данные, используя метод GetCustomData

public sealed class MyCashRegister : ICashRegister
{
     public CashRegisterResult DoCheque([NotNull] ChequeTask chequeTask, IViewManager viewManager)
     {
         order = operationService.TryGetOrderById(chequeTask.OrderId);
        if (order != null)
        {
            string myCustomPaymentData = GetCustomPaymentData(order);
            //передать данные в ФР
            //....
        }
    }

    //Вспомогательные методы
    private string GetCustomPaymentData(IOrder order)
    {
        if (order == null)
            throw new ArgumentNullException(nameof(order));

        var myPaymentItem = order.GetPaymentItems().FirstOrDefault(IsMyPluginPaymentType);
        if (myPaymentItem == null)
            return null;
        var customData = (myPaymentItem .AdditionalData as ExternalPaymentItemAdditionalData)?.CustomData;
        return customData;
    }

    //Проверка, что оплата является плагинным типом оплаты с заданным ключом
    private bool IsMyPluginPaymentType(IPaymentItem paymentItem)
    {
        if (paymentItem == null)
            throw new ArgumentNullException(nameof(paymentItem));

        var paymentSystemName = PluginContext.Operations.GetPaymentSystemKey(paymentItem.Type);

        return paymentItem.Type.Kind == PaymentTypeKind.External && !string.IsNullOrWhiteSpace(paymentSystemName) && paymentSystemName == PaymentSystemKey;
    }
}

См.также https://iiko.github.io/front.api.doc/v6/ru/PaymentProcessor.html https://iiko.github.io/front.api.sdk/v9/html/Methods_T_Resto_Front_Api_IPaymentDataContext.htm

shute276 commented 2 months ago

Используется посторонний плагин фискального регистратора CheckboxCashRegisterUA (2.1.7.10398). Его изменение недоступно.

rengal commented 2 months ago

Подходит ли передача данных платежной операции в виде набора текстовых строк в шапке или подвале чека ( в виде стандартной разметки)? Если да, то можно добавить эти строки, реализуя IChequeTaskProcessor (пример есть в Resto.Front.Api.SamplePlugin)

public BeforeDoCheckActionResult BeforeDoCheckAction(ChequeTask chequeTask, ICashRegisterInfo device, CashRegisterChequeExtensions chequeExtensions, IViewManager viewManager)
{
    PluginContext.Log.InfoFormat("Before do cheque on cash register: {0} ({1})", device.FriendlyName, device.Id);
    const bool needChangeInfo = true;
    if (needChangeInfo)
    {
        var sampleBeginElement = new XElement(Tags.Left,
            new XElement(Tags.Left, "Organization"),
            new XElement(Tags.Left, "Address"),
            new XElement(Tags.Left, $"Table number: {chequeTask.TableNumberLocalized}"));
        var textBeforeCheque = sampleBeginElement;
        var sampleAfterElement = new XElement(Tags.Left,
            new XElement(Tags.Left, "Have a nice day"));
        var textAfterCheque = sampleAfterElement;

        // This information will be passed to the front app
        return new BeforeDoCheckActionResult
        {
            BeforeCheque = new List<Data.Print.Document>(new[] { new Data.Print.Document { Markup = textBeforeCheque } }), // markup to add to the header (at the very beginning of the cheque)
            AfterCheque = new List<Data.Print.Document>(new[] { new Data.Print.Document { Markup = textAfterCheque } }), // markup to add at the end of the cheque
            CashierName = "CashierName",
            CustomerTin = "123456789012"
        };
    }

    // Nothing to change
    return null;
}