diff --git a/Hcs.Client/Client/Api/Payload/Payments/ImportNotificationsOfOrderExecutionPayload.cs b/Hcs.Client/Client/Api/Payload/Payments/ImportNotificationsOfOrderExecutionPayload.cs new file mode 100644 index 0000000..961efcb --- /dev/null +++ b/Hcs.Client/Client/Api/Payload/Payments/ImportNotificationsOfOrderExecutionPayload.cs @@ -0,0 +1,48 @@ +using System; + +namespace Hcs.Client.Api.Payload.Payments +{ + // http://open-gkh.ru/Payment/importNotificationsOfOrderExecutionRequest/NotificationOfOrderExecution139Type.html + public class ImportNotificationsOfOrderExecutionPayload + { + /// + /// Уникальный номер платежа (идентификатор операции) + /// + public string orderId; + + /// + /// Дата + /// + public DateTime orderDate; + + /// + /// Сумма оплаты (в копейках) + /// + public decimal amount; + + /// + /// Необязательное. Признак онлайн-оплаты. + /// + public bool? onlinePayment; + + /// + /// Необязательное. Год. Указывать совместно с . + /// + public short? year; + + /// + /// Необязательное. Месяц. Указывать совместно с . + /// + public int? month; + + /// + /// Идентификатор платежного документа + /// + public string paymentDocumentId; + + /// + /// GUID платежного документа + /// + public string paymentDocumentGUID; + } +} diff --git a/Hcs.Client/Client/Api/PaymentsApi.cs b/Hcs.Client/Client/Api/PaymentsApi.cs index ec114bb..3e4814f 100644 --- a/Hcs.Client/Client/Api/PaymentsApi.cs +++ b/Hcs.Client/Client/Api/PaymentsApi.cs @@ -8,6 +8,18 @@ namespace Hcs.Client.Api // http://open-gkh.ru/PaymentsServiceAsync/ public class PaymentsApi(ClientBase client) : ApiBase(client) { + /// + /// ВИ_ОПЛАТА_ИЗВ. Передать перечень документов "Извещение о принятии к исполнению распоряжения". + /// + /// Пейлоад документа + /// Токен отмены + /// true, если операция выполнена успешно, иначе - false + public async Task ImportNotificationsOfOrderExecutionAsync(ImportNotificationsOfOrderExecutionPayload payload, CancellationToken token = default) + { + var request = new ImportNotificationsOfOrderExecutionRequest(client); + return await request.ExecuteAsync(payload, token); + } + /// /// Импорт пакета документов "Извещение о принятии к исполнению распоряжения", размещаемых исполнителем /// diff --git a/Hcs.Client/Client/Api/Request/Payments/ImportNotificationsOfOrderExecutionRequest.cs b/Hcs.Client/Client/Api/Request/Payments/ImportNotificationsOfOrderExecutionRequest.cs new file mode 100644 index 0000000..4ef77d8 --- /dev/null +++ b/Hcs.Client/Client/Api/Request/Payments/ImportNotificationsOfOrderExecutionRequest.cs @@ -0,0 +1,112 @@ +using Hcs.Client.Api.Payload.Payments; +using Hcs.Client.Api.Request.Exception; +using Hcs.Client.Internal; +using Hcs.Service.Async.Payments; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Hcs.Client.Api.Request.Payments +{ + internal class ImportNotificationsOfOrderExecutionRequest(ClientBase client) : PaymentsRequestBase(client) + { + protected override bool CanBeRestarted => false; + + internal async Task ExecuteAsync(ImportNotificationsOfOrderExecutionPayload payload, CancellationToken token) + { + ThrowIfPayloadIncorrect(payload); + + // http://open-gkh.ru/Payment/importNotificationsOfOrderExecutionRequest.html + var request = new importNotificationsOfOrderExecutionRequest + { + Id = Constants.SIGNED_XML_ELEMENT_ID, + version = "10.0.1.1", + Items = [GetNotificationFromPayload(payload)] + }; + + var result = await SendAndWaitResultAsync(request, async asyncClient => + { + var response = await asyncClient.importNotificationsOfOrderExecutionAsync(CreateRequestHeader(), request); + return response.AckRequest.Ack; + }, token); + + result.Items.OfType().ToList().ForEach(error => + { + throw RemoteException.CreateNew(error.ErrorCode, error.Description); + }); + + result.Items.OfType().ToList().ForEach(commonResult => + { + commonResult.Items.OfType().ToList().ForEach(error => + { + throw RemoteException.CreateNew(error.ErrorCode, error.Description); + }); + }); + + return true; + } + + private void ThrowIfPayloadIncorrect(ImportNotificationsOfOrderExecutionPayload payload) + { + if (string.IsNullOrEmpty(payload.orderId)) + { + throw new ArgumentException($"{nameof(payload.orderId)} is empty"); + } + + if (payload.month.HasValue && !payload.year.HasValue) + { + throw new ArgumentException($"{nameof(payload.month)} has value but {nameof(payload.year)} has not"); + } + + if (!payload.month.HasValue && payload.year.HasValue) + { + throw new ArgumentException($"{nameof(payload.year)} has value but {nameof(payload.month)} has not"); + } + + if (string.IsNullOrEmpty(payload.paymentDocumentId)) + { + throw new ArgumentException($"{nameof(payload.paymentDocumentId)} is empty"); + } + + if (string.IsNullOrEmpty(payload.paymentDocumentGUID)) + { + throw new ArgumentException($"{nameof(payload.paymentDocumentGUID)} is empty"); + } + } + + private importNotificationsOfOrderExecutionRequestNotificationOfOrderExecution139Type GetNotificationFromPayload(ImportNotificationsOfOrderExecutionPayload payload) + { + var notification = new importNotificationsOfOrderExecutionRequestNotificationOfOrderExecution139Type() + { + TransportGUID = Guid.NewGuid().ToString(), + OrderInfo = new NotificationOfOrderExecution139TypeOrderInfo() + { + OrderID = payload.orderId, + OrderDate = payload.orderDate, + Amount = payload.amount, + // TODO: Проверить, возможно можно предоставить только один из двух параметров + Items = [payload.paymentDocumentId, payload.paymentDocumentGUID], + ItemsElementName = [ItemsChoiceType4.PaymentDocumentID, ItemsChoiceType4.PaymentDocumentGUID] + } + }; + + if (payload.onlinePayment.HasValue && payload.onlinePayment.Value) + { + notification.OrderInfo.OnlinePayment = true; + notification.OrderInfo.OnlinePaymentSpecified = true; + } + + if (payload.month.HasValue) + { + notification.OrderInfo.MonthAndYear = new NotificationOfOrderExecution139TypeOrderInfoMonthAndYear() + { + Year = payload.year.Value, + Month = payload.month.Value + }; + } + + return notification; + } + } +} diff --git a/Hcs.Client/Hcs.Client.csproj b/Hcs.Client/Hcs.Client.csproj index 854af73..1da3804 100644 --- a/Hcs.Client/Hcs.Client.csproj +++ b/Hcs.Client/Hcs.Client.csproj @@ -79,6 +79,7 @@ + @@ -129,6 +130,7 @@ + diff --git a/Hcs.TestApp/TestApp/Program.cs b/Hcs.TestApp/TestApp/Program.cs index d655950..4b36cb7 100644 --- a/Hcs.TestApp/TestApp/Program.cs +++ b/Hcs.TestApp/TestApp/Program.cs @@ -80,6 +80,7 @@ namespace Hcs.TestApp //orgRegistryCommonScenario.ExportDataProvider(); //orgRegistryCommonScenario.ExportOrgRegistry(); + //paymentsScenario.ImportNotificationsOfOrderExecution(); //paymentsScenario.ImportSupplierNotificationsOfOrderExecution(); } catch (Exception e) diff --git a/Hcs.TestApp/TestApp/Scenario/PaymentsScenario.cs b/Hcs.TestApp/TestApp/Scenario/PaymentsScenario.cs index 3757127..1131a38 100644 --- a/Hcs.TestApp/TestApp/Scenario/PaymentsScenario.cs +++ b/Hcs.TestApp/TestApp/Scenario/PaymentsScenario.cs @@ -8,6 +8,26 @@ namespace Hcs.TestApp.Scenario { private readonly UniClient client = client; + internal void ImportNotificationsOfOrderExecution() + { + var payload = new ImportNotificationsOfOrderExecutionPayload() + { + // TODO: Разобраться, что это за айди + orderId = "", + orderDate = new DateTime(2025, 9, 5), + amount = 4000M, + onlinePayment = true, + year = 2025, + month = 8, + paymentDocumentId = "00АА095186-02-5081", + // TODO: Возможно что не обязательно передавать оба параметра + paymentDocumentGUID = "" + }; + + var result = client.Payments.ImportNotificationsOfOrderExecutionAsync(payload).Result; + Console.WriteLine("Scenario execution " + (result ? "succeeded" : "failed")); + } + internal void ImportSupplierNotificationsOfOrderExecution() { var payload = new ImportSupplierNotificationsOfOrderExecutionPayload()