252 lines
11 KiB
C#
252 lines
11 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
|
||
using DebtRequests = Hcs.Service.Async.DebtRequests.v15_7_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;
|
||
}
|
||
}
|
||
}
|