Add project
Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
This commit is contained in:
106
Hcs.Client/ClientApi/DebtRequestsApi/HcsDebtRequestsApi.cs
Normal file
106
Hcs.Client/ClientApi/DebtRequestsApi/HcsDebtRequestsApi.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hcs.ClientApi.DebtRequestsApi
|
||||
{
|
||||
public class HcsDebtRequestsApi
|
||||
{
|
||||
private HcsClientConfig config;
|
||||
|
||||
public HcsDebtRequestsApi(HcsClientConfig config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public async Task<HcsDebtSubrequest> ExportDSRByRequestNumber(
|
||||
string requestNumber, CancellationToken token = default)
|
||||
{
|
||||
var worker = new HcsDebtSubrequestExporter(config);
|
||||
return await worker.ExportDSRByRequestNumber(requestNumber, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение списка запросов о наличии задолженности направленных в данный период
|
||||
/// </summary>
|
||||
public async Task<int> ExportDSRsByPeriodOfSending(
|
||||
DateTime startDate,
|
||||
DateTime endDate,
|
||||
Guid? firstSubrequestGuid,
|
||||
Action<HcsDebtSubrequest> resultHandler,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var worker = new HcsDebtSubrequestExporter(config);
|
||||
return await worker.ExportDSRsByPeriodOfSending(
|
||||
startDate, endDate, firstSubrequestGuid, resultHandler, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправка пакета ответов на запросы о наличии задолженности
|
||||
/// </summary>
|
||||
public async Task<int> ImportDSRsResponsesAsOneBatch(
|
||||
HcsDebtResponse[] responses,
|
||||
Action<HcsDebtResponse, HcsDebtResponseResult> resultHandler,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var worker = new HcsDebtResponseImporter(config);
|
||||
var results = await worker.ImportDSRResponses(responses, token);
|
||||
|
||||
foreach (var response in responses)
|
||||
{
|
||||
var result = results.FirstOrDefault(
|
||||
x => x.SubrequestGuid == response.SubrequestGuid &&
|
||||
x.TransportGuid == response.TransportGuid);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
result = new HcsDebtResponseResult();
|
||||
result.TransportGuid = response.TransportGuid;
|
||||
result.SubrequestGuid = response.SubrequestGuid;
|
||||
result.Error = new HcsException(
|
||||
$"В пакете результатов приема ответов нет" +
|
||||
$" результата для подзапроса {response.SubrequestGuid}");
|
||||
}
|
||||
|
||||
resultHandler(response, result);
|
||||
}
|
||||
|
||||
return responses.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправка ответов на запросы о наличии задолженности для списков любой длины
|
||||
/// </summary>
|
||||
public async Task<int> ImportDSRsResponses(
|
||||
HcsDebtResponse[] responses,
|
||||
Action<HcsDebtResponse, HcsDebtResponseResult> resultHandler,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
int chunkSize = 20;
|
||||
int i = 0;
|
||||
HcsDebtResponse[][] chunks =
|
||||
responses.GroupBy(s => i++ / chunkSize).Select(g => g.ToArray()).ToArray();
|
||||
|
||||
int n = 0;
|
||||
foreach (var chunk in chunks)
|
||||
{
|
||||
n += await ImportDSRsResponsesAsOneBatch(chunk, resultHandler, token);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправка ответа на один запрос о наличии задолженности
|
||||
/// </summary>
|
||||
public async Task<HcsDebtResponseResult> ImportDSRResponse(
|
||||
HcsDebtResponse response, CancellationToken token = default)
|
||||
{
|
||||
HcsDebtResponse[] array = { response };
|
||||
HcsDebtResponseResult result = null;
|
||||
await ImportDSRsResponses(array, (x, y) => result = y, token);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
135
Hcs.Client/ClientApi/DebtRequestsApi/HcsDebtRequestsMethod.cs
Normal file
135
Hcs.Client/ClientApi/DebtRequestsApi/HcsDebtRequestsMethod.cs
Normal file
@ -0,0 +1,135 @@
|
||||
using Hcs.ClientApi.RemoteCaller;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DebtRequests = Hcs.Service.Async.DebtRequests.v14_5_0_1;
|
||||
|
||||
namespace Hcs.Service.Async.DebtRequests.v14_5_0_1
|
||||
{
|
||||
public partial class AckRequestAck : IHcsAck { }
|
||||
public partial class getStateResult : IHcsGetStateResult { }
|
||||
public partial class Fault : IHcsFault { }
|
||||
public partial class HeaderType : IHcsHeaderType { }
|
||||
}
|
||||
|
||||
namespace Hcs.ClientApi.DebtRequestsApi
|
||||
{
|
||||
/// Метод для отправки запросов к сервису запросов о наличии задолженности
|
||||
/// Описание: http://open-gkh.ru/DebtRequestsServiceAsync/
|
||||
public class HcsDebtRequestsMethod : HcsRemoteCallMethod
|
||||
{
|
||||
public HcsEndPoints EndPoint => HcsEndPoints.DebtRequestsAsync;
|
||||
|
||||
public HcsDebtRequestsMethod(HcsClientConfig config) : base(config)
|
||||
{
|
||||
}
|
||||
|
||||
public DebtRequests.RequestHeader CreateRequestHeader() =>
|
||||
HcsRequestHelper.CreateHeader<DebtRequests.RequestHeader>(ClientConfig);
|
||||
|
||||
public System.ServiceModel.EndpointAddress RemoteAddress
|
||||
=> GetEndpointAddress(HcsConstants.EndPointLocator.GetPath(EndPoint));
|
||||
|
||||
private DebtRequests.DebtRequestsAsyncPortClient NewPortClient()
|
||||
{
|
||||
var client = new DebtRequests.DebtRequestsAsyncPortClient(_binding, RemoteAddress);
|
||||
ConfigureEndpointCredentials(client.Endpoint, client.ClientCredentials);
|
||||
return client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Метод отправления запроса
|
||||
/// </summary>
|
||||
public async Task<IHcsAck> SendAsync(object request, CancellationToken token)
|
||||
{
|
||||
Func<Task<IHcsAck>> func = async () => await SendBareAsync(request);
|
||||
return await RunRepeatableTaskInsistentlyAsync(func, token);
|
||||
}
|
||||
|
||||
private async Task<IHcsAck> SendBareAsync(object request)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException("Null request");
|
||||
string version = HcsRequestHelper.GetRequestVersionString(request);
|
||||
_config.Log($"Отправляю {RemoteAddress.Uri}/{request.GetType().Name}" +
|
||||
$" в версии {version} {ThreadIdText}...");
|
||||
|
||||
IHcsAck ack;
|
||||
using (var client = NewPortClient())
|
||||
{
|
||||
switch (request)
|
||||
{
|
||||
|
||||
case DebtRequests.exportDebtSubrequestsRequest x:
|
||||
{
|
||||
var response = await client.exportDebtSubrequestsAsync(x.RequestHeader, x.exportDSRsRequest);
|
||||
ack = response.AckRequest.Ack;
|
||||
break;
|
||||
}
|
||||
|
||||
case DebtRequests.importResponsesRequest x:
|
||||
{
|
||||
var response = await client.importResponsesAsync(x.RequestHeader, x.importDSRResponsesRequest);
|
||||
ack = response.AckRequest.Ack;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new HcsException($"Неизвестный тип запроса: {request.GetType().Name}");
|
||||
}
|
||||
}
|
||||
|
||||
_config.Log($"Запрос принят в обработку, подтверждение {ack.MessageGUID}");
|
||||
return ack;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполняет однократную проверку наличия результата.
|
||||
/// Возвращает null если результата еще нет.
|
||||
/// </summary>
|
||||
protected override async Task<IHcsGetStateResult> TryGetResultAsync(
|
||||
IHcsAck sourceAck, CancellationToken token = default)
|
||||
{
|
||||
Func<Task<IHcsGetStateResult>> func = async () => await TryGetResultBareAsync(sourceAck);
|
||||
return await RunRepeatableTaskInsistentlyAsync(func, token);
|
||||
}
|
||||
|
||||
private async Task<IHcsGetStateResult> TryGetResultBareAsync(IHcsAck sourceAck)
|
||||
{
|
||||
using (var client = NewPortClient())
|
||||
{
|
||||
var requestHeader = HcsRequestHelper.CreateHeader<DebtRequests.RequestHeader>(_config);
|
||||
var requestBody = new DebtRequests.getStateRequest { MessageGUID = sourceAck.MessageGUID };
|
||||
|
||||
var response = await client.getStateAsync(requestHeader, requestBody);
|
||||
var resultBody = response.getStateResult;
|
||||
|
||||
if (resultBody.RequestState == HcsAsyncRequestStateTypes.Ready)
|
||||
{
|
||||
CheckResultForErrors(resultBody);
|
||||
return resultBody;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckResultForErrors(IHcsGetStateResult result)
|
||||
{
|
||||
if (result == null) throw new HcsException("Пустой result");
|
||||
|
||||
if (result.Items == null) throw new HcsException("Пустой result.Items");
|
||||
|
||||
result.Items.OfType<DebtRequests.Fault>().ToList().ForEach(x =>
|
||||
{
|
||||
throw HcsRemoteException.CreateNew(x.ErrorCode, x.ErrorMessage);
|
||||
});
|
||||
|
||||
result.Items.OfType<DebtRequests.ErrorMessageType>().ToList().ForEach(x =>
|
||||
{
|
||||
throw HcsRemoteException.CreateNew(x.ErrorCode, x.Description);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
40
Hcs.Client/ClientApi/DebtRequestsApi/HcsDebtResponse.cs
Normal file
40
Hcs.Client/ClientApi/DebtRequestsApi/HcsDebtResponse.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi.DebtRequestsApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Ответ на запрос о наличии задолженности
|
||||
/// </summary>
|
||||
public class HcsDebtResponse
|
||||
{
|
||||
// Добавить в XML-описание
|
||||
public Guid TransportGuid; // Идентификатор ответа в отправляющей системе
|
||||
public Guid SubrequestGuid; // Идентификатор подзапроса
|
||||
public bool HasDebt;
|
||||
public HcsPersonalData[] PersonalData;
|
||||
public string Description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сведения о должнике
|
||||
/// </summary>
|
||||
public class HcsPersonalData
|
||||
{
|
||||
public string FirstName;
|
||||
public string MiddleName;
|
||||
public string LastName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Результат отправки ответа на запрос о наличии задолженности
|
||||
/// </summary>
|
||||
public class HcsDebtResponseResult
|
||||
{
|
||||
// Добавить в XML-описание
|
||||
public Guid TransportGuid; // Идентификатор ответа в отправляющей системе
|
||||
public Guid SubrequestGuid; // Идентификатор подзапроса
|
||||
public Exception Error; // Ожибка отправки если указано
|
||||
public DateTime UpdateDate; // Дата успешного приема ответа если не указана ошибка
|
||||
public bool HasError => (Error != null);
|
||||
}
|
||||
}
|
||||
141
Hcs.Client/ClientApi/DebtRequestsApi/HcsDebtResponseImporter.cs
Normal file
141
Hcs.Client/ClientApi/DebtRequestsApi/HcsDebtResponseImporter.cs
Normal file
@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DebtRequests = Hcs.Service.Async.DebtRequests.v14_5_0_1;
|
||||
|
||||
namespace Hcs.ClientApi.DebtRequestsApi
|
||||
{
|
||||
public class HcsDebtResponseImporter : HcsDebtRequestsMethod
|
||||
{
|
||||
public HcsDebtResponseImporter(HcsClientConfig config) : base(config)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<HcsDebtResponseResult[]> ImportDSRResponses(
|
||||
HcsDebtResponse[] debtResponses, CancellationToken token = default)
|
||||
{
|
||||
if (debtResponses == null || debtResponses.Length == 0)
|
||||
throw new ArgumentException("Пустой debtResponses");
|
||||
|
||||
var actions = debtResponses.Select(x => ConvertToImportAction(x)).ToArray();
|
||||
|
||||
var requestHeader = CreateRequestHeader();
|
||||
var requestBody = new DebtRequests.importDSRResponsesRequest
|
||||
{
|
||||
Id = HcsConstants.SignedXmlElementId,
|
||||
// TODO: Проверить комментарий
|
||||
// Версия предустановлена в WSDL, реальная версия шаблонов дает ошибку "Bad Request"
|
||||
//version = HcsConstants.DefaultHCSVersionString,
|
||||
action = actions
|
||||
};
|
||||
|
||||
var request = new DebtRequests.importResponsesRequest
|
||||
{
|
||||
RequestHeader = requestHeader,
|
||||
importDSRResponsesRequest = requestBody
|
||||
};
|
||||
|
||||
var ack = await SendAsync(request, token);
|
||||
var result = await WaitForResultAsync(ack, true, token);
|
||||
|
||||
var responseResults = result.Items.Select(
|
||||
x => ParseDebtResponseResultSafely(x)).ToArray();
|
||||
|
||||
if (debtResponses.Length != responseResults.Length)
|
||||
throw new HcsException(
|
||||
$"Количество направленных ответов {debtResponses.Length} не совпадает" +
|
||||
$" с количеством {responseResults.Length} результатов обработки");
|
||||
|
||||
foreach (var response in debtResponses)
|
||||
{
|
||||
var found = responseResults.FirstOrDefault(x => x.TransportGuid == response.TransportGuid);
|
||||
if (found != null) found.SubrequestGuid = response.SubrequestGuid;
|
||||
}
|
||||
|
||||
return responseResults;
|
||||
}
|
||||
|
||||
private DebtRequests.importDSRResponsesRequestAction ConvertToImportAction(
|
||||
HcsDebtResponse source)
|
||||
{
|
||||
DebtRequests.DebtInfoType[] debtInfo = null;
|
||||
if (source.HasDebt)
|
||||
{
|
||||
if (IsArrayEmpty(source.PersonalData)) throw new HcsException("Не указаны должники");
|
||||
debtInfo = source.PersonalData.Select(x => new DebtRequests.DebtInfoType
|
||||
{
|
||||
person = new DebtRequests.DebtInfoTypePerson
|
||||
{
|
||||
firstName = x.FirstName,
|
||||
lastName = x.LastName,
|
||||
middleName = x.MiddleName
|
||||
}
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
var responseData = new DebtRequests.ImportDSRResponseType()
|
||||
{
|
||||
hasDebt = source.HasDebt,
|
||||
description = source.Description,
|
||||
Items = debtInfo,
|
||||
// TODO: Проверить комментарий
|
||||
//debtInfo = debtInfo, // Так было в hcs-v13
|
||||
executorGUID = ClientConfig.ExecutorGUID
|
||||
};
|
||||
|
||||
return new DebtRequests.importDSRResponsesRequestAction()
|
||||
{
|
||||
subrequestGUID = source.SubrequestGuid.ToString(),
|
||||
TransportGUID = source.TransportGuid.ToString(),
|
||||
actionType = DebtRequests.DSRResponseActionType.Send,
|
||||
responseData = responseData
|
||||
};
|
||||
}
|
||||
|
||||
private HcsDebtResponseResult ParseDebtResponseResultSafely(object resultItem)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ParseDebtResponseResult(resultItem);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new HcsDebtResponseResult() { Error = e };
|
||||
}
|
||||
}
|
||||
|
||||
private HcsDebtResponseResult ParseDebtResponseResult(object resultItem)
|
||||
{
|
||||
if (resultItem == null) throw new HcsException("Пустой resultItem");
|
||||
|
||||
var common = resultItem as DebtRequests.CommonResultType;
|
||||
if (common == null) throw new HcsException($"Неожиданный тип экземпляра ответа {resultItem.GetType()}");
|
||||
|
||||
if (common.Items == null || common.Items.Length == 0)
|
||||
throw new HcsException("Пустой набор common.Items");
|
||||
|
||||
var result = new HcsDebtResponseResult();
|
||||
foreach (var commonItem in common.Items)
|
||||
{
|
||||
if (commonItem == null) throw new HcsException("Пустой commonItem");
|
||||
|
||||
switch (commonItem)
|
||||
{
|
||||
case DebtRequests.CommonResultTypeError error:
|
||||
result.Error = new HcsRemoteException(error.ErrorCode, error.Description);
|
||||
break;
|
||||
case DateTime updateDate:
|
||||
result.UpdateDate = updateDate;
|
||||
break;
|
||||
default:
|
||||
throw new HcsException($"Неожиданный тип сommonItem" + commonItem.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
result.TransportGuid = ParseGuid(common.TransportGUID);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Hcs.Client/ClientApi/DebtRequestsApi/HcsDebtSubrequest.cs
Normal file
39
Hcs.Client/ClientApi/DebtRequestsApi/HcsDebtSubrequest.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi.DebtRequestsApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Подзапрос о наличии задолженности за ЖКУ у организаци предоставляющей ЖКУ.
|
||||
/// В терминологии ГИСЖКХ это называется Subrequests, потому что сама ГИСЖКХ выбирает организации,
|
||||
/// которым (пере)направляется оригинальный запрос о наличии задолженности направленный его источником
|
||||
/// в ГИСЖКХ.
|
||||
/// </summary>
|
||||
public class HcsDebtSubrequest
|
||||
{
|
||||
public enum ResponseStatusType { Sent, NotSent, AutoGenerated }
|
||||
|
||||
// TODO: Добавить XML-описания
|
||||
public Guid SubrequestGuid; // Идентификатор подзапроса направленный конкретному поставщику ЖКУ
|
||||
public Guid RequestGuid; // Идентификатор первичного запроса направленного соццентром всем поставщикам
|
||||
public string RequestNumber; // Номер запроса
|
||||
public DateTime SentDate; // Дата направления
|
||||
public string Address; // Строка адреса из запроса
|
||||
public Guid FiasHouseGuid; // Идентификатор здания в ФИАС
|
||||
public Guid GisHouseGuid; // Идентификатор здания в ГИСЖКХ
|
||||
public Guid HМObjectGuid; // Идентификатор помещения в ГИСЖКХ (v14)
|
||||
public string HMObjectType; // Тип помещения (v14)
|
||||
public string AddressDetails; // Номер помещения (не заполняется в v14)
|
||||
public DateTime DebtStartDate; // Начало периода задолженности
|
||||
public DateTime DebtEndDate; // Конец периода задолженности
|
||||
public ResponseStatusType ResponseStatus; // Признак отправления запроса
|
||||
public DateTime ResponseDate; // Дата ответа
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$"ПодзапросОНЗ #{RequestNumber}" +
|
||||
$" Address=[{Address}] Details=[{AddressDetails}]" +
|
||||
$" HMO={HМObjectGuid} Sent={SentDate} ResponseStatus={ResponseStatus}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,251 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DebtRequests = Hcs.Service.Async.DebtRequests.v14_5_0_1;
|
||||
|
||||
namespace Hcs.ClientApi.DebtRequestsApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Метод получения данных о направленных нам (под)запросах о наличии задолженности
|
||||
/// </summary>
|
||||
public class HcsDebtSubrequestExporter : HcsDebtRequestsMethod
|
||||
{
|
||||
public HcsDebtSubrequestExporter(HcsClientConfig config) : base(config)
|
||||
{
|
||||
EnableMinimalResponseWaitDelay = true;
|
||||
}
|
||||
|
||||
public class DSRsBatch
|
||||
{
|
||||
public List<HcsDebtSubrequest> DebtSubrequests = new List<HcsDebtSubrequest>();
|
||||
public Guid NextSubrequestGuid;
|
||||
public bool LastPage;
|
||||
}
|
||||
|
||||
public async Task<HcsDebtSubrequest> ExportDSRByRequestNumber(string requestNumber, CancellationToken token)
|
||||
{
|
||||
var conditionTypes = new List<DebtRequests.ItemsChoiceType5>();
|
||||
var conditionValues = new List<object>();
|
||||
|
||||
conditionTypes.Add(DebtRequests.ItemsChoiceType5.requestNumber);
|
||||
conditionValues.Add(requestNumber);
|
||||
|
||||
var result = await ExportSubrequestBatchByCondition(
|
||||
conditionTypes.ToArray(), conditionValues.ToArray(), token);
|
||||
|
||||
int n = result.DebtSubrequests.Count;
|
||||
if (n == 0) return null;
|
||||
if (n == 1) return result.DebtSubrequests[0];
|
||||
throw new HcsException(
|
||||
$"По номеру запроса о наличии задолженности №{requestNumber}" +
|
||||
$" получено несколько ({n}) ответов, ожидался только один");
|
||||
}
|
||||
|
||||
public async Task<int> ExportDSRsByPeriodOfSending(
|
||||
DateTime startDate, DateTime endDate, Guid? firstSubrequestGuid,
|
||||
Action<HcsDebtSubrequest> resultHandler, CancellationToken token = default)
|
||||
{
|
||||
int numResults = 0;
|
||||
Guid? nextSubrequestGuid = firstSubrequestGuid;
|
||||
bool firstGuidIsReliable = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (numResults == 0) Log("Запрашиваем первую партию записей...");
|
||||
else Log($"Запрашиваем следующую партию записей, уже получено {numResults}...");
|
||||
|
||||
var batch = await ExportDSRsBatchByPeriodOfSending(
|
||||
startDate, endDate, nextSubrequestGuid, token, firstGuidIsReliable);
|
||||
|
||||
foreach (var s in batch.DebtSubrequests)
|
||||
{
|
||||
if (resultHandler != null) resultHandler(s);
|
||||
numResults += 1;
|
||||
}
|
||||
|
||||
if (batch.LastPage) break;
|
||||
nextSubrequestGuid = batch.NextSubrequestGuid;
|
||||
firstGuidIsReliable = true;
|
||||
}
|
||||
|
||||
return numResults;
|
||||
}
|
||||
|
||||
public async Task<DSRsBatch> ExportDSRsBatchByPeriodOfSending(
|
||||
DateTime startDate, DateTime endDate, Guid? firstSubrequestGuid,
|
||||
CancellationToken token, bool firstGuidIsReliable)
|
||||
{
|
||||
var conditionTypes = new List<DebtRequests.ItemsChoiceType5>();
|
||||
var conditionValues = new List<object>();
|
||||
|
||||
conditionTypes.Add(DebtRequests.ItemsChoiceType5.periodOfSendingRequest);
|
||||
conditionValues.Add(new DebtRequests.Period() { startDate = startDate, endDate = endDate });
|
||||
|
||||
if (firstSubrequestGuid != null)
|
||||
{
|
||||
conditionTypes.Add(DebtRequests.ItemsChoiceType5.exportSubrequestGUID);
|
||||
conditionValues.Add(firstSubrequestGuid.ToString());
|
||||
}
|
||||
|
||||
Func<Task<DSRsBatch>> taskFunc = async ()
|
||||
=> await ExportSubrequestBatchByCondition(
|
||||
conditionTypes.ToArray(), conditionValues.ToArray(), token);
|
||||
|
||||
Func<Exception, bool> canIgnoreFunc = delegate (Exception e)
|
||||
{
|
||||
return CanIgnoreSuchException(e, firstGuidIsReliable);
|
||||
};
|
||||
|
||||
return await RunRepeatableTaskAsync(taskFunc, canIgnoreFunc, int.MaxValue);
|
||||
}
|
||||
|
||||
private async Task<DSRsBatch> ExportSubrequestBatchByCondition(
|
||||
DebtRequests.ItemsChoiceType5[] conditionTypes, object[] conditionValues,
|
||||
CancellationToken token)
|
||||
{
|
||||
var requestHeader = CreateRequestHeader();
|
||||
var requestBody = new DebtRequests.exportDSRsRequest
|
||||
{
|
||||
Id = HcsConstants.SignedXmlElementId,
|
||||
// TODO: Тут напрямую указывается версия
|
||||
version = "14.0.0.0",
|
||||
ItemsElementName = conditionTypes,
|
||||
Items = conditionValues
|
||||
};
|
||||
|
||||
var request = new DebtRequests.exportDebtSubrequestsRequest
|
||||
{
|
||||
RequestHeader = requestHeader,
|
||||
exportDSRsRequest = requestBody
|
||||
};
|
||||
|
||||
var ack = await SendAsync(request, token);
|
||||
|
||||
try
|
||||
{
|
||||
var result = await WaitForResultAsync(ack, true, token);
|
||||
return ParseExportResultBatch(result);
|
||||
}
|
||||
catch (HcsNoResultsRemoteException)
|
||||
{
|
||||
return new DSRsBatch() { LastPage = true };
|
||||
}
|
||||
}
|
||||
|
||||
private DSRsBatch ParseExportResultBatch(RemoteCaller.IHcsGetStateResult result)
|
||||
{
|
||||
var batch = new DSRsBatch();
|
||||
|
||||
result.Items.OfType<DebtRequests.exportDSRsResultType>().ToList().ForEach(r =>
|
||||
{
|
||||
Log($"Принято запросов о наличии задолженности: {r.subrequestData?.Count()}");
|
||||
|
||||
// на последней странице вывода может не быть ни одной записи
|
||||
if (r.subrequestData != null)
|
||||
{
|
||||
r.subrequestData.ToList().ForEach(s => { batch.DebtSubrequests.Add(Adapt(s)); });
|
||||
}
|
||||
|
||||
if (r.pagedOutput == null || r.pagedOutput.Item == null) batch.LastPage = true;
|
||||
else
|
||||
{
|
||||
var item = r.pagedOutput.Item;
|
||||
if (item is bool && (bool)item == true) batch.LastPage = true;
|
||||
else if (!Guid.TryParse(item.ToString(), out batch.NextSubrequestGuid))
|
||||
throw new HcsException($"Неожиданное значение pagedOutput [{item}]");
|
||||
}
|
||||
});
|
||||
|
||||
return batch;
|
||||
}
|
||||
|
||||
private HcsDebtSubrequest Adapt(DebtRequests.DSRType s)
|
||||
{
|
||||
var dsr = new HcsDebtSubrequest();
|
||||
dsr.SubrequestGuid = ParseGuid(s.subrequestGUID);
|
||||
dsr.RequestGuid = ParseGuid(s.requestInfo.requestGUID);
|
||||
dsr.RequestNumber = s.requestInfo.requestNumber;
|
||||
dsr.SentDate = s.requestInfo.sentDate;
|
||||
dsr.Address = s.requestInfo.housingFundObject.address;
|
||||
|
||||
var hfo = s.requestInfo.housingFundObject;
|
||||
if (hfo.Items != null &&
|
||||
hfo.ItemsElementName != null &&
|
||||
hfo.Items.Length == hfo.ItemsElementName.Length)
|
||||
{
|
||||
|
||||
for (int i = 0; i < hfo.Items.Length; i++)
|
||||
{
|
||||
string itemValue = hfo.Items[i];
|
||||
switch (hfo.ItemsElementName[i])
|
||||
{
|
||||
case DebtRequests.ItemsChoiceType7.HMobjectGUID:
|
||||
dsr.HМObjectGuid = ParseGuid(itemValue);
|
||||
break;
|
||||
case DebtRequests.ItemsChoiceType7.houseGUID:
|
||||
dsr.GisHouseGuid = ParseGuid(itemValue);
|
||||
break;
|
||||
case DebtRequests.ItemsChoiceType7.adressType:
|
||||
dsr.HMObjectType = itemValue;
|
||||
break;
|
||||
case DebtRequests.ItemsChoiceType7.addressDetails:
|
||||
dsr.AddressDetails = itemValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(hfo.fiasHouseGUID))
|
||||
{
|
||||
dsr.FiasHouseGuid = ParseGuid(hfo.fiasHouseGUID);
|
||||
}
|
||||
|
||||
// TODO: Проверить комментарий
|
||||
// Из hcs-v13
|
||||
//dsr.GisHouseGuid = ParseGuid(s.requestInfo.housingFundObject.houseGUID);
|
||||
//dsr.AddressDetails = s.requestInfo.housingFundObject.addressDetails;
|
||||
|
||||
dsr.DebtStartDate = s.requestInfo.period.startDate;
|
||||
dsr.DebtEndDate = s.requestInfo.period.endDate;
|
||||
dsr.ResponseStatus = ConvertStatusType(s.responseStatus);
|
||||
dsr.ResponseDate = s.requestInfo.responseDate;
|
||||
|
||||
return dsr;
|
||||
}
|
||||
|
||||
private HcsDebtSubrequest.ResponseStatusType ConvertStatusType(DebtRequests.ResponseStatusType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DebtRequests.ResponseStatusType.Sent: return HcsDebtSubrequest.ResponseStatusType.Sent;
|
||||
case DebtRequests.ResponseStatusType.NotSent: return HcsDebtSubrequest.ResponseStatusType.NotSent;
|
||||
case DebtRequests.ResponseStatusType.AutoGenerated: return HcsDebtSubrequest.ResponseStatusType.AutoGenerated;
|
||||
default: throw new HcsException("Неизвестный статус отправки ответа: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Проверить игнорирование ошибок
|
||||
private bool CanIgnoreSuchException(Exception e, bool firstGuidIsReliable)
|
||||
{
|
||||
// "Произошла ошибка при передаче данных. Попробуйте осуществить передачу данных повторно."
|
||||
if (HcsUtil.EnumerateInnerExceptions(e).Any(
|
||||
x => x is HcsRemoteException && (x as HcsRemoteException).ErrorCode == "EXP001000"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Возникающий на больших списках отказ возобновляемый, учитывем факт что GUID был
|
||||
// получен из ГИСЖКХ и явно является надежным
|
||||
if (firstGuidIsReliable && HcsUtil.EnumerateInnerExceptions(e).Any(
|
||||
x => x.Message != null && x.Message.Contains("Error loading content: Content not found for guid:")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user