iiko / front.api.sdk

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

Set and change custom Order or Payment data issue #324

Open noncommunicado opened 2 years ago

noncommunicado commented 2 years ago

Здравствуйте!

Есть небольшая задача:

Установить некоторые клиентские данные (например строку в формате json) связные с объектом заказа при успешной оплате заказа. Затем, иметь возможность обратиться к заказу через PluginContext.Operations.GetOrders() и поменять эти данные.

Это нужно для отправки статистики при отмене; повторной отправки статистики в случае, если интернет соединение было недоступно; хранения логов и т.п.

Идея:

В методе Pay имплементации IPaymentProcessor записывать в объект данные, например флаги, используя IPaymentDataContext.SetCustomData или PluginContext.OperationsAddOrderExternalData при успешной оплате заказа (обращаясь к внешним сервисам), а затем по таймеру грузить последние несколько заказов (в контексте плагина вцелом) и по флагам производить операции, попутно меняя флаг (данные) используя ChangePaymentItemCustomData или PluginContext.Operations.AddOrderExternalData. (Или как-то иначе?)

Проблема:

Если в методе Pay пользовать AddOrderExternalData :

Pay(...) { var credits = PluginContext.Operations.AuthenticateByPin(_config.DefaultSettings.Pincode); PluginContext.Operations.AddOrderExternalData("data", data, order, credits); }

То будет исключение, что Entity занята - что вполне понятно.

Ок, пойдем другим путем:

Pay(...) { IPaymentDataContext.SetCustomData(data); }

Но тогда мы не сможем изменить данные Payment'a (платежа) после, по таймеру:

TimerAction(...) { editSession.ChangePaymentItemCustomData(convertor.GetJsonString(additionData), payment, order); PluginContext.Operations.SubmitChanges(credentials, editSession); throw: Cannot edit payment item in status PROCESSED. }

Вопрос:

Не очень хочется городить что-то вне системы, тем более, что кажется есть возможность этого не делать. Подскажите пожалуйста, может, я что-либо упустил? Или вышеизложенной возможности пока нет? Спасибо!

rgalk commented 2 years ago

Какую версию iikoFront API вы используете? Предполагаю, что V6 или выше.

Pay(...) { var credits = PluginContext.Operations.AuthenticateByPin(_config.DefaultSettings.Pincode); PluginContext.Operations.AddOrderExternalData("data", data, order, credits);

Почему вы используете глобальный экземпляр IOperationService обращаясь к нему через PluginContext.Operations?

Когда вы находитесь на экране кассы на заказ имеется блокировка и он будет недоступен для редактирования через API с помощью глобального экземпляра IOperationService, по возможности нужно пользоваться "локальным" экземпляром IOperationService переданным в метод. Посмотрите на сигнатуру метода IPaymentProcessor.Pay: void Pay(decimal sum, [NotNull] IOrder order, Guid paymentTypeId, Guid transactionId, [NotNull] IPointOfSale pointOfSale, [NotNull] IUser cashier, [NotNull] IOperationService operationService, IReceiptPrinter printer, [NotNull] IViewManager viewManager, IPaymentDataContext context); здесь есть аргумент IOperationService operationService.

vcpp commented 2 years ago

по возможности нужно пользоваться "локальным" экземпляром IOperationService переданным в метод.

В вашем случае так:


Pay(..., operationService, ...) {
var credits = operationService.AuthenticateByPin(_config.DefaultSettings.Pincode);
operationService.AddOrderExternalData("data", data, order, credits);
}
noncommunicado commented 2 years ago

image Все дело в том, что появляется ошибка и не важно какой IOperationService я использую. Версия пакета: v7Preview7

Pay(...) 
{
// ...
var credits = operationService.AuthenticateByPin(_config.DefaultSettings.Pincode);
operationService.AddOrderExternalData("data", data, order, credits); // <--- throw Exception
// ...
}

Exception:

System.InvalidOperationException
  HResult=0x80131509
  Message=Method “CreateEditSession” cannot be called using operation service of ProcessPayment event handler.
  Source=mscorlib
  StackTrace:
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Resto.Front.Api.IOperationServiceInternal.CreateEditSession()
   at Resto.Front.Api.OperationServiceFacade.Resto.Front.Api.IOperationService.CreateEditSession()
   at Resto.Front.Api.Extensions.OperationServiceExtensions.AddOrderExternalData(IOperationService operationService, String key, String value, IOrder order, ICredentials credentials)
   at Nm.Momentum.PluginIiko.MomentumPaymentProcessor.Pay(Decimal sum, IOrder order, IPaymentItem paymentItem, Guid transactionId, IPointOfSale pointOfSale, IUser cashier, IOperationService os, IReceiptPrinter printer, IViewManager vm, IPaymentDataContext context) in D:\Local Projects\Nm.Momentum.Plugin\Nm.Momentum.PluginIiko\Nm.Momentum.PluginIiko\MomentumPaymentProcessor.cs:line 262
   at Resto.Front.Api.RemotingHelpers.RemotablePaymentProcessor.Resto.Front.Api.IPaymentProcessor.Pay(Decimal sum, IOrder order, IPaymentItem paymentItem, Guid transactionId, IPointOfSale pointOfSale, IUser cashier, IOperationService operationService, IReceiptPrinter printer, IViewManager viewManager, IPaymentDataContext context)
   at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Object[]& outArgs)
   at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msg)

  This exception was originally thrown at this call stack:
    [External Code]
    Nm.Momentum.PluginIiko.MomentumPaymentProcessor.Pay(decimal, Resto.Front.Api.Data.Orders.IOrder, Resto.Front.Api.Data.Payments.IPaymentItem, System.Guid, Resto.Front.Api.Data.Organization.IPointOfSale, Resto.Front.Api.Data.Security.IUser, Resto.Front.Api.IOperationService, Resto.Front.Api.IReceiptPrinter, Resto.Front.Api.UI.IViewManager, Resto.Front.Api.IPaymentDataContext) in MomentumPaymentProcessor.cs
    [External Code]
vcpp commented 2 years ago

Method “CreateEditSession” cannot be called using operation service of ProcessPayment event handler

Увы, все действия с заказом, выполняемые пакетно в рамках сессии редактирования, во время проведения оплаты не поддерживаются. Это грубое ограничение, просто потому что пока не было возможности точечно запрещать одни действия и разрешать другие. Очевидно, что AddOrderExternalData — совершенно безопасное действие, никак не мешающее оплате, и его стоило бы разрешить. Если поправим это в V8, достаточно будет? Теоретически можно и в V7 протащить, это не должно сломать обратную совместимость.

noncommunicado commented 2 years ago

@vcpp Спасибо за ответ. Данную проблему пришлось решить иначе. Думаю, что скоропостижных правок она не требует. Ждем V8 (в котором, надеемся, не будут меняться имена интерфейсов, классов и методов на похожие, переставляя слова местами, как в случае с v6 -> v7) 😃

igorpooh1978 commented 2 years ago

@vcpp если вы такое протащите - будет прекрасно, т.к. есть несколько сценариев, когда addexternaldata надо выполнить именно при выполнении операции Pay.