Add project

Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
This commit is contained in:
2025-08-12 11:21:10 +09:00
parent bbcbe841a7
commit 33ab055b43
546 changed files with 176950 additions and 0 deletions

View File

@ -0,0 +1,132 @@
using Hcs.ClientApi.DataTypes;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод получения из ГИС ЖКХ полного реестра договоров ресурсоснабжения
/// и всех связанных с ними лицевых счетов и приборов учета
/// </summary>
internal class HcsContractRegistryDownloader
{
private HcsHouseManagementApi api;
internal HcsContractRegistryDownloader(HcsHouseManagementApi api)
{
this.api = api;
}
private void ThrowOperationCancelled()
{
throw new HcsException("Операция прервана пользователем");
}
/// <summary>
/// Получить все договоры РСО удовлетворяющие фильтру @фильтрДоговоров
/// с подчиненными объектами (ЛС и ПУ)
/// </summary>
internal async Task<ГисДоговорыИПриборы> ПолучитьВсеДоговорыИПриборы(
Func<ГисДоговор, bool> фильтрДоговоров, CancellationToken token)
{
// TODO: Проверить комментарий
// В процессе будет много запросов, возвращающих мало данных,
// но требующих стандартного ожидания в несколько секунд, что
// суммарно складывается в целые часы. Экспериментально установлено
// что ГИС ЖКХ способна пережить некоторую параллельность запросов
// к ней. Так, с параллельностью в 5 потоков получение данных
// по 3000 договорам РСО (70000 ПУ) длится 2,5 часа.
int числоПотоковПараллельности = 5;
var все = new ГисДоговорыИПриборы();
все.ДатаНачалаСборки = DateTime.Now;
Action<ГисДоговор> обработчикДоговора = (ГисДоговор договор) =>
{
if (фильтрДоговоров(договор)) все.ДоговорыРСО.Add(договор);
};
await api.ПолучитьДоговорыРСО(обработчикДоговора, token);
int сделаноДоговоров = 0;
Action<ГисАдресныйОбъект> обработчикАдреса = все.АдресаОбъектов.Add;
Func<ГисДоговор, Task> обработчикДоговораАдреса = async (договор) =>
{
if (token.IsCancellationRequested) ThrowOperationCancelled();
api.Config.Log($"Получаем адреса договора #{++сделаноДоговоров}/{все.ДоговорыРСО.Count()}...");
await api.ПолучитьАдресаДоговораРСО(договор, обработчикАдреса, token);
};
await HcsParallel.ForEachAsync(все.ДоговорыРСО, обработчикДоговораАдреса, числоПотоковПараллельности);
var гуидыЗданий = все.АдресаОбъектов.Select(x => x.ГуидЗданияФиас).Distinct();
int сделаноЗданий = 0;
Func<Guid, Task> обработчикЗдания = async (гуидЗдания) =>
{
if (token.IsCancellationRequested) ThrowOperationCancelled();
api.Config.Log($"Получаем помещения здания #{++сделаноЗданий}/{гуидыЗданий.Count()}...");
try
{
var здание = await api.ПолучитьЗданиеПоГуидФиас(гуидЗдания, token);
все.Здания.Add(здание);
}
catch (Exception e)
{
if (HcsRemoteException.ContainsErrorCode(e, HcsRemoteException.KnownCodes.ОтсутствуетВРеестре))
{
api.Config.Log($"Не удалось получить здание по ФИАС ГУИД {гуидЗдания}: здание отсутствует в реестре");
var здание = new ГисЗдание() { ГуидЗданияФиас = гуидЗдания };
все.Здания.Add(здание);
}
else if (HcsRemoteException.ContainsErrorCode(e, HcsRemoteException.KnownCodes.ДоступЗапрещен))
{
api.Config.Log($"Не удалось получить здание по ФИАС ГУИД {гуидЗдания}: доступ запрещен");
var здание = new ГисЗдание() { ГуидЗданияФиас = гуидЗдания };
все.Здания.Add(здание);
}
else
{
throw new HcsException($"Вложенная ошибка получения здания {гуидЗдания}", e);
}
}
};
await HcsParallel.ForEachAsync(гуидыЗданий, обработчикЗдания, числоПотоковПараллельности);
сделаноЗданий = 0;
Action<ГисЛицевойСчет> обработчикЛС = (ГисЛицевойСчет лс) =>
{
if (лс.ДействуетСейчас && все.ЭтотЛицевойСчетСвязанСДоговорами(лс))
{
все.ЛицевыеСчета.Add(лс);
}
};
Func<Guid, Task> обработчикЗданияЛС = async (гуидЗдания) =>
{
if (token.IsCancellationRequested) ThrowOperationCancelled();
api.Config.Log($"Получаем ЛС по зданию #{++сделаноЗданий}/{гуидыЗданий.Count()}...");
await api.ПолучитьЛицевыеСчетаПоЗданию(гуидЗдания, обработчикЛС, token);
};
await HcsParallel.ForEachAsync(гуидыЗданий, обработчикЗданияЛС, числоПотоковПараллельности);
сделаноЗданий = 0;
Action<ГисПриборУчета> обработчикПУ = (ГисПриборУчета прибор) =>
{
if (прибор.ЭтоАктивный && (прибор.ЭтоОДПУ || все.ЭтотПриборСвязанСЛицевымиСчетами(прибор)))
{
все.ПриборыУчета.Add(прибор);
}
};
Func<Guid, Task> обработчикЗданияПУ = async (гуидЗдания) =>
{
if (token.IsCancellationRequested) ThrowOperationCancelled();
api.Config.Log($"Получаем ПУ по зданию #{++сделаноЗданий}/{гуидыЗданий.Count()}...");
await api.ПолучитьПриборыУчетаПоЗданию(гуидЗдания, обработчикПУ, token);
};
await HcsParallel.ForEachAsync(гуидыЗданий, обработчикЗданияПУ, числоПотоковПараллельности);
все.ДатаКонцаСборки = DateTime.Now;
return все;
}
}
}

View File

@ -0,0 +1,189 @@
using Hcs.ClientApi.DataTypes;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Методы ГИС ЖКХ сервиса hcs-house-management (Договоры, ЛицевыеСчета, Приборы учета)
/// </summary>
public class HcsHouseManagementApi
{
public HcsClientConfig Config { get; private set; }
public HcsHouseManagementApi(HcsClientConfig config)
{
this.Config = config;
}
/// <summary>
/// Размещает договор и возвращает дату размещения
/// </summary>
public async Task<DateTime> РазместитьДоговор(
ГисДоговор договор, IEnumerable<ГисАдресныйОбъект> адреса, CancellationToken token = default)
{
var method = new HcsMethodImportSupplyResourceContractData(Config);
return await method.ImportContract(договор, адреса, token);
}
/// <summary>
/// Размещает лицевой счет и возвращает его ЕЛС
/// </summary>
public async Task<string> РазместитьЛицевойСчет(
ГисДоговор договор, ГисЛицевойСчет лицевойСчет, CancellationToken token = default)
{
var method = new HcsMethodImportAccountData(Config);
return await method.ImportAccount(договор, лицевойСчет, token);
}
/// <summary>
/// Размещает прибор учета и возвращает его ГУИД
/// </summary>
public async Task<Guid> РазместитьПриборУчета(
ГисПриборУчета прибор, CancellationToken token = default)
{
var method = new HcsMethodImportMeteringDeviceData(Config);
return await method.ImportMeteringDevice(прибор, token);
}
public async Task<DateTime> АрхивироватьПриборУчета(
ГисПриборУчета прибор, CancellationToken token = default)
{
var method = new HcsMethodImportMeteringDeviceData(Config);
return await method.ArchiveMeteringDevice(прибор, token);
}
public async Task<DateTime> РасторгнутьДоговор(
ГисДоговор договор, DateTime датаРасторжения, CancellationToken token = default)
{
var method = new HcsMethodImportSupplyResourceContractData(Config);
return await method.TerminateContract(договор, датаРасторжения, token);
}
public async Task<DateTime> АннулироватьДоговор(
ГисДоговор договор, string причина, CancellationToken token = default)
{
var method = new HcsMethodImportSupplyResourceContractData(Config);
return await method.AnnulContract(договор, причина, token);
}
public async Task УдалитьПроектДоговора(
ГисДоговор договор, CancellationToken token = default)
{
var method = new HcsMethodImportSupplyResourceContractProject(Config);
await method.DeleteContractProject(договор, token);
}
/// <summary>
/// Переводит проект договора в состояние "Размещен"
/// </summary>
public async Task РазместитьПроектДоговора(
ГисДоговор договор, CancellationToken token = default)
{
var method = new HcsMethodImportSupplyResourceContractProject(Config);
await method.PlaceContractProject(договор, token);
}
/// <summary>
/// Получение одного договора ресурсоснабжения по его ГУИД.
/// Если такого договора нет, будет выброшено HcsNoResultsRemoteException.
/// </summary>
public async Task<ГисДоговор> ПолучитьДоговорРСО(
Guid гуидДоговора, CancellationToken token = default)
{
var method = new HcsMethodExportSupplyResourceContractData(Config);
method.EnableMinimalResponseWaitDelay = true;
return await method.QueryOne(гуидДоговора, token);
}
/// <summary>
/// Получение одного договора ресурсоснабжения по его номеру.
/// Если такого договора нет, будет выброшено HcsNoResultsRemoteException.
/// </summary>
public async Task<ГисДоговор[]> ПолучитьДоговорыРСО(
string номерДоговора, CancellationToken token = default)
{
var method = new HcsMethodExportSupplyResourceContractData(Config);
method.EnableMinimalResponseWaitDelay = true;
return await method.QueryByContractNumber(номерДоговора, token);
}
/// <summary>
/// Получение списка договоров ресурсоснабжения
/// </summary>
public async Task<int> ПолучитьДоговорыРСО(
Action<ГисДоговор> resultHandler, CancellationToken token = default)
{
var method = new HcsMethodExportSupplyResourceContractData(Config);
return await method.QueryAll(resultHandler, token);
}
/// <summary>
/// Запрос на экспорт объектов жилищного фонда из договора ресурсоснабжения
/// </summary>
public async Task<int> ПолучитьАдресаДоговораРСО(
ГисДоговор договор, Action<ГисАдресныйОбъект> resultHandler, CancellationToken token = default)
{
var method = new HcsMethodExportSupplyResourceContractObjectAddress(Config);
return await method.QueryAddresses(договор, resultHandler, token);
}
/// <summary>
/// Размещение изменения списка адресных объектов в договоре
/// </summary>
public async Task РазместитьАдресаДоговораРСО(
ГисДоговор договор,
IEnumerable<ГисАдресныйОбъект> адресаДляРазмещения,
IEnumerable<ГисАдресныйОбъект> адресаДляУдаления,
CancellationToken token)
{
var method = new HcsMethodImportSupplyResourceContractObjectAddress(Config);
await method.ImportObjectAddresses(договор, адресаДляРазмещения, адресаДляУдаления, token);
}
/// <summary>
/// Получение списка лицевых счетов для одного здания
/// </summary>
public async Task<int> ПолучитьЛицевыеСчетаПоЗданию(
Guid fiasHouseGuid, Action<ГисЛицевойСчет> resultHandler, CancellationToken token = default)
{
var method = new HcsMethodExportAccountData(Config);
return await method.Query(fiasHouseGuid, null, resultHandler, token);
}
/// <summary>
/// Получение списка приборов учета для одного здания
/// </summary>
public async Task<int> ПолучитьПриборыУчетаПоЗданию(
Guid fiasHouseGuid, Action<ГисПриборУчета> resultHandler, CancellationToken token = default)
{
var method = new HcsMethodExportMeteringDeviceData(Config);
return await method.ExportByHouse(fiasHouseGuid, resultHandler, token);
}
/// <summary>
/// Пример получения данных об одном здании по его идентификатору в ФИАС
/// </summary>
public async Task<ГисЗдание> ПолучитьЗданиеПоГуидФиас(Guid fiasHouseGuid, CancellationToken token = default)
{
try
{
var method = new HcsMethodExportHouse(Config);
return await method.ExportHouseByFiasGuid(fiasHouseGuid, token);
}
catch (HcsException e)
{
throw new HcsException($"Не удалось получить здание по ФИАС GUID {fiasHouseGuid}", e);
}
}
public async Task<ГисДоговорыИПриборы> ПолучитьВсеДоговорыИПриборы(
Func<ГисДоговор, bool> contractFilter, CancellationToken token = default)
{
return await (new HcsContractRegistryDownloader(this))
.ПолучитьВсеДоговорыИПриборы(contractFilter, token);
}
}
}

View File

@ -0,0 +1,162 @@
using Hcs.ClientApi.RemoteCaller;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.Service.Async.HouseManagement.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.HouseManagementApi
{
public class HcsHouseManagementMethod : HcsRemoteCallMethod
{
public HcsEndPoints EndPoint => HcsEndPoints.HomeManagementAsync;
public HouseManagement.RequestHeader CreateRequestHeader() =>
HcsRequestHelper.CreateHeader<HouseManagement.RequestHeader>(ClientConfig);
public HcsHouseManagementMethod(HcsClientConfig config) : base(config) { }
public System.ServiceModel.EndpointAddress RemoteAddress
=> GetEndpointAddress(HcsConstants.EndPointLocator.GetPath(EndPoint));
private HouseManagement.HouseManagementPortsTypeAsyncClient NewPortClient()
{
var client = new HouseManagement.HouseManagementPortsTypeAsyncClient(_binding, RemoteAddress);
ConfigureEndpointCredentials(client.Endpoint, client.ClientCredentials);
return client;
}
public async Task<IHcsGetStateResult> SendAndWaitResultAsync(
object request,
Func<HouseManagement.HouseManagementPortsTypeAsyncClient, Task<IHcsAck>> sender,
CancellationToken token)
{
while (true)
{
token.ThrowIfCancellationRequested();
try
{
if (CanBeRestarted)
{
return await RunRepeatableTaskInsistentlyAsync(
async () => await SendAndWaitResultAsyncImpl(request, sender, token), token);
}
else
{
return await SendAndWaitResultAsyncImpl(request, sender, token);
}
}
catch (HcsRestartTimeoutException e)
{
if (!CanBeRestarted) throw new HcsException("Превышен лимит ожидания выполнения запроса", e);
Log($"Перезапускаем запрос типа {request.GetType().Name}...");
}
}
}
private async Task<IHcsGetStateResult> SendAndWaitResultAsyncImpl(
object request,
Func<HouseManagement.HouseManagementPortsTypeAsyncClient, Task<IHcsAck>> sender,
CancellationToken token)
{
if (request == null) throw new ArgumentNullException(nameof(request));
string version = HcsRequestHelper.GetRequestVersionString(request);
_config.Log($"Отправляем запрос: {RemoteAddress.Uri}/{request.GetType().Name} в версии {version}...");
var stopWatch = System.Diagnostics.Stopwatch.StartNew();
IHcsAck ack;
using (var client = NewPortClient())
{
ack = await sender(client);
}
stopWatch.Stop();
_config.Log($"Запрос принят в обработку за {stopWatch.ElapsedMilliseconds}мс., подтверждение {ack.MessageGUID}");
var stateResult = await WaitForResultAsync(ack, true, token);
stateResult.Items.OfType<HouseManagement.ErrorMessageType>().ToList().ForEach(x =>
{
throw HcsRemoteException.CreateNew(x.ErrorCode, x.Description);
});
return stateResult;
}
/// <summary>
/// Выполняет однократную проверку наличия результата.
/// Возвращает null если результата еще нет.
/// </summary>
protected override async Task<IHcsGetStateResult> TryGetResultAsync(IHcsAck sourceAck, CancellationToken token)
{
using (var client = NewPortClient())
{
var requestHeader = HcsRequestHelper.CreateHeader<HouseManagement.RequestHeader>(_config);
var requestBody = new HouseManagement.getStateRequest { MessageGUID = sourceAck.MessageGUID };
var response = await client.getStateAsync(requestHeader, requestBody);
var resultBody = response.getStateResult;
if (resultBody.RequestState == HcsAsyncRequestStateTypes.Ready)
{
return resultBody;
}
return null;
}
}
/// <summary>
/// Разбирает стандартный ответ HCS на операцию импорта с приемом ошибок
/// </summary>
protected HouseManagement.getStateResultImportResultCommonResult ParseSingleImportResult(IHcsGetStateResult stateResult)
{
return ParseImportResults(stateResult, 1, true).First();
}
/// <summary>
/// Разбирает стандартный ответ HCS на операцию импорта с приемом ошибок
/// </summary>
protected HouseManagement.getStateResultImportResultCommonResult[] ParseImportResults(
IHcsGetStateResult stateResult, int commonResultRequiredCount, bool checkItemErrors)
{
var importResult = RequireSingleItem<HouseManagement.getStateResultImportResult>(stateResult.Items);
if (IsArrayEmpty(importResult.Items)) throw new HcsException("Пустой ImportResult.Items");
importResult.Items.OfType<HouseManagement.ErrorMessageType>().ToList()
.ForEach(error => { throw HcsRemoteException.CreateNew(error.ErrorCode, error.Description); });
var commonResults = importResult.Items.OfType<HouseManagement.getStateResultImportResultCommonResult>();
foreach (var commonResult in commonResults)
{
if (IsArrayEmpty(commonResult.Items)) throw new HcsException("Пустой CommonResult.Items");
if (checkItemErrors) CheckCommonResultErrors(commonResult);
}
if (commonResults.Count() != commonResultRequiredCount)
{
throw new HcsException(
$"Число результатов {commonResults.Count()} типа CommonResult не равно {commonResultRequiredCount}");
}
return commonResults.ToArray();
}
protected void CheckCommonResultErrors(HouseManagement.getStateResultImportResultCommonResult commonResult)
{
commonResult.Items.OfType<HouseManagement.CommonResultTypeError>().ToList()
.ForEach(error => { throw HcsRemoteException.CreateNew(error.ErrorCode, error.Description); });
}
}
}

View File

@ -0,0 +1,90 @@
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Методы и константы для работы с номенклатурно-справочной информацией (НСИ)
/// применяемой в сервисе hcs-house-management
/// https://my.dom.gosuslugi.ru/#!/open-data
/// </summary>
public class HcsHouseManagementNsi
{
// Ссылка на НСИ "54 Причина расторжения договора" (реестровый номер 54)
// https://my.dom.gosuslugi.ru/#!/open-data-passport?passportName=7710474375-nsi-54
public class ПричинаРасторженияДоговора
{
public static HouseManagement.nsiRef ПоВзаимномуСогласиюСторон => new HouseManagement.nsiRef()
{
Name = "По взаимному согласию сторон",
Code = "4",
GUID = "4a481322-05c9-47cb-9d05-30387dff1f93"
};
}
// Ссылка на НСИ "22 Причина закрытия лицевого счета" (реестровый номер 22)
// https://dom.gosuslugi.ru/opendataapi/nsi-22/v1
public class ПричинаЗакрытияЛицевогоСчета
{
public static HouseManagement.nsiRef РасторжениеДоговора => new HouseManagement.nsiRef()
{
Name = "Расторжение договора",
Code = "11",
GUID = "7ee8b4db-dabc-40eb-9009-f4f80b36bfe5"
};
}
// Ссылка на НСИ "Причина архивации прибора учета" (реестровый номер 21)
// https://my.dom.gosuslugi.ru/#!/open-data-passport?passportName=7710474375-nsi-21
public class ПричинаАрхивацииПрибораУчета
{
public static HouseManagement.nsiRef ИстекСрокЭксплуатации => new HouseManagement.nsiRef()
{
Code = "12",
GUID = "2b8f44f9-7ca1-44f5-803a-af80d6912f36",
Name = "Истек срок эксплуатации прибора учета"
};
public static HouseManagement.nsiRef Ошибка => new HouseManagement.nsiRef()
{
Code = "4",
GUID = "d723696f-5ed7-4923-ad6a-9c2c5bce5032",
Name = "Ошибка"
};
}
// Ссылка на НСИ "Основание заключения договора" (реестровый номер 58)
// https://my.dom.gosuslugi.ru/#!/open-data-passport?passportName=7710474375-nsi-58
public class ОснованиеЗаключенияДоговора
{
public static HouseManagement.nsiRef ЗаявлениеПотребителя => new HouseManagement.nsiRef()
{
Code = "7",
GUID = "93cd9d85-91b8-4bf9-ae48-c5f1e691949f",
Name = "Заявление потребителя"
};
public static HouseManagement.nsiRef ДоговорУправления => new HouseManagement.nsiRef()
{
Code = "3",
GUID = "11efe618-79f8-4f53-bfd6-11620e8e9e1e",
Name = "Договор управления"
};
}
public static HouseManagement.ContractSubjectTypeServiceType ElectricSupplyServiceType
=> new HouseManagement.ContractSubjectTypeServiceType()
{
Code = "4",
GUID = "903c7763-73f8-4af2-9ec2-94ee08c7beaa",
Name = "Электроснабжение"
};
public static HouseManagement.ContractSubjectTypeMunicipalResource ElectricSupplyMunicipalResource
=> new HouseManagement.ContractSubjectTypeMunicipalResource()
{
Code = "8",
GUID = "7379be86-6c95-4e41-b000-3bc703d35969",
Name = "Электрическая энергия"
};
}
}

View File

@ -0,0 +1,190 @@
using Hcs.ClientApi.DataTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод получения реестра лицевых счетов
/// </summary>
public class HcsMethodExportAccountData : HcsHouseManagementMethod
{
public HcsMethodExportAccountData(HcsClientConfig config) : base(config)
{
CanBeRestarted = true;
}
/// <summary>
/// Получает реестр лицевых счетов по зданию с данным ГУИД ФИАС или по списку номеров ЕЛС
/// </summary>
public async Task<int> Query(
Guid? fiasHouseGuid, IEnumerable<string> unifiedAccountNumbers,
Action<ГисЛицевойСчет> resultHandler, CancellationToken token)
{
int numResults = 0;
var itemNames = new List<HouseManagement.ItemsChoiceType18> { };
List<string> items = new List<string> { };
if (fiasHouseGuid != null)
{
itemNames.Add(HouseManagement.ItemsChoiceType18.FIASHouseGuid);
items.Add(FormatGuid(fiasHouseGuid));
}
if (unifiedAccountNumbers != null)
{
if (unifiedAccountNumbers.Count() > 1000)
throw new HcsException($"Слишком много ЕЛС в запросе {unifiedAccountNumbers.Count()} > допустимых 1000");
foreach (var un in unifiedAccountNumbers)
{
itemNames.Add(HouseManagement.ItemsChoiceType18.UnifiedAccountNumber);
items.Add(un);
}
}
try
{
var request = new HouseManagement.exportAccountRequest
{
Id = HcsConstants.SignedXmlElementId,
Items = items.ToArray(),
ItemsElementName = itemNames.ToArray()
};
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
{
var ackResponse = await portClient.exportAccountDataAsync(
CreateRequestHeader(), request);
return ackResponse.AckRequest.Ack;
}, token);
stateResult.Items.OfType<HouseManagement.exportAccountResultType>().ToList().ForEach(
account => { resultHandler(Adopt(account)); numResults += 1; });
}
catch (HcsNoResultsRemoteException)
{
return 0;
}
return numResults;
}
private ГисЛицевойСчет Adopt(HouseManagement.exportAccountResultType source)
{
return new ГисЛицевойСчет()
{
ГуидЛицевогоСчета = ParseGuid(source.AccountGUID),
НомерЕЛС = source.UnifiedAccountNumber,
НомерЛицевогоСчета = source.AccountNumber,
ПолнаяПлощадь = (source.TotalSquareSpecified ? (decimal?)source.TotalSquare : null),
ЖилаяПлощадь = (source.ResidentialSquareSpecified ? (decimal?)source.ResidentialSquare : null),
КодЖКУ = source.ServiceID,
ДатаСоздания = (source.CreationDateSpecified ? (DateTime?)source.CreationDate : null),
ДатаЗакрытия = (source.Closed != null ? (DateTime?)source.Closed.CloseDate : null),
КодНсиПричиныЗакрытия = (source.Closed != null ? source.Closed.CloseReason.Code : null),
ИмяПричиныЗакрытия = (source.Closed != null ? source.Closed.Description : null),
Размещения = Adopt(source.Accommodation),
Основания = Adopt(source.AccountReasons)
};
}
private ГисОснованиеЛС[] Adopt(HouseManagement.exportAccountResultTypeAccountReasons source)
{
if (source == null) throw new ArgumentNullException("HouseManagement.exportAccountResultTypeAccountReasons");
var основания = new List<ГисОснованиеЛС>();
if (source.SupplyResourceContract != null)
{
foreach (var sr in source.SupplyResourceContract)
{
var основание = new ГисОснованиеЛС();
основание.ТипОснованияЛС = ГисТипОснованияЛС.ДоговорРСО;
for (int i = 0; i < sr.Items.Length; i++)
{
switch (sr.ItemsElementName[i])
{
case HouseManagement.ItemsChoiceType9.ContractGUID:
основание.ГуидДоговора = ParseGuid(sr.Items[i]);
break;
}
}
if (основание.ГуидДоговора == default(Guid))
throw new HcsException("Для основания ЛС не указан ГУИД договора РСО");
основания.Add(основание);
}
}
if (source.SocialHireContract != null)
{
var sh = source.SocialHireContract;
var основание = new ГисОснованиеЛС();
основание.ТипОснованияЛС = ГисТипОснованияЛС.Соцнайм;
for (int i = 0; i < sh.Items.Length; i++)
{
object itemValue = sh.Items[i];
switch (sh.ItemsElementName[i])
{
case HouseManagement.ItemsChoiceType10.ContractGUID:
основание.ГуидДоговора = ParseGuid(itemValue);
break;
case HouseManagement.ItemsChoiceType10.ContractNumber:
основание.НомерДоговора = (itemValue != null ? itemValue.ToString() : null);
break;
}
}
if (основание.ГуидДоговора == default(Guid))
throw new HcsException("Для основания ЛС не указан ГУИД договора соцнайма");
основания.Add(основание);
}
if (source.Contract != null)
{
var основание = new ГисОснованиеЛС();
основание.ТипОснованияЛС = ГисТипОснованияЛС.Договор;
основание.ГуидДоговора = ParseGuid(source.Contract.ContractGUID);
основания.Add(основание);
}
// TODO: Проверить комментарий
// Непонятно что делать с остальными типам основания и даже следует ли их
// расшифровывать или считать ошибкой пустого списка оснований
return основания.ToArray();
}
private ГисРазмещениеЛС[] Adopt(HouseManagement.AccountExportTypeAccommodation[] array)
{
if (array == null) throw new ArgumentNullException("HouseManagement.AccountExportTypeAccommodation");
return array.ToList().Select(x => Adopt(x)).ToArray();
}
private ГисРазмещениеЛС Adopt(HouseManagement.AccountExportTypeAccommodation source)
{
var размещение = new ГисРазмещениеЛС();
размещение.ПроцентДоли = (source.SharePercentSpecified ? (decimal?)source.SharePercent : null);
switch (source.ItemElementName)
{
case HouseManagement.ItemChoiceType7.FIASHouseGuid: размещение.ГуидЗдания = ParseGuid(source.Item); break;
case HouseManagement.ItemChoiceType7.PremisesGUID: размещение.ГуидПомещения = ParseGuid(source.Item); break;
case HouseManagement.ItemChoiceType7.LivingRoomGUID: размещение.ГуидЖилойКомнаты = ParseGuid(source.Item); break;
default: throw new HcsException("Неизвестный тип размещения ЛС: " + source.ItemElementName);
}
return размещение;
}
}
}

View File

@ -0,0 +1,101 @@
using Hcs.ClientApi.DataTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод получения информации о доме и его помещениях
/// </summary>
public class HcsMethodExportHouse : HcsHouseManagementMethod
{
public HcsMethodExportHouse(HcsClientConfig config) : base(config)
{
CanBeRestarted = true;
}
public async Task<ГисЗдание> ExportHouseByFiasGuid(Guid fiasHouseGuid, CancellationToken token)
{
var request = new HouseManagement.exportHouseRequest
{
Id = HcsConstants.SignedXmlElementId,
FIASHouseGuid = FormatGuid(fiasHouseGuid),
// TODO: Тут хардкод версии
version = "12.2.0.1"
};
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
{
var response = await portClient.exportHouseDataAsync(CreateRequestHeader(), request);
return response.AckRequest.Ack;
}, token);
return Adopt(RequireSingleItem<HouseManagement.exportHouseResultType>(stateResult.Items));
}
private ГисЗдание Adopt(HouseManagement.exportHouseResultType source)
{
bool заполнен = false;
var дом = new ГисЗдание();
дом.НомерДомаГис = source.HouseUniqueNumber;
var помещения = new List<ГисПомещение>();
var apartmentHouse = source.Item as HouseManagement.exportHouseResultTypeApartmentHouse;
if (apartmentHouse != null)
{
дом.ТипДома = ГисТипДома.Многоквартирный;
дом.ГуидЗданияФиас = ParseGuid(apartmentHouse.BasicCharacteristicts.FIASHouseGuid);
if (apartmentHouse.ResidentialPremises != null)
{
apartmentHouse.ResidentialPremises.ToList().ForEach(x => помещения.Add(Adopt(x)));
}
if (apartmentHouse.NonResidentialPremises != null)
{
apartmentHouse.NonResidentialPremises.ToList().ForEach(x => помещения.Add(Adopt(x)));
}
заполнен = true;
}
var livingHouse = source.Item as HouseManagement.exportHouseResultTypeLivingHouse;
if (livingHouse != null)
{
дом.ТипДома = ГисТипДома.Жилой;
дом.ГуидЗданияФиас = ParseGuid(livingHouse.BasicCharacteristicts.FIASHouseGuid);
заполнен = true;
}
if (!заполнен) throw new HcsException("В информации о доме неизвестный тип данных: " + source.Item);
дом.Помещения = помещения.ToArray();
return дом;
}
private ГисПомещение Adopt(HouseManagement.exportHouseResultTypeApartmentHouseResidentialPremises source)
{
return new ГисПомещение()
{
ЭтоЖилоеПомещение = true,
НомерПомещения = source.PremisesNum,
ГуидПомещения = ParseGuid(source.PremisesGUID),
ДатаПрекращения = source.TerminationDateSpecified ? source.TerminationDate : null,
Аннулирование = source.AnnulmentInfo
};
}
private ГисПомещение Adopt(HouseManagement.exportHouseResultTypeApartmentHouseNonResidentialPremises source)
{
return new ГисПомещение()
{
ЭтоЖилоеПомещение = false,
НомерПомещения = source.PremisesNum,
ГуидПомещения = ParseGuid(source.PremisesGUID)
};
}
}
}

View File

@ -0,0 +1,165 @@
using Hcs.ClientApi.DataTypes;
using Hcs.Service.Async.HouseManagement.v14_5_0_1;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод получения списка приборов учета
/// </summary>
public class HcsMethodExportMeteringDeviceData : HcsHouseManagementMethod
{
public HcsMethodExportMeteringDeviceData(HcsClientConfig config) : base(config)
{
CanBeRestarted = true;
}
/// <summary>
/// Получение списка приборов учета для одного здания
/// </summary>
public async Task<int> ExportByHouse(
Guid fiasHouseGuid, Action<ГисПриборУчета> resultHandler, CancellationToken token)
{
List<HouseManagement.ItemsChoiceType4> itemNames = [HouseManagement.ItemsChoiceType4.FIASHouseGuid];
List<string> items = [FormatGuid(fiasHouseGuid)];
var request = new HouseManagement.exportMeteringDeviceDataRequest
{
Id = HcsConstants.SignedXmlElementId,
Items = items.ToArray(),
ItemsElementName = itemNames.ToArray(),
// TODO: Проверить комментарий
//version = "11.1.0.2" // Версия указана в API
};
int numResults = 0;
try
{
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
{
var ackResponse = await portClient.exportMeteringDeviceDataAsync(CreateRequestHeader(), request);
return ackResponse.AckRequest.Ack;
}, token);
stateResult.Items.OfType<HouseManagement.exportMeteringDeviceDataResultType>().ToList().ForEach(
device => { resultHandler(Adopt(device)); numResults += 1; }
);
}
catch (HcsNoResultsRemoteException)
{
return 0;
}
return numResults;
}
private ГисПриборУчета Adopt(HouseManagement.exportMeteringDeviceDataResultType source)
{
var прибор = new ГисПриборУчета()
{
ГуидПрибораУчета = ParseGuid(source.MeteringDeviceRootGUID),
ГуидВерсииПрибора = ParseGuid(source.MeteringDeviceVersionGUID),
НомерПрибораУчетаГис = source.MeteringDeviceGISGKHNumber,
ЗаводскойНомер = source.BasicChatacteristicts.MeteringDeviceNumber,
МодельПрибораУчета = source.BasicChatacteristicts.MeteringDeviceModel,
ДатаРазмещенияВерсии = source.UpdateDateTime
};
if (!IsArrayEmpty(source.MeteringOwner))
{
прибор.ГуидВладельцаПрибора = ParseGuid(source.MeteringOwner[0]);
}
switch (source.StatusRootDoc)
{
case HouseManagement.exportMeteringDeviceDataResultTypeStatusRootDoc.Active:
прибор.СтатусПрибораУчета = ГисСтатусПрибораУчета.Активный;
break;
case HouseManagement.exportMeteringDeviceDataResultTypeStatusRootDoc.Archival:
прибор.СтатусПрибораУчета = ГисСтатусПрибораУчета.Архивный;
break;
default:
throw new HcsException($"Неизвестный статус ПУ {source.StatusRootDoc} для №{прибор.ЗаводскойНомер}");
}
var basic = source.BasicChatacteristicts;
прибор.ДатаУстановки = basic.InstallationDateSpecified ? basic.InstallationDate : null;
прибор.ДатаВводаВЭксплуатацию = basic.CommissioningDateSpecified ? basic.CommissioningDate : null;
прибор.ДатаПоследнейПоверки = basic.FirstVerificationDateSpecified ? basic.FirstVerificationDate : null;
прибор.ДатаИзготовления = basic.FactorySealDateSpecified ? basic.FactorySealDate : null;
прибор.РежимДистанционногоОпроса = basic.RemoteMeteringMode;
прибор.ОписаниеДистанционногоОпроса = basic.RemoteMeteringInfo;
object basicItem = basic.Item;
bool типНайден = false;
CallOnType<HouseManagement.MeteringDeviceBasicCharacteristicsTypeResidentialPremiseDevice>(basicItem, x =>
{
прибор.ГуидыЛицевыхСчетов = ParseGuidArray(x.AccountGUID);
прибор.ГуидыПомещений = ParseGuidArray(x.PremiseGUID);
прибор.ВидПрибораУчета = ГисВидПрибораУчета.ЖилоеПомещение;
типНайден = true;
});
CallOnType<HouseManagement.MeteringDeviceBasicCharacteristicsTypeNonResidentialPremiseDevice>(basicItem, x =>
{
прибор.ГуидыЛицевыхСчетов = ParseGuidArray(x.AccountGUID);
прибор.ГуидыПомещений = ParseGuidArray(x.PremiseGUID);
прибор.ВидПрибораУчета = ГисВидПрибораУчета.НежилоеПомещение;
типНайден = true;
});
CallOnType<HouseManagement.MeteringDeviceBasicCharacteristicsTypeCollectiveDevice>(basicItem, x =>
{
прибор.ГуидыЗданийФиас = ParseGuidArray(x.FIASHouseGuid);
прибор.ВидПрибораУчета = ГисВидПрибораУчета.ОДПУ;
типНайден = true;
});
CallOnType<HouseManagement.MeteringDeviceBasicCharacteristicsTypeCollectiveApartmentDevice>(basicItem, x =>
{
прибор.ГуидыЛицевыхСчетов = ParseGuidArray(x.AccountGUID);
прибор.ГуидыПомещений = ParseGuidArray(x.PremiseGUID);
прибор.ВидПрибораУчета = ГисВидПрибораУчета.КоммунальнаяКвартира;
типНайден = true;
});
CallOnType<HouseManagement.MeteringDeviceBasicCharacteristicsTypeLivingRoomDevice>(basicItem, x =>
{
прибор.ГуидыЛицевыхСчетов = ParseGuidArray(x.AccountGUID);
прибор.ГуидыЖилыхКомнат = ParseGuidArray(x.LivingRoomGUID);
прибор.ВидПрибораУчета = ГисВидПрибораУчета.ЖилаяКомната;
типНайден = true;
});
CallOnType<HouseManagement.MeteringDeviceBasicCharacteristicsTypeApartmentHouseDevice>(basicItem, x =>
{
прибор.ГуидыЗданийФиас = ParseGuidArray(x.FIASHouseGuid);
прибор.ГуидыЛицевыхСчетов = ParseGuidArray(x.AccountGUID);
прибор.ВидПрибораУчета = ГисВидПрибораУчета.ЖилойДом;
типНайден = true;
});
if (!типНайден) throw new HcsException($"Неизвестный тип ПУ {basicItem} для №{прибор.ЗаводскойНомер}");
foreach (var electric in source.Items.OfType<MunicipalResourceElectricExportType>())
{
прибор.КоэффициентТрансформации =
(electric.TransformationRatioSpecified ? electric.TransformationRatio : 0);
прибор.ПоказаниеТ1 = electric.MeteringValueT1;
прибор.ПоказаниеТ2 = electric.MeteringValueT2;
прибор.ПоказаниеТ3 = electric.MeteringValueT3;
}
return прибор;
}
}
}

View File

@ -0,0 +1,297 @@
using Hcs.ClientApi.DataTypes;
using Hcs.ClientApi.RemoteCaller;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод получения реестра договоров ресурсоснабжения (ДРСО)
/// </summary>
public class HcsMethodExportSupplyResourceContractData : HcsHouseManagementMethod
{
public HcsMethodExportSupplyResourceContractData(HcsClientConfig config) : base(config)
{
CanBeRestarted = true;
}
/// <summary>
/// Получает один договор ресурсоснабжения по его GUID
/// </summary>
public async Task<ГисДоговор> QueryOne(Guid contractRootGuid, CancellationToken token)
{
ГисДоговор договор = null;
Action<ГисДоговор> handler = (result) => { договор = result; };
await QueryOneBatch(contractRootGuid, null, handler, null, token);
if (договор == null)
throw new HcsNoResultsRemoteException($"Нет договора РСО с ГУИД {contractRootGuid}");
return договор;
}
/// <summary>
/// Получает один договор ресурсоснабжения по его номеру договора
/// </summary>
public async Task<ГисДоговор[]> QueryByContractNumber(string contractNumber, CancellationToken token)
{
var list = new List<ГисДоговор>();
Action<ГисДоговор> handler = list.Add;
await QueryOneBatch(null, contractNumber, handler, null, token);
if (!list.Any()) throw new HcsNoResultsRemoteException($"Нет договора РСО с номером {contractNumber}");
return list.ToArray();
}
/// <summary>
/// Получает полный список реестра договоров ресурсоснабжения
/// </summary>
public async Task<int> QueryAll(Action<ГисДоговор> resultHandler, CancellationToken token)
{
int numResults = 0;
int numPages = 0;
Action<ГисДоговор> countingHandler = (result) =>
{
numResults += 1;
resultHandler(result);
};
Guid? nextGuid = null;
while (true)
{
if (++numPages > 1) Log($"Запрашиваем страницу #{numPages} данных...");
var paged = await QueryOneBatch(null, null, countingHandler, nextGuid, token);
if (paged.IsLastPage) break;
nextGuid = paged.NextGuid;
}
return numResults;
}
private async Task<HcsPagedResultState> QueryOneBatch(
Guid? contractRootGuid, string contractNumber, Action<ГисДоговор> resultHandler,
Guid? exportNextGuid, CancellationToken token)
{
var itemNames = new List<HouseManagement.ItemsChoiceType27> { };
List<object> items = new List<object> { };
if (contractRootGuid != null)
{
itemNames.Add(HouseManagement.ItemsChoiceType27.ContractRootGUID);
items.Add(FormatGuid(contractRootGuid));
}
if (contractNumber != null)
{
itemNames.Add(HouseManagement.ItemsChoiceType27.ContractNumber);
items.Add(contractNumber);
}
if (exportNextGuid != null)
{
itemNames.Add(HouseManagement.ItemsChoiceType27.ExportContractRootGUID);
items.Add(FormatGuid(exportNextGuid));
}
var request = new HouseManagement.exportSupplyResourceContractRequest
{
Id = HcsConstants.SignedXmlElementId,
Items = items.ToArray(),
ItemsElementName = itemNames.ToArray(),
// TODO: Проверить хардкод версии
version = "13.1.1.1" // Значение из сообщения об ошибке от сервера HCS
};
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
{
var ackResponse = await portClient.exportSupplyResourceContractDataAsync(
CreateRequestHeader(), request);
return ackResponse.AckRequest.Ack;
}, token);
var result = RequireSingleItem
<HouseManagement.getStateResultExportSupplyResourceContractResult>(stateResult.Items);
foreach (var c in result.Contract)
{
resultHandler(Adopt(c));
}
return new HcsPagedResultState(result.Item);
}
private ГисДоговор Adopt(HouseManagement.exportSupplyResourceContractResultType source)
{
var договор = new ГисДоговор()
{
ГуидДоговора = ParseGuid(source.ContractRootGUID),
ГуидВерсииДоговора = ParseGuid(source.ContractGUID),
НомерВерсии = source.VersionNumber,
СостояниеДоговора = Adopt(source.ContractState),
СтатусВерсииДоговора = Adopt(source.VersionStatus)
};
if (source.Item is HouseManagement.ExportSupplyResourceContractTypeIsContract isContract)
{
договор.ТипДоговораРСО = ГисТипДоговораРСО.НеПубличныйИлиНеНежилые;
договор.НомерДоговора = isContract.ContractNumber;
договор.ДатаЗаключения = (DateTime?)isContract.SigningDate;
договор.ДатаВступленияВСилу = (DateTime?)isContract.EffectiveDate;
if (isContract.ContractAttachment != null)
{
договор.ПриложенияДоговора = isContract.ContractAttachment.Select(AdoptAttachment).ToArray();
}
}
if (source.Item is HouseManagement.ExportSupplyResourceContractTypeIsNotContract isNotContract)
{
договор.ТипДоговораРСО = ГисТипДоговораРСО.ПубличныйИлиНежилые;
договор.НомерДоговора = isNotContract.ContractNumber;
договор.ДатаЗаключения = isNotContract.SigningDateSpecified ? isNotContract.SigningDate : null;
договор.ДатаВступленияВСилу = isNotContract.EffectiveDateSpecified ? isNotContract.EffectiveDate : null;
if (isNotContract.ContractAttachment != null)
{
договор.ПриложенияДоговора = isNotContract.ContractAttachment.Select(AdoptAttachment).ToArray();
}
}
var предметы = new List<ГисПредметДоговора>();
foreach (var subject in source.ContractSubject)
{
var предмет = new ГисПредметДоговора()
{
КодНсиУслуги = subject.ServiceType.Code,
ГуидНсиУслуги = ParseGuid(subject.ServiceType.GUID),
ИмяНсиУслуги = subject.ServiceType.Name,
КодНсиРесурса = subject.MunicipalResource.Code,
ГуидНсиРесурса = ParseGuid(subject.MunicipalResource.GUID),
ИмяНсиРесурса = subject.MunicipalResource.Name
};
предметы.Add(предмет);
}
договор.ПредметыДоговора = предметы.ToArray();
договор.Контрагент = AdoptCounterparty(source.Item1);
if (source.CountingResourceSpecified)
{
if (source.CountingResource == HouseManagement.ExportSupplyResourceContractTypeCountingResource.R)
договор.НачисленияРазмещаетРСО = true;
}
if (source.MeteringDeviceInformationSpecified)
{
if (source.MeteringDeviceInformation == true)
договор.ПриборыРазмещаетРСО = true;
}
return договор;
}
private ГисПриложение AdoptAttachment(HouseManagement.AttachmentType attachment)
{
return new ГисПриложение()
{
ИмяПриложения = attachment.Name,
ГуидПриложения = ParseGuid(attachment.Attachment.AttachmentGUID),
ХэшПриложения = attachment.AttachmentHASH
};
}
/// <summary>
/// Разбор сведений о контрагенте - второй стороне договора
/// </summary>
private ГисКонтрагент AdoptCounterparty(object item1)
{
switch (item1)
{
case HouseManagement.ExportSupplyResourceContractTypeApartmentBuildingOwner owner:
return AdoptCounterpartyEntity(owner.Item, ГисТипКонтрагента.ВладелецПомещения);
case HouseManagement.ExportSupplyResourceContractTypeApartmentBuildingRepresentativeOwner rep:
return AdoptCounterpartyEntity(rep.Item, ГисТипКонтрагента.ВладелецПомещения);
case HouseManagement.ExportSupplyResourceContractTypeApartmentBuildingSoleOwner sole:
return AdoptCounterpartyEntity(sole.Item, ГисТипКонтрагента.ВладелецПомещения);
case HouseManagement.ExportSupplyResourceContractTypeLivingHouseOwner owner:
return AdoptCounterpartyEntity(owner.Item, ГисТипКонтрагента.ВладелецПомещения);
case HouseManagement.ExportSupplyResourceContractTypeOrganization uk:
return new ГисКонтрагент()
{
ТипКонтрагента = ГисТипКонтрагента.УправляющаяКомпания,
ГуидОрганизации = ParseGuid(uk.orgRootEntityGUID)
};
}
return new ГисКонтрагент() { ТипКонтрагента = ГисТипКонтрагента.НеУказано };
}
/// <summary>
/// Разбор ссылки на контрагента - второй стороны договора
/// </summary>
private ГисКонтрагент AdoptCounterpartyEntity(object item, ГисТипКонтрагента типКонтрагента)
{
switch (item)
{
case HouseManagement.DRSORegOrgType org:
return new ГисКонтрагент()
{
ТипКонтрагента = типКонтрагента,
ГуидОрганизации = ParseGuid(org.orgRootEntityGUID)
};
case HouseManagement.DRSOIndType ind:
var индивид = new ГисИндивид()
{
Фамилия = ind.Surname,
Имя = ind.FirstName,
Отчество = ind.Patronymic
};
switch (ind.Item)
{
case string снилс: индивид.СНИЛС = снилс; break;
case HouseManagement.ID id:
индивид.НомерДокумента = id.Number;
индивид.СерияДокумента = id.Series;
индивид.ДатаДокумента = id.IssueDate;
break;
}
return new ГисКонтрагент() { ТипКонтрагента = типКонтрагента, Индивид = индивид, };
}
return new ГисКонтрагент() { ТипКонтрагента = ГисТипКонтрагента.НеУказано };
}
internal static ГисСтатусВерсииДоговора Adopt(
HouseManagement.exportSupplyResourceContractResultTypeVersionStatus source)
{
switch (source)
{
case HouseManagement.exportSupplyResourceContractResultTypeVersionStatus.Posted: return ГисСтатусВерсииДоговора.Размещен;
case HouseManagement.exportSupplyResourceContractResultTypeVersionStatus.Terminated: return ГисСтатусВерсииДоговора.Расторгнут;
case HouseManagement.exportSupplyResourceContractResultTypeVersionStatus.Draft: return ГисСтатусВерсииДоговора.Проект;
case HouseManagement.exportSupplyResourceContractResultTypeVersionStatus.Annul: return ГисСтатусВерсииДоговора.Аннулирован;
default: throw NewUnexpectedObjectException(source);
}
}
internal static ГисСостояниеДоговора Adopt(
HouseManagement.exportSupplyResourceContractResultTypeContractState source)
{
switch (source)
{
case HouseManagement.exportSupplyResourceContractResultTypeContractState.Expired: return ГисСостояниеДоговора.ИстекСрокДействия;
case HouseManagement.exportSupplyResourceContractResultTypeContractState.NotTakeEffect: return ГисСостояниеДоговора.НеВступилВСилу;
case HouseManagement.exportSupplyResourceContractResultTypeContractState.Proceed: return ГисСостояниеДоговора.Действующий;
default: throw NewUnexpectedObjectException(source);
}
}
}
}

View File

@ -0,0 +1,125 @@
using Hcs.ClientApi.DataTypes;
using Hcs.ClientApi.RemoteCaller;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод получения списка адресных объектов по договору ресурсоснабжения
/// </summary>
public class HcsMethodExportSupplyResourceContractObjectAddress : HcsHouseManagementMethod
{
public HcsMethodExportSupplyResourceContractObjectAddress(HcsClientConfig config) : base(config)
{
EnableMinimalResponseWaitDelay = true;
CanBeRestarted = true;
}
/// <summary>
/// Запрос на экспорт объектов жилищного фонда из договора ресурсоснабжения
/// </summary>
public async Task<int> QueryAddresses(
ГисДоговор договор, Action<ГисАдресныйОбъект> resultHandler, CancellationToken token)
{
int numResults = 0;
Action<ГисАдресныйОбъект> countingHandler = (result) =>
{
numResults += 1;
resultHandler(result);
};
Guid? nextGuid = null;
while (true)
{
var paged = await QueryOneBatch(договор, countingHandler, nextGuid, token);
if (paged.IsLastPage) break;
nextGuid = paged.NextGuid;
numResults += 1;
}
return numResults;
}
private async Task<HcsPagedResultState> QueryOneBatch(
ГисДоговор договор, Action<ГисАдресныйОбъект> resultHandler,
Guid? firstGuid, CancellationToken token)
{
var itemNames = new List<HouseManagement.ItemsChoiceType29> { };
List<string> items = new List<string> { };
if (договор.ГуидВерсииДоговора != default)
{
itemNames.Add(HouseManagement.ItemsChoiceType29.ContractGUID);
items.Add(FormatGuid(договор.ГуидВерсииДоговора));
}
else
{
itemNames.Add(HouseManagement.ItemsChoiceType29.ContractRootGUID);
items.Add(FormatGuid(договор.ГуидДоговора));
}
// TODO: Проверить комментарий
// Если указан guid следующей страницы данных, добавляем его в параметры
// (на 20.12.2023 эта функция не работает, первый пакет содержит 1000 записей
// и запрос второго пакета с ExportObjectGUID возвращает "Bad request")
if (firstGuid != null)
{
itemNames.Add(HouseManagement.ItemsChoiceType29.ExportObjectGUID);
items.Add(FormatGuid(firstGuid));
}
var request = new HouseManagement.exportSupplyResourceContractObjectAddressRequest
{
Id = HcsConstants.SignedXmlElementId,
Items = items.ToArray(),
ItemsElementName = itemNames.ToArray(),
// TODO: Проверить хардкод версии
version = "13.1.1.1" // Номер версии из сообщения об ошибке сервера HCS
};
try
{
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
{
var ackResponse = await portClient.exportSupplyResourceContractObjectAddressDataAsync(
CreateRequestHeader(), request);
return ackResponse.AckRequest.Ack;
}, token);
var result = RequireSingleItem
<HouseManagement.getStateResultExportSupplyResourceContractObjectAddress>(stateResult.Items);
foreach (var x in result.ObjectAddress)
{
resultHandler(Adopt(x));
}
return new HcsPagedResultState(result.Item);
}
catch (HcsNoResultsRemoteException)
{
return HcsPagedResultState.IsLastPageResultState;
}
}
private ГисАдресныйОбъект Adopt(
HouseManagement.exportSupplyResourceContractObjectAddressResultType source)
{
return new ГисАдресныйОбъект()
{
ТипЗдания = (source.HouseTypeSpecified ? source.HouseType.ToString() : null),
ГуидЗданияФиас = ParseGuid(source.FIASHouseGuid),
ГуидДоговора = ParseGuid(source.ContractRootGUID),
ГуидВерсииДоговора = ParseGuid(source.ContractGUID),
ГуидАдресногоОбъекта = ParseGuid(source.ObjectGUID),
НомерПомещения = source.ApartmentNumber,
НомерКомнаты = source.RoomNumber
};
}
}
}

View File

@ -0,0 +1,187 @@
using Hcs.ClientApi.DataTypes;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Операции размещения и закрытия Лицевых счетов в ГИС ЖКХ
/// </summary>
public class HcsMethodImportAccountData : HcsHouseManagementMethod
{
public HcsMethodImportAccountData(HcsClientConfig config) : base(config)
{
CanBeRestarted = false;
}
/// <summary>
/// Размещение нового Лицевого счета если ГисЛицевойСчет.ГуидЛицевогоСчета не заполнен,
/// размещение новой версии лицевого счета если заполнен.
/// Возвращает Единый номер лицевого счета в ГИС ЖКХ для размещенного ЛС
/// http://open-gkh.ru/HouseManagement/importAccountRequest/Account.html
/// </summary>
public async Task<string> ImportAccount(
ГисДоговор договор, ГисЛицевойСчет лицевойСчет, CancellationToken token)
{
if (лицевойСчет == null) throw new ArgumentNullException(nameof(лицевойСчет));
if (договор == null) throw new ArgumentNullException(nameof(договор));
var account = ConvertToAccount(договор, лицевойСчет);
var result = await CallImportAccountData(account, token);
return result.UnifiedAccountNumber;
}
private HouseManagement.importAccountRequestAccount ConvertToAccount(
ГисДоговор договор, ГисЛицевойСчет лицевойСчет)
{
var account = new HouseManagement.importAccountRequestAccount()
{
TransportGUID = FormatGuid(Guid.NewGuid()),
AccountNumber = лицевойСчет.НомерЛицевогоСчета
};
if (лицевойСчет.ГуидЛицевогоСчета != default)
{
account.AccountGUID = FormatGuid(лицевойСчет.ГуидЛицевогоСчета);
}
if (договор.ГуидДоговора == null) throw new HcsException("Не указан ГуидДоговора для размещения ЛС");
var reasonRSO = new HouseManagement.AccountReasonsImportTypeSupplyResourceContract()
{
Items = [FormatGuid(договор.ГуидДоговора)],
ItemsElementName = [HouseManagement.ItemsChoiceType9.ContractGUID]
};
account.AccountReasons = new HouseManagement.AccountReasonsImportType()
{
SupplyResourceContract = [reasonRSO]
};
account.ItemElementName = HouseManagement.ItemChoiceType18.isRSOAccount;
account.Item = true;
if (IsArrayEmpty(лицевойСчет.Размещения))
throw new HcsException($"Не указаны размещения ЛС №{лицевойСчет.НомерЛицевогоСчета}");
account.Accommodation = лицевойСчет.Размещения.Select(ConvertToAccomodation).ToArray();
if (лицевойСчет.ДатаЗакрытия != null)
{
account.Closed = new HouseManagement.ClosedAccountAttributesType()
{
CloseDate = (DateTime)лицевойСчет.ДатаЗакрытия,
CloseReason = HcsHouseManagementNsi.ПричинаЗакрытияЛицевогоСчета.РасторжениеДоговора
};
}
account.PayerInfo = new HouseManagement.AccountTypePayerInfo()
{
Item = ConvertToAccountContragent(договор.Контрагент)
};
return account;
}
private object ConvertToAccountContragent(ГисКонтрагент контрагент)
{
if (контрагент == null) throw new HcsException("В договоре не заполнен Контрагент");
if (контрагент.ГуидОрганизации != null)
{
if (контрагент.ГуидВерсииОрганизации == null)
throw new HcsException("Для размещения ЛС в договоре с ЮЛ обязательно указание ГисКонтрагент.ГуидВерсииОрганизации");
return new HouseManagement.RegOrgVersionType()
{
orgVersionGUID = FormatGuid(контрагент.ГуидВерсииОрганизации)
};
}
if (контрагент.Индивид != null)
{
контрагент.Индивид.ПроверитьЗаполнениеСНИЛС();
контрагент.Индивид.ПроверитьЗаполнениеФИО();
return new HouseManagement.AccountIndType()
{
FirstName = контрагент.Индивид.Имя,
Patronymic = контрагент.Индивид.Отчество,
Surname = контрагент.Индивид.Фамилия,
Item = контрагент.Индивид.СНИЛСТолькоЦифры
};
}
throw new HcsException("Не указана ни организация ни индивид для размещения ЛС");
}
private HouseManagement.AccountTypeAccommodation ConvertToAccomodation(ГисРазмещениеЛС размещение)
{
if (размещение == null) throw new HcsException("Пустое размещение для ЛС");
var accomodation = new HouseManagement.AccountTypeAccommodation();
if (размещение.ГуидПомещения != null)
{
accomodation.ItemElementName = HouseManagement.ItemChoiceType19.PremisesGUID;
accomodation.Item = FormatGuid(размещение.ГуидПомещения);
}
else if (размещение.ГуидЖилойКомнаты != null)
{
accomodation.ItemElementName = HouseManagement.ItemChoiceType19.LivingRoomGUID;
accomodation.Item = FormatGuid(размещение.ГуидЖилойКомнаты);
}
else
{
throw new HcsException("Не указан ГУИД помещения или комнаты для ЛС");
}
if (размещение.ПроцентДоли != null)
{
accomodation.SharePercent = (decimal)размещение.ПроцентДоли;
accomodation.SharePercentSpecified = true;
}
return accomodation;
}
private async Task<(string UnifiedAccountNumber, DateTime UpdateDate)> CallImportAccountData(
HouseManagement.importAccountRequestAccount account,
CancellationToken token)
{
var request = new HouseManagement.importAccountRequest
{
Id = HcsConstants.SignedXmlElementId,
Account = [account]
// TODO: Проверить комментарий
//version = "13.1.1.1" // Версия указана в API
};
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
{
var ackResponse = await portClient.importAccountDataAsync(
CreateRequestHeader(), request);
return ackResponse.AckRequest.Ack;
}, token);
var commonResult = ParseSingleImportResult(stateResult);
switch (commonResult.ItemElementName)
{
case HouseManagement.ItemChoiceType2.ImportAccount:
var accountResult = RequireType<HouseManagement.getStateResultImportResultCommonResultImportAccount>(commonResult.Item);
DateTime updateDate = commonResult.Items.OfType<DateTime>().FirstOrDefault();
if (updateDate == default)
throw new HcsException("В ответе сервера не указана дата обновления лицевого счета");
return (accountResult.UnifiedAccountNumber, updateDate);
default:
throw new HcsException($"Неожиданная структура в пакете результата: {commonResult.ItemElementName}");
}
}
}
}

View File

@ -0,0 +1,207 @@
using Hcs.ClientApi.DataTypes;
using Hcs.ClientApi.DeviceMeteringApi;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод передачи в ГИС ЖКХ сведений о приборе учета (новом или уже существующем)
/// </summary>
public class HcsMethodImportMeteringDeviceData : HcsHouseManagementMethod
{
public HcsMethodImportMeteringDeviceData(HcsClientConfig config) : base(config)
{
CanBeRestarted = false;
}
/// <summary>
/// Размещение нового прибора учета если ГисПриборУчета.ГуидПрибораУчета не заполнен,
/// размещение новой версии прибора учета если заполнен.
/// Возвращает GUID размещенного прибора учета
/// http://open-gkh.ru/HouseManagement/importMeteringDeviceDataRequest.html
/// </summary>
public async Task<Guid> ImportMeteringDevice(ГисПриборУчета прибор, CancellationToken token)
{
if (прибор == null) throw new ArgumentNullException(nameof(прибор));
var device = ConvertToMeteringDevice(прибор);
var result = await CallImportMeteringDevice(device, token);
return result.MeteringDeviceGuid;
}
/// <summary>
/// Выполняет архивацию(удаление) прибора учета в ГИС.
/// В структуре ПриборУчета используется только поле ГуидВерсииПрибора.
/// </summary>
public async Task<DateTime> ArchiveMeteringDevice(ГисПриборУчета приборУчета, CancellationToken token)
{
var archive = new HouseManagement.importMeteringDeviceDataRequestMeteringDeviceDeviceDataToUpdateArchiveDevice();
archive.ArchivingReason = HcsHouseManagementNsi.ПричинаАрхивацииПрибораУчета.ИстекСрокЭксплуатации;
var update = new HouseManagement.importMeteringDeviceDataRequestMeteringDeviceDeviceDataToUpdate();
update.MeteringDeviceVersionGUID = FormatGuid(приборУчета.ГуидВерсииПрибора);
update.Item = archive;
var device = new HouseManagement.importMeteringDeviceDataRequestMeteringDevice();
device.TransportGUID = FormatGuid(Guid.NewGuid());
device.Item = update;
var result = await CallImportMeteringDevice(device, token);
return result.UpdateDate;
}
private HouseManagement.importMeteringDeviceDataRequestMeteringDevice
ConvertToMeteringDevice(ГисПриборУчета прибор)
{
var device = new HouseManagement.importMeteringDeviceDataRequestMeteringDevice();
// ГИС будет возвращать ошибку с указанием этого идентификатора для определения элемента пакета
device.TransportGUID = FormatGuid(Guid.NewGuid());
if (прибор.ГуидВерсииПрибора != default)
{
var update = new HouseManagement.importMeteringDeviceDataRequestMeteringDeviceDeviceDataToUpdate();
update.MeteringDeviceVersionGUID = FormatGuid(прибор.ГуидВерсииПрибора);
update.Item = ConvertToFullInformationType(прибор);
device.Item = update;
}
else
{
device.Item = ConvertToFullInformationType(прибор);
}
return device;
}
private HouseManagement.MeteringDeviceFullInformationType ConvertToFullInformationType(
ГисПриборУчета прибор)
{
var basic = new HouseManagement.MeteringDeviceBasicCharacteristicsType();
basic.MeteringDeviceNumber = прибор.ЗаводскойНомер;
basic.MeteringDeviceModel = прибор.МодельПрибораУчета;
basic.MeteringDeviceStamp = прибор.МодельПрибораУчета;
basic.TemperatureSensor = false;
basic.PressureSensor = false;
basic.RemoteMeteringMode = прибор.РежимДистанционногоОпроса;
if (прибор.РежимДистанционногоОпроса)
basic.RemoteMeteringInfo = прибор.ОписаниеДистанционногоОпроса;
if (прибор.ДатаУстановки != null)
{
basic.InstallationDate = (DateTime)прибор.ДатаУстановки;
basic.InstallationDateSpecified = true;
}
if (прибор.ДатаВводаВЭксплуатацию != null)
{
basic.CommissioningDate = (DateTime)прибор.ДатаВводаВЭксплуатацию;
basic.CommissioningDateSpecified = true;
}
if (прибор.ДатаПоследнейПоверки != null)
{
basic.FirstVerificationDate = (DateTime)прибор.ДатаПоследнейПоверки;
basic.FirstVerificationDateSpecified = true;
}
if (прибор.ДатаИзготовления != null)
{
basic.FactorySealDate = (DateTime)прибор.ДатаИзготовления;
basic.FactorySealDateSpecified = true;
}
switch (прибор.ВидПрибораУчета)
{
case ГисВидПрибораУчета.ОДПУ:
if (IsArrayEmpty(прибор.ГуидыЗданийФиас))
throw new HcsException("Для ОДПУ необходимо указать ГУИД здания ФИАС");
basic.Item = new HouseManagement.MeteringDeviceBasicCharacteristicsTypeCollectiveDevice()
{
FIASHouseGuid = прибор.ГуидыЗданийФиас.Select(FormatGuid).ToArray()
};
break;
case ГисВидПрибораУчета.НежилоеПомещение:
if (IsArrayEmpty(прибор.ГуидыЛицевыхСчетов))
throw new HcsException("Для размещения ПУ нежилого помещения следует указать ГУИД лицевого счета");
if (IsArrayEmpty(прибор.ГуидыПомещений))
throw new HcsException("Для размещения ПУ нежилого помещения следует указать ГУИД помещения");
basic.Item = new HouseManagement.MeteringDeviceBasicCharacteristicsTypeNonResidentialPremiseDevice()
{
AccountGUID = прибор.ГуидыЛицевыхСчетов.Select(FormatGuid).ToArray(),
PremiseGUID = прибор.ГуидыПомещений.Select(FormatGuid).ToArray()
};
break;
default:
throw new NotImplementedException(
"Не реализовано размещение вида прибора: " + прибор.ВидПрибораУчета);
}
var electric = new HouseManagement.MunicipalResourceElectricBaseType();
electric.Unit = HouseManagement.MunicipalResourceElectricBaseTypeUnit.Item245; // Константа ОКЕИ 245=кВт*ч
electric.UnitSpecified = true;
electric.MeteringValueT1 = HcsDeviceMeteringUtil.ConvertMeterReading(прибор.ПоказаниеТ1, true);
electric.MeteringValueT2 = HcsDeviceMeteringUtil.ConvertMeterReading(прибор.ПоказаниеТ2, false);
electric.MeteringValueT3 = HcsDeviceMeteringUtil.ConvertMeterReading(прибор.ПоказаниеТ3, false);
if (прибор.КоэффициентТрансформацииУказан)
{
electric.TransformationRatio = прибор.КоэффициентТрансформации;
electric.TransformationRatioSpecified = true;
}
return new HouseManagement.MeteringDeviceFullInformationType()
{
BasicChatacteristicts = basic,
// TODO: Проверить комментарий
Item = true, // NotLinkedWithMetering (нет связей с другими приборами)
Items = [electric]
};
}
private async Task<(Guid MeteringDeviceGuid, DateTime UpdateDate)> CallImportMeteringDevice(
HouseManagement.importMeteringDeviceDataRequestMeteringDevice device,
CancellationToken token)
{
HouseManagement.importMeteringDeviceDataRequestMeteringDevice[] devices = { device };
var request = new HouseManagement.importMeteringDeviceDataRequest
{
Id = HcsConstants.SignedXmlElementId,
MeteringDevice = devices
// TODO: Проверить хардкод версии
//version = "13.1.1.1" // Версия указана в API
};
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
{
var ackResponse = await portClient.importMeteringDeviceDataAsync(
CreateRequestHeader(), request);
return ackResponse.AckRequest.Ack;
}, token);
var commonResult = ParseSingleImportResult(stateResult);
switch (commonResult.ItemElementName)
{
case HouseManagement.ItemChoiceType2.importMeteringDevice:
var deviceResult = RequireType<HouseManagement.getStateResultImportResultCommonResultImportMeteringDevice>(commonResult.Item);
DateTime updateDate = commonResult.Items.OfType<DateTime>().FirstOrDefault();
if (updateDate == default) throw new HcsException("В ответе сервера не указана дата обновления прибора учета");
return (ParseGuid(deviceResult.MeteringDeviceGUID), updateDate);
default:
throw new HcsException($"Неожиданная структура в пакете результата: {commonResult.ItemElementName}");
}
}
}
}

View File

@ -0,0 +1,386 @@
using Hcs.ClientApi.DataTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод передачи в ГИС ЖКХ сведений о договоре РСО (новом или уже существующем)
/// </summary>
public class HcsMethodImportSupplyResourceContractData : HcsHouseManagementMethod
{
public HcsMethodImportSupplyResourceContractData(HcsClientConfig config) : base(config)
{
CanBeRestarted = false;
}
/// <summary>
/// Размещение нового договора если ГисДоговор.ГуидДоговора не заполнен,
/// размещение новой версии договора если заполнен
/// http://open-gkh.ru/HouseManagement/SupplyResourceContractType.html
/// </summary>
public async Task<DateTime> ImportContract(
ГисДоговор договор, IEnumerable<ГисАдресныйОбъект> адреса, CancellationToken token)
{
if (договор == null) throw new ArgumentNullException(nameof(договор));
if (адреса == null || !адреса.Any())
throw new ArgumentException($"Для импорта нового договора {договор.НомерДоговора}" +
" необходимо указать хотя-бы один адресный объект");
Guid? contractGuid = (договор.ГуидДоговора == default) ? null : договор.ГуидДоговора;
var contract = ConvertToSupplyResourceContract(договор, адреса);
return await CallImportContract(contractGuid, contract, token);
}
/// <summary>
/// Вызывает удаленный метод импорта договора с @contractGuid и данными операции импорта @contractItem.
/// Чтобы перевести договор из состояния "Проект" в состояние "Размещен" необходимо вызвать
/// importSupplyResourceContractProjectData/PlacingContractProject=true
/// http://open-gkh.ru/HouseManagement/importSupplyResourceContractRequest.html
/// </summary>
private async Task<DateTime> CallImportContract(
Guid? contractGuid, object contractItem, CancellationToken token)
{
var contract = new HouseManagement.importSupplyResourceContractRequestContract();
HouseManagement.importSupplyResourceContractRequestContract[] contracts = { contract };
// Передаем условие запроса - гуид версии договора.
// При создании нового договора атрибут importSupplyResourceContractRequest.Contract.ContractGUID не заполняется.
if (contractGuid != null)
{
contract.ItemElementName = HouseManagement.ItemChoiceType26.ContractRootGUID;
contract.Item = FormatGuid(contractGuid);
}
contract.TransportGUID = FormatGuid(Guid.NewGuid());
contract.Item1 = contractItem;
var request = new HouseManagement.importSupplyResourceContractRequest
{
Id = HcsConstants.SignedXmlElementId,
Contract = contracts
// TODO: Проверить комментарий
//version = "13.1.1.1" // Версия указана в API
};
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
{
var ackResponse = await portClient.importSupplyResourceContractDataAsync(
CreateRequestHeader(), request);
return ackResponse.AckRequest.Ack;
}, token);
var commonResult = ParseSingleImportResult(stateResult);
switch (commonResult.ItemElementName)
{
case HouseManagement.ItemChoiceType2.ImportSupplyResourceContract:
var contractResult = RequireType<HouseManagement.getStateResultImportResultCommonResultImportSupplyResourceContract>(commonResult.Item);
var датаИмпорта = RequireSingleItem<DateTime>(commonResult.Items);
return датаИмпорта;
default:
throw new HcsException($"Неожиданная структура в пакете результата: {commonResult.ItemElementName}");
}
}
/// <summary>
/// Преобразует модель данных ГисДоговор в модель данных HouseManagement.SupplyResourceContractType
/// http://open-gkh.ru/HouseManagement/SupplyResourceContractType.html
/// </summary>
private HouseManagement.SupplyResourceContractType ConvertToSupplyResourceContract(
ГисДоговор договор, IEnumerable<ГисАдресныйОбъект> адреса)
{
var contract = new HouseManagement.SupplyResourceContractType();
if (договор.ЭтоДоговорНежилогоПомещения)
{
var isNotContract = new HouseManagement.SupplyResourceContractTypeIsNotContract();
isNotContract.ContractNumber = договор.НомерДоговора;
if (договор.ДатаЗаключения != null)
isNotContract.SigningDate = (DateTime)договор.ДатаЗаключения;
if (!IsArrayEmpty(договор.ПриложенияДоговора))
isNotContract.ContractAttachment = договор.ПриложенияДоговора.Select(ConvertToAttachment).ToArray();
contract.Item = isNotContract;
}
if (договор.ЭтоДоговорИКУ)
{
var isContract = new HouseManagement.SupplyResourceContractTypeIsContract();
isContract.ContractNumber = договор.НомерДоговора;
var нужнаДатаЗаключения = (договор.ДатаЗаключения != null) ? (DateTime)договор.ДатаЗаключения : DateTime.Now;
isContract.SigningDate = isContract.EffectiveDate = нужнаДатаЗаключения;
// Для ИКУ обязательно приложение файла договора (иначе 400 Bad request)
if (IsArrayEmpty(договор.ПриложенияДоговора))
throw new HcsException($"Для размещения договора ИКУ {договор.НомерДоговора} необходимо указать файл приложения");
isContract.ContractAttachment = договор.ПриложенияДоговора.Select(ConvertToAttachment).ToArray();
contract.Item = isContract;
}
if (договор.Контрагент == null)
throw new HcsException($"В договоре {договор.НомерДоговора} не указан Контрагент");
if (договор.ЭтоДоговорНежилогоПомещения)
{
contract.Item1 = new HouseManagement.SupplyResourceContractTypeApartmentBuildingOwner()
{
Item = ConvertToDRSOContragent(договор.Контрагент)
};
contract.ContractBase = [HcsHouseManagementNsi.ОснованиеЗаключенияДоговора.ЗаявлениеПотребителя];
}
if (договор.ЭтоДоговорИКУ)
{
if (договор.Контрагент.ГуидОрганизации == null)
throw new HcsException($"В договоре ИКУ {договор.НомерДоговора} не указан ГУИД организации");
contract.Item1 = new HouseManagement.SupplyResourceContractTypeOrganization()
{
orgRootEntityGUID = FormatGuid(договор.Контрагент.ГуидОрганизации)
};
contract.ContractBase = [HcsHouseManagementNsi.ОснованиеЗаключенияДоговора.ДоговорУправления];
}
Guid contractSubjectGuid = Guid.NewGuid();
contract.ContractSubject = [
new HouseManagement.SupplyResourceContractTypeContractSubject() {
ServiceType = HcsHouseManagementNsi.ElectricSupplyServiceType,
MunicipalResource = HcsHouseManagementNsi.ElectricSupplyMunicipalResource,
StartSupplyDate = (договор.ДатаЗаключения != null ? (DateTime)договор.ДатаЗаключения : DateTime.Now),
EndSupplyDate = DateTime.Now.AddYears(50),
TransportGUID = FormatGuid(contractSubjectGuid)
}
];
// Порядок размещения информации о начислениях за коммунальные услуги ведется.
// "D" - в разрезе договора. "O" - в разрезе объектов. Обязательно для ИКУ.
if (договор.ЭтоДоговорИКУ)
{
contract.AccrualProcedure = HouseManagement.SupplyResourceContractTypeAccrualProcedure.D;
contract.AccrualProcedureSpecified = true;
}
if (договор.ЭтоДоговорИКУ)
{
// Размещение информации о начислениях за коммунальные услуги осуществляет.
// R(SO)- РСО. P(roprietor)-Исполнитель коммунальных услуг. Обязательно для ИКУ.
contract.CountingResource =
договор.НачисленияРазмещаетРСО ?
HouseManagement.SupplyResourceContractTypeCountingResource.R :
HouseManagement.SupplyResourceContractTypeCountingResource.P;
contract.CountingResourceSpecified = true;
if (договор.НачисленияРазмещаетРСО)
{
if (договор.ПриборыРазмещаетРСО)
{
contract.MeteringDeviceInformation = true;
contract.MeteringDeviceInformationSpecified = true;
}
}
// В договоре нет планового объема потребления
contract.IsPlannedVolume = false;
}
if (договор.НачисленияРазмещаетРСО)
{
// Cрок предоставления платежных документов, не позднее
contract.BillingDate = new HouseManagement.SupplyResourceContractTypeBillingDate()
{
Date = 15,
DateType = HouseManagement.SupplyResourceContractTypeBillingDateDateType.N // Следующий месяц
};
// Срок предоставления информации о поступивших платежах, не позднее
contract.ProvidingInformationDate = new HouseManagement.SupplyResourceContractTypeProvidingInformationDate()
{
Date = 15,
DateType = HouseManagement.SupplyResourceContractTypeProvidingInformationDateDateType.N // Следующий месяц
};
}
if (договор.ПриборыРазмещаетРСО)
{
// Период передачи текущих показаний должен быть указан, если ИПУ размещает РСО
contract.Period = new HouseManagement.SupplyResourceContractTypePeriod()
{
Start = new HouseManagement.SupplyResourceContractTypePeriodStart()
{
StartDate = 1
},
End = new HouseManagement.SupplyResourceContractTypePeriodEnd()
{
EndDate = 25
}
};
}
// Срок представления (выставления) платежных документов, не позднее. Является обязательным,
// если вторая сторона договора отличается от "Управляющая организация".
if (договор.ЭтоДоговорНежилогоПомещения)
{
contract.BillingDate = new HouseManagement.SupplyResourceContractTypeBillingDate()
{
Date = -1, // последний день месяца
DateType = HouseManagement.SupplyResourceContractTypeBillingDateDateType.N // следующего месяца
};
// Объем поставки определяется на основании прибора учета (признак необходим чтобы
// ГИС разрешал размещать ПУ на лицевых счетах договора) (признак запрещен для ИКУ)
contract.VolumeDepends = true;
contract.VolumeDependsSpecified = true;
// Период передачи текущих показаний должен быть указан если указано VolumeDepends
contract.Period = new HouseManagement.SupplyResourceContractTypePeriod()
{
Start = new HouseManagement.SupplyResourceContractTypePeriodStart()
{
StartDate = 1
},
End = new HouseManagement.SupplyResourceContractTypePeriodEnd()
{
EndDate = 25
}
};
}
// Срок действия договора
contract.ItemsElementName = [HouseManagement.ItemsChoiceType25.IndefiniteTerm];
contract.Items = [true];
// Данные об объекте жилищного фонда. При импорте договора должен быть добавлен
// как минимум один адрес объекта жилищного фонда.
if (адреса != null)
{
contract.ObjectAddress = адреса.Select(
адрес => ConvertToObjectAddress(договор, адрес, contractSubjectGuid)).ToArray();
}
return contract;
}
/// <summary>
/// Сборка сведений для отправки указателя на файл приложения к договору
/// http://open-gkh.ru/Base/AttachmentType.html
/// </summary>
private HouseManagement.AttachmentType ConvertToAttachment(ГисПриложение приложение)
{
return new HouseManagement.AttachmentType()
{
Name = приложение.ИмяПриложения ?? throw new HcsException("Не указано имя файла приложения"),
Description = приложение.ОписаниеПриложения != null ? приложение.ОписаниеПриложения : приложение.ИмяПриложения,
AttachmentHASH = приложение.ХэшПриложения ?? throw new HcsException("Не указан хэш файла приложения"),
Attachment = new HouseManagement.Attachment()
{
AttachmentGUID = FormatGuid(приложение.ГуидПриложения)
}
};
}
private HouseManagement.SupplyResourceContractTypeObjectAddress ConvertToObjectAddress(
ГисДоговор договор, ГисАдресныйОбъект адрес, Guid contractSubjectGuid)
{
// Дату начала снабжения выводим из даты заключения договора
DateTime startSupplyDate = (договор.ДатаЗаключения != null) ?
(DateTime)договор.ДатаЗаключения : DateTime.Now;
// Ссылка на пару определения ресурсов предмета договора
var pair = new HouseManagement.SupplyResourceContractTypeObjectAddressPair();
pair.PairKey = FormatGuid(contractSubjectGuid);
pair.StartSupplyDate = startSupplyDate;
// TODO: Проверить комментарий
pair.EndSupplyDateSpecified = false; // Не указана дата окончания поставки ресурса
var address = new HouseManagement.SupplyResourceContractTypeObjectAddress()
{
TransportGUID = FormatGuid(Guid.NewGuid()),
FIASHouseGuid = FormatGuid(адрес.ГуидЗданияФиас),
ApartmentNumber = MakeEmptyNull(адрес.НомерПомещения),
RoomNumber = MakeEmptyNull(адрес.НомерКомнаты),
Pair = [pair]
};
if (!string.IsNullOrEmpty(адрес.ТипЗдания))
{
address.HouseTypeSpecified = true;
address.HouseType = ConvertToHouseType(адрес.ТипЗдания);
}
return address;
}
private HouseManagement.ObjectAddressTypeHouseType ConvertToHouseType(string типЗдания)
{
return типЗдания switch
{
ГисАдресныйОбъект.ИзвестныеТипыЗдания.MKD => HouseManagement.ObjectAddressTypeHouseType.MKD,
ГисАдресныйОбъект.ИзвестныеТипыЗдания.ZHD => HouseManagement.ObjectAddressTypeHouseType.ZHD,
ГисАдресныйОбъект.ИзвестныеТипыЗдания.ZHDBlockZastroyki => HouseManagement.ObjectAddressTypeHouseType.ZHDBlockZastroyki,
_ => throw new HcsException($"Указан неизвестный тип здания [{типЗдания}]")
};
}
/// <summary>
/// Преобразует реквизиты контрагента в модель данных ГИС ЖКХ
/// </summary>
private object ConvertToDRSOContragent(ГисКонтрагент контрагент)
{
if (контрагент.ГуидОрганизации != null)
{
return new HouseManagement.DRSORegOrgType()
{
orgRootEntityGUID = FormatGuid(контрагент.ГуидОрганизации)
};
}
if (контрагент.Индивид != null)
{
контрагент.Индивид.ПроверитьЗаполнениеСНИЛС();
контрагент.Индивид.ПроверитьЗаполнениеФИО();
return new HouseManagement.DRSOIndType()
{
Patronymic = MakeEmptyNull(контрагент.Индивид.Отчество),
FirstName = MakeEmptyNull(контрагент.Индивид.Имя),
Surname = MakeEmptyNull(контрагент.Индивид.Фамилия),
Item = MakeEmptyNull(контрагент.Индивид.СНИЛСТолькоЦифры) // В СНИЛС требуется только 11 цифр
};
}
return false;
}
/// <summary>
/// Выполнение операции размещения факта расторжения договора
/// http://open-gkh.ru/HouseManagement/importSupplyResourceContractRequest/Contract/TerminateContract.html
/// </summary>
public async Task<DateTime> TerminateContract(
ГисДоговор договор, DateTime датаРасторжения, CancellationToken token)
{
var terminate = new HouseManagement.importSupplyResourceContractRequestContractTerminateContract();
terminate.Terminate = датаРасторжения;
terminate.ReasonRef = HcsHouseManagementNsi.ПричинаРасторженияДоговора.ПоВзаимномуСогласиюСторон;
return await CallImportContract(договор.ГуидДоговора, terminate, token);
}
/// <summary>
/// Выполнение операции размещения факта аннулирование договора
/// http://open-gkh.ru/HouseManagement/AnnulmentType.html
/// </summary>
public async Task<DateTime> AnnulContract(ГисДоговор договор, string причина, CancellationToken token)
{
var annulment = new HouseManagement.AnnulmentType();
annulment.ReasonOfAnnulment = причина;
return await CallImportContract(договор.ГуидДоговора, annulment, token);
}
}
}

View File

@ -0,0 +1,133 @@
using Hcs.ClientApi.DataTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод добавления/изменения/удаления элементов списка адресных объектов
/// в договоре ресурсоснабжения
/// </summary>
public class HcsMethodImportSupplyResourceContractObjectAddress : HcsHouseManagementMethod
{
public HcsMethodImportSupplyResourceContractObjectAddress
(HcsClientConfig config) : base(config)
{
EnableMinimalResponseWaitDelay = true;
CanBeRestarted = true;
}
public async Task ImportObjectAddresses(
ГисДоговор договор,
IEnumerable<ГисАдресныйОбъект> адресаДляРазмещения,
IEnumerable<ГисАдресныйОбъект> адресаДляУдаления,
CancellationToken token)
{
if (договор == null) throw new ArgumentNullException(nameof(договор));
var list = new List<HouseManagement.importSupplyResourceContractObjectAddressRequestObjectAddress>();
if (адресаДляРазмещения != null) list.AddRange(адресаДляРазмещения.Select(AdoptForLoading));
if (адресаДляУдаления != null) list.AddRange(адресаДляУдаления.Select(AdoptForRemoval));
var request = new HouseManagement.importSupplyResourceContractObjectAddressRequest()
{
Id = HcsConstants.SignedXmlElementId,
Item = FormatGuid(договор.ГуидДоговора),
ItemElementName = HouseManagement.ItemChoiceType28.ContractRootGUID,
ObjectAddress = list.ToArray()
// TODO: Проверить комментарий
//version = "13.1.1.1" // Версия указана в API
};
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
{
var ackResponse = await portClient.importSupplyResourceContractObjectAddressDataAsync(
CreateRequestHeader(), request);
return ackResponse.AckRequest.Ack;
}, token);
ParseImportResults(stateResult, list.Count(), true);
}
/// <summary>
/// Готовит структуру адресного объекта для удаления в ГИС
/// </summary>
private HouseManagement.importSupplyResourceContractObjectAddressRequestObjectAddress AdoptForRemoval(
ГисАдресныйОбъект адрес)
{
if (адрес == null) throw new ArgumentNullException(nameof(адрес));
Guid transportGuid = Guid.NewGuid();
bool deleteObject = true;
return new HouseManagement.importSupplyResourceContractObjectAddressRequestObjectAddress()
{
TransportGUID = FormatGuid(transportGuid),
ObjectGUID = FormatGuid(адрес.ГуидАдресногоОбъекта),
Item = deleteObject
};
}
/// <summary>
/// Готовит структуру адресного объекта для добавления/обновления в ГИС
/// </summary>
private HouseManagement.importSupplyResourceContractObjectAddressRequestObjectAddress AdoptForLoading(
ГисАдресныйОбъект адрес)
{
if (адрес == null) throw new ArgumentNullException(nameof(адрес));
Guid transportGuid = Guid.NewGuid();
var serviceType = new HouseManagement.ContractSubjectObjectAdressTypeServiceType()
{
Code = HcsHouseManagementNsi.ElectricSupplyServiceType.Code,
GUID = HcsHouseManagementNsi.ElectricSupplyServiceType.GUID,
Name = HcsHouseManagementNsi.ElectricSupplyServiceType.Name
};
var municipalResource = new HouseManagement.ContractSubjectObjectAdressTypeMunicipalResource()
{
Code = HcsHouseManagementNsi.ElectricSupplyMunicipalResource.Code,
GUID = HcsHouseManagementNsi.ElectricSupplyMunicipalResource.GUID,
Name = HcsHouseManagementNsi.ElectricSupplyMunicipalResource.Name
};
var pair = new HouseManagement.importSupplyResourceContractObjectAddressRequestObjectAddressLoadObjectPair()
{
// TODO: Проверить комментарий
TransportGUID = FormatGuid(Guid.NewGuid()), // Получал BadRequest пока не сделал здесь новый GUID
ServiceType = serviceType,
MunicipalResource = municipalResource,
// TODO: Проверить комментарий
StartSupplyDate = DateTime.Now // В договоре нет даты начала снабжения адреса, ставлю что-нибудь
};
var loadObject = new HouseManagement.importSupplyResourceContractObjectAddressRequestObjectAddressLoadObject()
{
FIASHouseGuid = FormatGuid(адрес.ГуидЗданияФиас),
ApartmentNumber = MakeEmptyNull(адрес.НомерПомещения),
RoomNumber = MakeEmptyNull(адрес.НомерКомнаты),
Pair = [pair]
};
var address = new HouseManagement.importSupplyResourceContractObjectAddressRequestObjectAddress()
{
TransportGUID = FormatGuid(transportGuid),
Item = loadObject
};
if (адрес.ГуидАдресногоОбъекта != default)
{
address.ObjectGUID = FormatGuid(адрес.ГуидАдресногоОбъекта);
}
return address;
}
}
}

View File

@ -0,0 +1,80 @@
using Hcs.ClientApi.DataTypes;
using Hcs.Service.Async.HouseManagement.v14_5_0_1;
using System;
using System.Threading;
using System.Threading.Tasks;
using HouseManagement = Hcs.Service.Async.HouseManagement.v14_5_0_1;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод отправки в ГИС проекта договора ресурсоснабжения, удаления
/// проекта договора РСО, перевода проекта в статус Размещенные
/// </summary>
public class HcsMethodImportSupplyResourceContractProject : HcsHouseManagementMethod
{
public HcsMethodImportSupplyResourceContractProject
(HcsClientConfig config) : base(config)
{
EnableMinimalResponseWaitDelay = true;
CanBeRestarted = false;
}
/// <summary>
/// Выполнение удаления в ГИС проекта договора
/// </summary>
public async Task DeleteContractProject(ГисДоговор договор, CancellationToken token)
{
await DoContractProjectOperation(
договор, Item1ChoiceType10.DeleteContractProject, token);
}
/// <summary>
/// Выполнение перевода проекта договора в статус Размещен
/// </summary>
public async Task PlaceContractProject(ГисДоговор договор, CancellationToken token)
{
await DoContractProjectOperation(
договор, Item1ChoiceType10.PlacingContractProject, token);
}
private async Task DoContractProjectOperation(
ГисДоговор договор, Item1ChoiceType10 operationType, CancellationToken token)
{
if (договор == null) throw new ArgumentNullException(nameof(договор));
if (договор.ГуидВерсииДоговора == default)
throw new ArgumentException("Для проекта договора не указан ГУИД версии");
var contract = new HouseManagement.importSupplyResourceContractProjectRequestContract()
{
TransportGUID = FormatGuid(Guid.NewGuid()),
ItemElementName = ItemChoiceType29.ContractRootGUID,
Item = FormatGuid(договор.ГуидДоговора),
// TODO: Проверить комментарий
// Если удалять версию проекта то остается предыдущая версия проекта
//ItemElementName = ItemChoiceType29.ContractGUID,
//Item = FormatGuid(договор.ГуидВерсииДоговора),
Item1ElementName = operationType,
Item1 = true,
};
var request = new HouseManagement.importSupplyResourceContractProjectRequest()
{
Id = HcsConstants.SignedXmlElementId,
Contract = [contract],
// TODO: Проверить комментарий
//version = "13.1.1.1" // Версия указана в API
};
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
{
var ackResponse = await portClient.importSupplyResourceContractProjectDataAsync(
CreateRequestHeader(), request);
return ackResponse.AckRequest.Ack;
}, token);
ParseSingleImportResult(stateResult);
}
}
}