Remove old code and services
This commit is contained in:
@ -1,35 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Информация о зданиях и помещениях в зданиях (объектах жилого фонда),
|
||||
/// которые связаны с договором (в договоре имеются Лицевые Счета в
|
||||
/// указанных объектах)
|
||||
/// </summary>
|
||||
public class ГисАдресныйОбъект
|
||||
{
|
||||
public Guid ГуидДоговора;
|
||||
public Guid ГуидВерсииДоговора;
|
||||
public Guid ГуидЗданияФиас;
|
||||
public Guid ГуидАдресногоОбъекта;
|
||||
|
||||
public class ИзвестныеТипыЗдания
|
||||
{
|
||||
public const string MKD = "MKD";
|
||||
public const string ZHD = "ZHD";
|
||||
public const string ZHDBlockZastroyki = "ZHDBlockZastroyki";
|
||||
}
|
||||
|
||||
public string ТипЗдания;
|
||||
public string НомерПомещения;
|
||||
public string НомерКомнаты;
|
||||
|
||||
public bool СвязанСДоговором(ГисДоговор договор) => договор != null && договор.ГуидДоговора == ГуидДоговора;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Тип=[{ТипЗдания}] ЗданиеФиас=[{ГуидЗданияФиас}] Объект[{ГуидАдресногоОбъекта}] Помещ[{НомерПомещения}] Комн[{НомерКомнаты}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,140 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Договор с ресурсоснабжающей организацией
|
||||
/// </summary>
|
||||
public class ГисДоговор
|
||||
{
|
||||
public Guid ГуидДоговора;
|
||||
public Guid ГуидВерсииДоговора;
|
||||
public string НомерВерсии;
|
||||
|
||||
public ГисСостояниеДоговора СостояниеДоговора;
|
||||
public ГисСтатусВерсииДоговора СтатусВерсииДоговора;
|
||||
|
||||
public ГисТипДоговораРСО ТипДоговораРСО;
|
||||
public string НомерДоговора;
|
||||
public DateTime? ДатаЗаключения;
|
||||
public DateTime? ДатаВступленияВСилу;
|
||||
|
||||
public bool НачисленияРазмещаетРСО;
|
||||
public bool ПриборыРазмещаетРСО;
|
||||
|
||||
public ГисКонтрагент Контрагент;
|
||||
|
||||
public ГисПредметДоговора[] ПредметыДоговора;
|
||||
|
||||
public ГисПриложение[] ПриложенияДоговора;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ЭтоДоговорИКУ => (ТипДоговораРСО == ГисТипДоговораРСО.НеПубличныйИлиНеНежилые);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ЭтоДоговорНежилогоПомещения => (ТипДоговораРСО == ГисТипДоговораРСО.ПубличныйИлиНежилые);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ЭтоПроектДоговора => (СтатусВерсииДоговора == ГисСтатусВерсииДоговора.Проект);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool Расторгнут => (СтатусВерсииДоговора == ГисСтатусВерсииДоговора.Расторгнут);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ИмеетГуидДоговора => (ГуидДоговора != default);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ПриниматьИзГисНаАнализ
|
||||
{
|
||||
get
|
||||
{
|
||||
return СтатусВерсииДоговора switch
|
||||
{
|
||||
// TODO: Проверить комментирование этой строчки
|
||||
//ГисСтатусВерсииДоговора.Проект => false, // С 15.11.2024 принимаем проекты
|
||||
ГисСтатусВерсииДоговора.Аннулирован => false,
|
||||
ГисСтатусВерсииДоговора.Расторгнут => false,
|
||||
_ => true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Договор №{НомерДоговора} Тип={ТипДоговораРСО}" +
|
||||
$" Статус={СтатусВерсииДоговора} Состояние={СостояниеДоговора}" +
|
||||
$" Заключен={HcsUtil.FormatDate(ДатаЗаключения)}" +
|
||||
$" №Версии={НомерВерсии} ГуидДог={ГуидДоговора}" +
|
||||
$" ГуидВерсии={ГуидВерсииДоговора}";
|
||||
}
|
||||
}
|
||||
|
||||
public enum ГисТипДоговораРСО
|
||||
{
|
||||
/// <summary>
|
||||
/// Договор не является публичным и/или присутствует заключенный на бумажном
|
||||
/// носителе (электронной форме) и/или не заключен в отношении нежилых помещений
|
||||
/// в многоквартирных домах (IsContract в терминах HCS)
|
||||
/// </summary>
|
||||
НеПубличныйИлиНеНежилые,
|
||||
|
||||
/// <summary>
|
||||
/// Договор является публичным и/или отсутствует заключенный на бумажном носителе
|
||||
/// (в электронной форме) и/или заключен в отношении нежилых помещений в
|
||||
/// многоквартирных домах (IsNotContract в терминах HCS)
|
||||
/// </summary>
|
||||
ПубличныйИлиНежилые
|
||||
}
|
||||
|
||||
public enum ГисСостояниеДоговора
|
||||
{
|
||||
НеВступилВСилу, // NotTakeEffect
|
||||
Действующий, // Proceed
|
||||
ИстекСрокДействия // Expired
|
||||
}
|
||||
|
||||
public enum ГисСтатусВерсииДоговора
|
||||
{
|
||||
Размещен, // Posted
|
||||
Расторгнут, // Terminated
|
||||
Проект, // Draft
|
||||
Аннулирован // Annul
|
||||
}
|
||||
|
||||
public class ГисПредметДоговора
|
||||
{
|
||||
// Вид КУ. Ссылка на НСИ "Вид коммунальной услуги" (реестровый номер 3)
|
||||
public string КодНсиУслуги;
|
||||
public Guid ГуидНсиУслуги;
|
||||
public string ИмяНсиУслуги;
|
||||
|
||||
// Коммунальный ресурс. Ссылка на НСИ "Тарифицируемый ресурс" (реестровый номер 239)
|
||||
public string КодНсиРесурса;
|
||||
public Guid ГуидНсиРесурса;
|
||||
public string ИмяНсиРесурса;
|
||||
}
|
||||
|
||||
public class ГисПриложение
|
||||
{
|
||||
/// <summary>
|
||||
/// Имя файла приложения
|
||||
/// </summary>
|
||||
public string ИмяПриложения;
|
||||
|
||||
/// <summary>
|
||||
/// Пояснение к файлу приложения
|
||||
/// </summary>
|
||||
public string ОписаниеПриложения;
|
||||
|
||||
/// <summary>
|
||||
/// ГУИД файла приложения из ext-bus-file-store-service
|
||||
/// </summary>
|
||||
public Guid ГуидПриложения;
|
||||
|
||||
/// <summary>
|
||||
/// Хэш файла приложения в устаревшем стандарте "ГОСТ Р 34.11-94" в Binhex
|
||||
/// </summary>
|
||||
public string ХэшПриложения;
|
||||
}
|
||||
}
|
||||
@ -1,197 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Сборный класс для получения сразу всех договоров, их лицевых счетов
|
||||
/// и приборов учета привязанных к лицевым счетам договоров
|
||||
/// </summary>
|
||||
public class ГисДоговорыИПриборы
|
||||
{
|
||||
public DateTime ДатаНачалаСборки;
|
||||
public DateTime ДатаКонцаСборки;
|
||||
|
||||
/// <summary>
|
||||
/// Договоры ресурсоснабжения
|
||||
/// </summary>
|
||||
public List<ГисДоговор> ДоговорыРСО = new List<ГисДоговор>();
|
||||
|
||||
public List<ГисАдресныйОбъект> АдресаОбъектов = new List<ГисАдресныйОбъект>();
|
||||
|
||||
public List<ГисЗдание> Здания = new List<ГисЗдание>();
|
||||
|
||||
public List<ГисЛицевойСчет> ЛицевыеСчета = new List<ГисЛицевойСчет>();
|
||||
|
||||
public List<ГисПриборУчета> ПриборыУчета = new List<ГисПриборУчета>();
|
||||
|
||||
public ГисДоговор НайтиДоговорПоНомеру(string номерДоговора)
|
||||
=> ДоговорыРСО.FirstOrDefault(x => x.НомерДоговора == номерДоговора);
|
||||
|
||||
public bool ЭтотЛицевойСчетСвязанСДоговорами(ГисЛицевойСчет лс)
|
||||
{
|
||||
return ДоговорыРСО.Any(договор => лс.СвязанСДоговором(договор));
|
||||
}
|
||||
|
||||
public ГисЗдание НайтиЗданиеПомещения(Guid гуидПомещения)
|
||||
{
|
||||
foreach (var здание in Здания)
|
||||
{
|
||||
foreach (var помещение in здание.Помещения)
|
||||
{
|
||||
if (помещение.ГуидПомещения == гуидПомещения) return здание;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ГисЗдание НайтиЗданиеЛицевогоСчета(ГисЛицевойСчет лс)
|
||||
{
|
||||
if (лс.Размещения == null) return null;
|
||||
|
||||
foreach (var размещение in лс.Размещения)
|
||||
{
|
||||
if (размещение.ГуидПомещения == null) continue;
|
||||
var здание = НайтиЗданиеПомещения((Guid)размещение.ГуидПомещения);
|
||||
if (здание != null) return здание;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void УдалитьЛицевыеСчетаЗдания(Guid гуидЗданияФиас)
|
||||
{
|
||||
var здание = Здания.FirstOrDefault(x => x.ГуидЗданияФиас == гуидЗданияФиас);
|
||||
if (здание == null || здание.Помещения == null) return;
|
||||
|
||||
var лсДляУдаления = new List<ГисЛицевойСчет>();
|
||||
var гуидыПомещенийЗдания = new HashSet<Guid>(здание.Помещения.Select(x => x.ГуидПомещения));
|
||||
|
||||
foreach (var лс in ЛицевыеСчета)
|
||||
{
|
||||
if (лс.Размещения == null) continue;
|
||||
foreach (var размещениеЛС in лс.Размещения)
|
||||
{
|
||||
if (размещениеЛС.ГуидПомещения == null) continue;
|
||||
if (гуидыПомещенийЗдания.Contains((Guid)размещениеЛС.ГуидПомещения))
|
||||
{
|
||||
лсДляУдаления.Add(лс);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var лсУдалить in лсДляУдаления)
|
||||
ЛицевыеСчета.Remove(лсУдалить);
|
||||
}
|
||||
|
||||
public int ЗаменитьЛицевыеСчетаЗданияВЛокальномСнимке(
|
||||
Guid гуидЗданияФиас, IEnumerable<ГисЛицевойСчет> лицевые)
|
||||
{
|
||||
УдалитьЛицевыеСчетаЗдания(гуидЗданияФиас);
|
||||
|
||||
var живые = лицевые.Where(лс => лс.ДействуетСейчас && ЭтотЛицевойСчетСвязанСДоговорами(лс));
|
||||
ЛицевыеСчета.AddRange(живые);
|
||||
return живые.Count();
|
||||
}
|
||||
|
||||
public bool ЭтотПриборСвязанСЛицевымиСчетами(ГисПриборУчета прибор)
|
||||
{
|
||||
return ЛицевыеСчета.Any(лс => прибор.СвязанСЛицевымСчетом(лс));
|
||||
}
|
||||
|
||||
public IEnumerable<ГисАдресныйОбъект> ДатьАдресаОбъектовДоговора(ГисДоговор договор)
|
||||
{
|
||||
return АдресаОбъектов.Where(x => x.СвязанСДоговором(договор));
|
||||
}
|
||||
|
||||
public IEnumerable<ГисПриборУчета> ДатьПриборыУчетаДоговора(ГисДоговор договор)
|
||||
{
|
||||
var адресаДоговора = ДатьАдресаОбъектовДоговора(договор).ToArray();
|
||||
var лицевыеДоговора = ЛицевыеСчета.Where(x => x.СвязанСДоговором(договор)).ToArray();
|
||||
|
||||
var приборы = new List<ГисПриборУчета>();
|
||||
foreach (var прибор in ПриборыУчета)
|
||||
{
|
||||
if (прибор == null) continue;
|
||||
|
||||
if (договор.ЭтоДоговорИКУ)
|
||||
{
|
||||
foreach (var адрес in адресаДоговора)
|
||||
{
|
||||
if (прибор.СвязанСАдреснымОбъектом(адрес)) приборы.Add(прибор);
|
||||
}
|
||||
}
|
||||
|
||||
if (договор.ЭтоДоговорНежилогоПомещения)
|
||||
{
|
||||
foreach (var лицевой in лицевыеДоговора)
|
||||
{
|
||||
if (прибор.СвязанСЛицевымСчетом(лицевой)) приборы.Add(прибор);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return приборы;
|
||||
}
|
||||
|
||||
public IEnumerable<ГисПомещение> ДатьПомещенияАдресногоОбъекта(ГисАдресныйОбъект адрес)
|
||||
{
|
||||
var здание = Здания.FirstOrDefault(x => x.ГуидЗданияФиас == адрес.ГуидЗданияФиас);
|
||||
if (здание == null) return new List<ГисПомещение>();
|
||||
return здание.Помещения;
|
||||
}
|
||||
|
||||
public IEnumerable<ГисПриборУчета> ДатьПриборыУчетаЛицевогоСчета(ГисЛицевойСчет лс)
|
||||
{
|
||||
return ПриборыУчета.Where(x => x.СвязанСЛицевымСчетом(лс));
|
||||
}
|
||||
|
||||
public ГисЗданиеПомещение НайтиПомещениеЛицевогоСчета(ГисЛицевойСчет лс)
|
||||
{
|
||||
foreach (var размещение in лс.Размещения)
|
||||
{
|
||||
foreach (var здание in Здания)
|
||||
{
|
||||
if (здание.Помещения == null) continue;
|
||||
foreach (var помещение in здание.Помещения)
|
||||
{
|
||||
if (помещение.ГуидПомещения == размещение.ГуидПомещения)
|
||||
{
|
||||
return new ГисЗданиеПомещение(здание, помещение);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ГисЗданиеПомещение(null, null);
|
||||
}
|
||||
|
||||
public static ГисДоговорыИПриборы ПрочитатьФайлJson(string jsonFileName)
|
||||
{
|
||||
using (StreamReader file = File.OpenText(jsonFileName))
|
||||
{
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
return (ГисДоговорыИПриборы)serializer.Deserialize(file, typeof(ГисДоговорыИПриборы));
|
||||
}
|
||||
}
|
||||
|
||||
public void ЗаписатьФайлJson(string jsonFileName)
|
||||
{
|
||||
using (StreamWriter file = File.CreateText(jsonFileName))
|
||||
{
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
serializer.Serialize(file, this);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ДоговорыРСО={ДоговорыРСО.Count} Адреса={АдресаОбъектов.Count}" +
|
||||
$" ЛС={ЛицевыеСчета.Count} ПУ={ПриборыУчета.Count}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Дом ГИС ЖКХ
|
||||
/// </summary>
|
||||
public class ГисЗдание
|
||||
{
|
||||
public ГисТипДома ТипДома;
|
||||
public Guid ГуидЗданияФиас;
|
||||
public string НомерДомаГис;
|
||||
|
||||
public ГисПомещение[] Помещения;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ТипДома} дом №ГИС={НомерДомаГис} Помещения={Помещения.Count()}";
|
||||
}
|
||||
}
|
||||
|
||||
public enum ГисТипДома { Многоквартирный, Жилой };
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
public record struct ГисЗданиеПомещение(ГисЗдание Здание, ГисПомещение Помещение)
|
||||
{
|
||||
public bool Пустое => (Здание == null || Помещение == null);
|
||||
public bool Заполнено => !Пустое;
|
||||
}
|
||||
}
|
||||
@ -1,72 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Сведения о контрагенте договора РСО
|
||||
/// </summary>
|
||||
public class ГисКонтрагент
|
||||
{
|
||||
public ГисТипКонтрагента ТипКонтрагента;
|
||||
|
||||
/// <summary>
|
||||
/// ГУИД из реестра организаций ГИС ЖКХ
|
||||
/// </summary>
|
||||
public Guid? ГуидОрганизации;
|
||||
|
||||
/// <summary>
|
||||
/// ГУИД версии организации из реестра организаций ГИС ЖКХ необходим
|
||||
/// для размещения Лицевого счета
|
||||
/// </summary>
|
||||
public Guid? ГуидВерсииОрганизации;
|
||||
|
||||
/// <summary>
|
||||
/// Сведения об индивидуальном физическом лице
|
||||
/// </summary>
|
||||
public ГисИндивид Индивид;
|
||||
}
|
||||
|
||||
public enum ГисТипКонтрагента
|
||||
{
|
||||
НеУказано,
|
||||
ВладелецПомещения,
|
||||
УправляющаяКомпания
|
||||
}
|
||||
|
||||
public class ГисИндивид
|
||||
{
|
||||
public string Фамилия;
|
||||
public string Имя;
|
||||
public string Отчество;
|
||||
public string СНИЛС;
|
||||
public string НомерДокумента;
|
||||
public string СерияДокумента;
|
||||
public DateTime? ДатаДокумента;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool СНИЛСЗаполнен
|
||||
=> !string.IsNullOrEmpty(СНИЛС);
|
||||
|
||||
[JsonIgnore]
|
||||
public string СНИЛСТолькоЦифры
|
||||
=> СНИЛСЗаполнен ? string.Concat(СНИЛС.Where(char.IsDigit)) : null;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool СНИЛСЗаполненВернойДлины
|
||||
=> (СНИЛСЗаполнен && СНИЛСТолькоЦифры.Length == 11);
|
||||
|
||||
public void ПроверитьЗаполнениеСНИЛС()
|
||||
{
|
||||
if (!СНИЛСЗаполненВернойДлины)
|
||||
throw new HcsException($"В СНИЛС контрагента ФЛ должно быть указано 11 цифр: {СНИЛС}");
|
||||
}
|
||||
|
||||
public void ПроверитьЗаполнениеФИО()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Фамилия)) throw new HcsException("Не заполнена Фамилия контрагента ФЛ");
|
||||
if (string.IsNullOrEmpty(Имя)) throw new HcsException("Не заполнено Имя контрагента ФЛ");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,112 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Лицевой счет из ГИС ЖКХ имеет номер единого лицевого счета (ЕЛС)
|
||||
/// и выдается на каждую точку поставки в жилом доме для договора
|
||||
/// по нежилым помещениям
|
||||
/// </summary>
|
||||
public class ГисЛицевойСчет
|
||||
{
|
||||
public Guid ГуидЛицевогоСчета;
|
||||
public string НомерЛицевогоСчета;
|
||||
public string НомерЕЛС;
|
||||
|
||||
public DateTime? ДатаСоздания;
|
||||
public DateTime? ДатаЗакрытия;
|
||||
public string КодНсиПричиныЗакрытия;
|
||||
public string ИмяПричиныЗакрытия;
|
||||
|
||||
public decimal? ПолнаяПлощадь;
|
||||
public decimal? ЖилаяПлощадь;
|
||||
public string КодЖКУ;
|
||||
|
||||
public ГисРазмещениеЛС[] Размещения;
|
||||
public ГисОснованиеЛС[] Основания;
|
||||
|
||||
public bool СвязанСДоговором(ГисДоговор договор)
|
||||
{
|
||||
if (договор != null && Основания != null && Основания.Any(
|
||||
основание => основание.ГуидДоговора == договор.ГуидВерсииДоговора ||
|
||||
основание.ГуидДоговора == договор.ГуидДоговора ||
|
||||
string.Compare(основание.НомерДоговора, договор.НомерДоговора) == 0)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ДействуетСейчас => (ДатаЗакрытия == null);
|
||||
|
||||
[JsonIgnore]
|
||||
public string ОписаниеРазмещений
|
||||
{
|
||||
get
|
||||
{
|
||||
var accomod = new StringBuilder();
|
||||
foreach (var x in Размещения) accomod.Append($"[{x}]");
|
||||
return accomod.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string ОписаниеОснований
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Основания == null) return null;
|
||||
var reasons = new StringBuilder();
|
||||
foreach (var x in Основания) reasons.Append($"[{x}]");
|
||||
return reasons.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ЛС №{НомерЛицевогоСчета} ЕЛС={НомерЕЛС}" +
|
||||
$" Создан={HcsUtil.FormatDate(ДатаСоздания)}" +
|
||||
$" Закрыт={HcsUtil.FormatDate(ДатаЗакрытия)}" +
|
||||
$" Размещения={ОписаниеРазмещений}" +
|
||||
$" Основания={ОписаниеОснований}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Лицевой счет может быть привязан к нескольким размещениям.
|
||||
/// Каждое размещение может быть или в здании, или в жилой комнате или в помещении
|
||||
/// </summary>
|
||||
public class ГисРазмещениеЛС
|
||||
{
|
||||
public Guid? ГуидЗдания;
|
||||
public Guid? ГуидПомещения;
|
||||
public Guid? ГуидЖилойКомнаты;
|
||||
public decimal? ПроцентДоли;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (ГуидЗдания != null) return $"Здание={ГуидЗдания}";
|
||||
if (ГуидПомещения != null) return $"Помещение={ГуидПомещения}";
|
||||
if (ГуидЖилойКомнаты != null) return $"ЖилКомната={ГуидЖилойКомнаты}";
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public enum ГисТипОснованияЛС { ДоговорРСО, Соцнайм, Договор }
|
||||
|
||||
/// <summary>
|
||||
/// Основание создания лицевого счета (договор на основании которого открыт ЛС)
|
||||
/// </summary>
|
||||
public class ГисОснованиеЛС
|
||||
{
|
||||
public ГисТипОснованияЛС ТипОснованияЛС;
|
||||
public Guid ГуидДоговора;
|
||||
public string НомерДоговора;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ТипОснованияЛС}={ГуидДоговора}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Сведения из реестра оргнаизации ГИС ЖКХ
|
||||
/// </summary>
|
||||
public class ГисОрганизация
|
||||
{
|
||||
public Guid ГуидОрганизации;
|
||||
|
||||
public Guid ГуидВерсииОрганизации;
|
||||
|
||||
public ГисТипОрганизации ТипОрганизации;
|
||||
|
||||
public string КраткоеИмяОрганизации;
|
||||
|
||||
public string ПолноеИмяОрганизации;
|
||||
|
||||
public bool Действующая;
|
||||
|
||||
public string ИНН;
|
||||
|
||||
public string КПП;
|
||||
|
||||
public string ОГРН;
|
||||
|
||||
public string ОКОПФ;
|
||||
|
||||
public string Фамилия;
|
||||
|
||||
public string Имя;
|
||||
|
||||
public string Отчество;
|
||||
|
||||
public string ЮридическийАдрес;
|
||||
|
||||
public DateTime? ДатаЛиквидации;
|
||||
|
||||
[JsonIgnore]
|
||||
public const int ДлинаОГРН = 13;
|
||||
|
||||
[JsonIgnore]
|
||||
public const int ДлинаОГРНИП = 15;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string имя = ТипОрганизации == ГисТипОрганизации.ИП ?
|
||||
$"ИП {Фамилия} {Имя} {Отчество}" : КраткоеИмяОрганизации;
|
||||
return $"{ТипОрганизации}: [{имя}] ИНН={ИНН} КПП={КПП} Действующая={Действующая}" +
|
||||
$" ГУИД={ГуидОрганизации} Версия={ГуидВерсииОрганизации}";
|
||||
}
|
||||
}
|
||||
|
||||
public enum ГисТипОрганизации { НетУказано, ЮЛ, ИП, Филиал, Иностранный }
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
public class ГисПоказания
|
||||
{
|
||||
public DateTime ДатаСнятия;
|
||||
public string ПоказанияТ1;
|
||||
public string ПоказанияТ2;
|
||||
public string ПоказанияТ3;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var buf = new StringBuilder();
|
||||
|
||||
if (!string.IsNullOrEmpty(ПоказанияТ1))
|
||||
{
|
||||
buf.AppendFormat("Т1={0}", ПоказанияТ1);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(ПоказанияТ2))
|
||||
{
|
||||
if (buf.Length > 0) buf.Append(" ");
|
||||
buf.AppendFormat("Т2={0}", ПоказанияТ2);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(ПоказанияТ3))
|
||||
{
|
||||
if (buf.Length > 0) buf.Append(" ");
|
||||
buf.AppendFormat("Т3={0}", ПоказанияТ3);
|
||||
}
|
||||
|
||||
if (ДатаСнятия != default)
|
||||
{
|
||||
if (buf.Length > 0) buf.Append(" ");
|
||||
buf.AppendFormat("на {0:d}", ДатаСнятия);
|
||||
}
|
||||
|
||||
return buf.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
public class ГисПолеЭлементаСправочника
|
||||
{
|
||||
public string наименование;
|
||||
public string значение;
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Жилое или нежилое момещение в доме ГИС ЖКХ
|
||||
/// </summary>
|
||||
public class ГисПомещение
|
||||
{
|
||||
public Guid ГуидПомещения;
|
||||
public bool ЭтоЖилоеПомещение;
|
||||
public string НомерПомещения;
|
||||
public DateTime? ДатаПрекращения;
|
||||
public string Аннулирование;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ГисПомещение={НомерПомещения} Жилое={ЭтоЖилоеПомещение} Guid={ГуидПомещения} Прекращено={ДатаПрекращения} Аннул={Аннулирование}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,102 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Прибор учета из ГИС ЖКХ может быть привязан к списку зданий (ОДПУ)
|
||||
/// или к списку Лицевых счетов (все виды кроме ОДПУ)
|
||||
/// </summary>
|
||||
public class ГисПриборУчета
|
||||
{
|
||||
public Guid ГуидПрибораУчета;
|
||||
public Guid ГуидВерсииПрибора;
|
||||
public string НомерПрибораУчетаГис;
|
||||
|
||||
public DateTime? ДатаРазмещенияВерсии;
|
||||
public Guid ГуидВладельцаПрибора;
|
||||
|
||||
public ГисСтатусПрибораУчета СтатусПрибораУчета;
|
||||
public ГисВидПрибораУчета ВидПрибораУчета;
|
||||
|
||||
public string ЗаводскойНомер;
|
||||
public string МодельПрибораУчета;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool КоэффициентТрансформацииУказан => (КоэффициентТрансформации > 0);
|
||||
public decimal КоэффициентТрансформации;
|
||||
|
||||
public string ПоказаниеТ1;
|
||||
public string ПоказаниеТ2;
|
||||
public string ПоказаниеТ3;
|
||||
|
||||
// TODO: Добавить эти комментарии как XML-комментарии
|
||||
public DateTime? ДатаИзготовления; // Обязательно при импорте
|
||||
public DateTime? ДатаУстановки;
|
||||
public DateTime? ДатаВводаВЭксплуатацию; // Обязательно кроме ОДПУ
|
||||
public DateTime? ДатаПоследнейПоверки; // Обязательно для ОДПУ
|
||||
|
||||
public bool РежимДистанционногоОпроса; // Признак наличия ИСУ
|
||||
public string ОписаниеДистанционногоОпроса; // Наименование ИСУ
|
||||
|
||||
public Guid[] ГуидыЗданийФиас;
|
||||
public Guid[] ГуидыЛицевыхСчетов;
|
||||
public Guid[] ГуидыПомещений;
|
||||
public Guid[] ГуидыЖилыхКомнат;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ЭтоАктивный => (СтатусПрибораУчета == ГисСтатусПрибораУчета.Активный);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ЭтоАрхивный => (СтатусПрибораУчета == ГисСтатусПрибораУчета.Архивный);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ЭтоОДПУ => (ВидПрибораУчета == ГисВидПрибораУчета.ОДПУ);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ЭтоНежилоеПомещение => (ВидПрибораУчета == ГисВидПрибораУчета.НежилоеПомещение);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ЭтоПриборЮЛ => ЭтоОДПУ || ЭтоНежилоеПомещение;
|
||||
|
||||
public bool СвязанСЛицевымСчетом(ГисЛицевойСчет лс)
|
||||
{
|
||||
if (лс == null || ГуидыЛицевыхСчетов == null || ГуидыЛицевыхСчетов.Length == 0) return false;
|
||||
if (ГуидыЛицевыхСчетов.Length == 1) return (ГуидыЛицевыхСчетов[0] == лс.ГуидЛицевогоСчета);
|
||||
return ГуидыЛицевыхСчетов.Contains(лс.ГуидЛицевогоСчета);
|
||||
}
|
||||
|
||||
public bool СвязанСАдреснымОбъектом(ГисАдресныйОбъект адрес)
|
||||
{
|
||||
// TODO: Для лицевых счетов здесь надо тестировать ГУИД помещения
|
||||
if (адрес == null || ГуидыЗданийФиас == null || ГуидыЗданийФиас.Length == 0) return false;
|
||||
if (ГуидыЗданийФиас.Length == 1) return ГуидыЗданийФиас[0] == адрес.ГуидЗданияФиас;
|
||||
return ГуидыЗданийФиас.Contains(адрес.ГуидЗданияФиас);
|
||||
}
|
||||
|
||||
public bool ЗаполненГуидЗданияФиас => (ГуидыЗданийФиас != null && ГуидыЗданийФиас.Length > 0);
|
||||
|
||||
public Guid? ОдинГуидЗданияФиас => (ЗаполненГуидЗданияФиас ? ГуидыЗданийФиас[0] : null);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
int числоЛС = ГуидыЛицевыхСчетов != null ? ГуидыЛицевыхСчетов.Length : 0;
|
||||
int числоДомов = ГуидыЗданийФиас != null ? ГуидыЗданийФиас.Length : 0;
|
||||
return $"{ВидПрибораУчета} {СтатусПрибораУчета} №{ЗаводскойНомер} [{МодельПрибораУчета}]" +
|
||||
$"Гуид={ГуидПрибораУчета} ЧислоЛС={числоЛС} ЧислоДомов={числоДомов}";
|
||||
}
|
||||
}
|
||||
|
||||
public enum ГисВидПрибораУчета
|
||||
{
|
||||
ЖилоеПомещение,
|
||||
НежилоеПомещение,
|
||||
ОДПУ,
|
||||
ЖилойДом,
|
||||
ЖилаяКомната,
|
||||
КоммунальнаяКвартира
|
||||
}
|
||||
|
||||
public enum ГисСтатусПрибораУчета { Активный, Архивный }
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
public class ГисСправочник
|
||||
{
|
||||
public string реестровыйНомер;
|
||||
public DateTime датаФормирования;
|
||||
public ГисЭлементСправочника[] элементы;
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi.DataTypes
|
||||
{
|
||||
public class ГисЭлементСправочника
|
||||
{
|
||||
public string код;
|
||||
public Guid гуид;
|
||||
public bool актуальный;
|
||||
public ГисПолеЭлементаСправочника[] поля;
|
||||
public ГисЭлементСправочника[] элементы;
|
||||
}
|
||||
}
|
||||
@ -1,106 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,135 +0,0 @@
|
||||
using Hcs.ClientApi.RemoteCaller;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DebtRequests = Hcs.Service.Async.DebtRequests.v15_7_0_1;
|
||||
|
||||
namespace Hcs.Service.Async.DebtRequests.v15_7_0_1
|
||||
{
|
||||
public partial class AckRequestAck : IHcsAck { }
|
||||
public partial class getStateResult : IHcsGetStateResultMany { }
|
||||
public partial class Fault : IHcsFault { }
|
||||
public partial class HeaderType : IHcsHeaderType { }
|
||||
}
|
||||
|
||||
namespace Hcs.ClientApi.DebtRequestsApi
|
||||
{
|
||||
/// Метод для отправки запросов к сервису запросов о наличии задолженности
|
||||
/// Описание: http://open-gkh.ru/DebtRequestsServiceAsync/
|
||||
public class HcsDebtRequestsMethod : HcsRemoteCallMethod<IHcsGetStateResultMany>
|
||||
{
|
||||
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<IHcsGetStateResultMany> TryGetResultAsync(
|
||||
IHcsAck sourceAck, CancellationToken token = default)
|
||||
{
|
||||
Func<Task<IHcsGetStateResultMany>> func = async () => await TryGetResultBareAsync(sourceAck);
|
||||
return await RunRepeatableTaskInsistentlyAsync(func, token);
|
||||
}
|
||||
|
||||
private async Task<IHcsGetStateResultMany> 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(IHcsGetStateResultMany 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1,141 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DebtRequests = Hcs.Service.Async.DebtRequests.v15_7_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,251 +0,0 @@
|
||||
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.IHcsGetStateResultMany 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hcs.ClientApi.DeviceMeteringApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Методы ГИС ЖКХ сервиса hcs-device-metering (показания приборов учета)
|
||||
/// </summary>
|
||||
public class HcsDeviceMeteringApi
|
||||
{
|
||||
public HcsClientConfig Config { get; private set; }
|
||||
|
||||
public HcsDeviceMeteringApi(HcsClientConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
}
|
||||
|
||||
public async Task<DateTime> РазместитьПоказания(
|
||||
ГисПриборУчета прибор, ГисПоказания показания, CancellationToken token = default)
|
||||
{
|
||||
var method = new HcsMethodImportMeteringDevicesValues(Config);
|
||||
return await method.ImportMeteringDevicesValues(прибор, показания, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,118 +0,0 @@
|
||||
using Hcs.ClientApi.RemoteCaller;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DeviceMetering = Hcs.Service.Async.DeviceMetering.v15_7_0_1;
|
||||
|
||||
namespace Hcs.Service.Async.DeviceMetering.v15_7_0_1
|
||||
{
|
||||
public partial class AckRequestAck : IHcsAck { }
|
||||
public partial class getStateResult : IHcsGetStateResultMany { }
|
||||
public partial class Fault : IHcsFault { }
|
||||
public partial class HeaderType : IHcsHeaderType { }
|
||||
}
|
||||
|
||||
namespace Hcs.ClientApi.DeviceMeteringApi
|
||||
{
|
||||
public class HcsDeviceMeteringMethod : HcsRemoteCallMethod<IHcsGetStateResultMany>
|
||||
{
|
||||
public HcsEndPoints EndPoint => HcsEndPoints.DeviceMeteringAsync;
|
||||
|
||||
public DeviceMetering.RequestHeader CreateRequestHeader() =>
|
||||
HcsRequestHelper.CreateHeader<DeviceMetering.RequestHeader>(ClientConfig);
|
||||
|
||||
public HcsDeviceMeteringMethod(HcsClientConfig config) : base(config) { }
|
||||
|
||||
public System.ServiceModel.EndpointAddress RemoteAddress
|
||||
=> GetEndpointAddress(HcsConstants.EndPointLocator.GetPath(EndPoint));
|
||||
|
||||
private DeviceMetering.DeviceMeteringPortTypesAsyncClient NewPortClient()
|
||||
{
|
||||
var client = new DeviceMetering.DeviceMeteringPortTypesAsyncClient(_binding, RemoteAddress);
|
||||
ConfigureEndpointCredentials(client.Endpoint, client.ClientCredentials);
|
||||
return client;
|
||||
}
|
||||
|
||||
public async Task<IHcsGetStateResultMany> SendAndWaitResultAsync(
|
||||
object request,
|
||||
Func<DeviceMetering.DeviceMeteringPortTypesAsyncClient, Task<IHcsAck>> sender,
|
||||
CancellationToken token)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
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<IHcsGetStateResultMany> SendAndWaitResultAsyncImpl(
|
||||
object request,
|
||||
Func<DeviceMetering.DeviceMeteringPortTypesAsyncClient, 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<DeviceMetering.ErrorMessageType>().ToList().ForEach(x =>
|
||||
{
|
||||
throw HcsRemoteException.CreateNew(x.ErrorCode, x.Description);
|
||||
});
|
||||
|
||||
return stateResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполняет однократную проверку наличия результата.
|
||||
/// Возвращает null если результата еще нет.
|
||||
/// </summary>
|
||||
protected override async Task<IHcsGetStateResultMany> TryGetResultAsync(IHcsAck sourceAck, CancellationToken token)
|
||||
{
|
||||
using (var client = NewPortClient())
|
||||
{
|
||||
var requestHeader = HcsRequestHelper.CreateHeader<DeviceMetering.RequestHeader>(_config);
|
||||
var requestBody = new DeviceMetering.getStateRequest { MessageGUID = sourceAck.MessageGUID };
|
||||
|
||||
var response = await client.getStateAsync(requestHeader, requestBody);
|
||||
var resultBody = response.getStateResult;
|
||||
|
||||
if (resultBody.RequestState == HcsAsyncRequestStateTypes.Ready)
|
||||
{
|
||||
return resultBody;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Hcs.ClientApi.DeviceMeteringApi
|
||||
{
|
||||
public class HcsDeviceMeteringUtil
|
||||
{
|
||||
public static string ConvertMeterReading(string reading, bool isRequired)
|
||||
{
|
||||
if (string.IsNullOrEmpty(reading)) return (isRequired ? "0" : null);
|
||||
|
||||
// TODO: Проверить комментарий
|
||||
// Исправляем типичный отказ ГИС в приеме показаний: заменяем запятую на точку
|
||||
string betterReading = reading.Contains(",") ? reading.Replace(",", ".") : reading;
|
||||
|
||||
// Шаблон из: http://open-gkh.ru/MeteringDeviceBase/MeteringValueType.html
|
||||
var match = Regex.Match(betterReading, "^\\d{1,15}(\\.\\d{1,7})?$");
|
||||
if (match.Success) return betterReading;
|
||||
|
||||
throw new HcsException($"Значение показания \"{reading}\" не соответствует требованиям ГИС: N.N");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DeviceMetering = Hcs.Service.Async.DeviceMetering.v15_7_0_1;
|
||||
|
||||
namespace Hcs.ClientApi.DeviceMeteringApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Размещение в ГИС показаний прибора учета
|
||||
/// http://open-gkh.ru/DeviceMetering/importMeteringDeviceValuesRequest.html
|
||||
/// </summary>
|
||||
public class HcsMethodImportMeteringDevicesValues : HcsDeviceMeteringMethod
|
||||
{
|
||||
public HcsMethodImportMeteringDevicesValues(HcsClientConfig config) : base(config)
|
||||
{
|
||||
CanBeRestarted = false;
|
||||
}
|
||||
|
||||
public async Task<DateTime> ImportMeteringDevicesValues(
|
||||
ГисПриборУчета прибор, ГисПоказания показания, CancellationToken token)
|
||||
{
|
||||
if (прибор == null) throw new ArgumentNullException(nameof(прибор));
|
||||
if (показания == null) throw new ArgumentNullException(nameof(показания));
|
||||
|
||||
var current = new DeviceMetering.importMeteringDeviceValuesRequestMeteringDevicesValuesElectricDeviceValueCurrentValue()
|
||||
{
|
||||
TransportGUID = FormatGuid(Guid.NewGuid()),
|
||||
DateValue = показания.ДатаСнятия,
|
||||
MeteringValueT1 = HcsDeviceMeteringUtil.ConvertMeterReading(показания.ПоказанияТ1, false),
|
||||
MeteringValueT2 = HcsDeviceMeteringUtil.ConvertMeterReading(показания.ПоказанияТ2, false),
|
||||
MeteringValueT3 = HcsDeviceMeteringUtil.ConvertMeterReading(показания.ПоказанияТ3, false)
|
||||
};
|
||||
|
||||
var electric = new DeviceMetering.importMeteringDeviceValuesRequestMeteringDevicesValuesElectricDeviceValue()
|
||||
{
|
||||
CurrentValue = current
|
||||
};
|
||||
|
||||
var value = new DeviceMetering.importMeteringDeviceValuesRequestMeteringDevicesValues()
|
||||
{
|
||||
ItemElementName = DeviceMetering.ItemChoiceType.MeteringDeviceRootGUID,
|
||||
Item = FormatGuid(прибор.ГуидПрибораУчета),
|
||||
Item1 = electric
|
||||
};
|
||||
|
||||
var request = new DeviceMetering.importMeteringDeviceValuesRequest()
|
||||
{
|
||||
Id = HcsConstants.SignedXmlElementId,
|
||||
MeteringDevicesValues = [value]
|
||||
};
|
||||
|
||||
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
|
||||
{
|
||||
var ackResponse = await portClient.importMeteringDeviceValuesAsync(
|
||||
CreateRequestHeader(), request);
|
||||
return ackResponse.AckRequest.Ack;
|
||||
}, token);
|
||||
|
||||
|
||||
if (IsArrayEmpty(stateResult.Items)) throw new HcsException("Пустой stateResult.Items");
|
||||
|
||||
stateResult.Items.OfType<DeviceMetering.CommonResultTypeError>().ToList()
|
||||
.ForEach(error => { throw HcsRemoteException.CreateNew(error.ErrorCode, error.Description); });
|
||||
|
||||
var commonResult = RequireSingleItem<DeviceMetering.CommonResultType>(stateResult.Items);
|
||||
if (IsArrayEmpty(commonResult.Items)) throw new HcsException("Пустой commonResult.Items");
|
||||
|
||||
DateTime датаПриема = commonResult.Items.OfType<DateTime>().FirstOrDefault();
|
||||
if (датаПриема == default) throw new HcsException("Сервер не вернул дату приема им показаний");
|
||||
return датаПриема;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,394 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hcs.ClientApi.FileStoreServiceApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Описание протокола в файле "ГИС ЖКХ. Альбом ТФФ 14.5.0.1.docx"
|
||||
/// 2.5 Описание протокола обмена файлами с внешними системами
|
||||
public class HcsFileStoreServiceApi
|
||||
{
|
||||
public HcsClientConfig Config { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Максимальный размер в байтах части файла, которую разрешено
|
||||
/// загружать на сервер по спецификации протокола
|
||||
/// </summary>
|
||||
private const int MAX_PART_LENGTH = 5242880;
|
||||
|
||||
public HcsFileStoreServiceApi(HcsClientConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Путь к сервису хранения файлов ГИС ЖКХ на серевере API
|
||||
/// </summary>
|
||||
private const string ExtBusFileStoreServiceRest = "ext-bus-file-store-service/rest";
|
||||
|
||||
/// <summary>
|
||||
/// Получение файла ранее загруженного в ГИС ЖКХ
|
||||
/// </summary>
|
||||
public async Task<HcsFile> DownloadFile(
|
||||
Guid fileGuid, HcsFileStoreContext context, CancellationToken token)
|
||||
{
|
||||
long length = await GetFileLength(context, fileGuid, token);
|
||||
if (length <= MAX_PART_LENGTH) return await DownloadSmallFile(fileGuid, context, token);
|
||||
return await DownloadLargeFile(fileGuid, length, context, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение файла по частям (не более 5Мб) по GUID файла
|
||||
/// </summary>
|
||||
private async Task<HcsFile> DownloadLargeFile(
|
||||
Guid fileGuid, long fileSize, HcsFileStoreContext context, CancellationToken token)
|
||||
{
|
||||
if (fileSize <= MAX_PART_LENGTH)
|
||||
throw new ArgumentException("Too short file for partial download");
|
||||
|
||||
string requestUri = ComposeFileDownloadUri(fileGuid, context);
|
||||
|
||||
var resultStream = new MemoryStream();
|
||||
string resultContentType = null;
|
||||
using (var client = BuildHttpClient())
|
||||
{
|
||||
|
||||
long doneSize = 0;
|
||||
while (doneSize < fileSize)
|
||||
{
|
||||
|
||||
long remainderSize = fileSize - doneSize;
|
||||
long partSize = Math.Min(remainderSize, MAX_PART_LENGTH);
|
||||
|
||||
long fromPosition = doneSize;
|
||||
long toPosition = fromPosition + partSize - 1;
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
|
||||
request.Headers.Range = new RangeHeaderValue(fromPosition, toPosition);
|
||||
|
||||
var response = await SendRequestAsync(client, request, token);
|
||||
resultContentType = response.Content.Headers.ContentType.ToString();
|
||||
|
||||
long? responseSize = response.Content.Headers.ContentLength;
|
||||
if (responseSize == null || (long)responseSize != partSize)
|
||||
throw new HcsException($"Получена часть файла длиной {responseSize}, а запрашивалась длина {partSize}");
|
||||
|
||||
using (var partStream = await response.Content.ReadAsStreamAsync())
|
||||
{
|
||||
partStream.Position = 0;
|
||||
await partStream.CopyToAsync(resultStream);
|
||||
}
|
||||
|
||||
doneSize += partSize;
|
||||
}
|
||||
|
||||
resultStream.Position = 0;
|
||||
return new HcsFile(null, resultContentType, resultStream);
|
||||
}
|
||||
}
|
||||
|
||||
private string ComposeFileDownloadUri(Guid fileGuid, HcsFileStoreContext context)
|
||||
{
|
||||
string endpointName = $"{ExtBusFileStoreServiceRest}/{context.GetName()}/{HcsUtil.FormatGuid(fileGuid)}?getfile";
|
||||
return Config.ComposeEndpointUri(endpointName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение файла одной частью (не более 5Мб) по GUID файла
|
||||
/// </summary>
|
||||
private async Task<HcsFile> DownloadSmallFile(
|
||||
Guid fileGuid, HcsFileStoreContext context, CancellationToken token)
|
||||
{
|
||||
string requestUri = ComposeFileDownloadUri(fileGuid, context);
|
||||
using (var client = BuildHttpClient())
|
||||
{
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
|
||||
var response = await SendRequestAsync(client, request, token);
|
||||
|
||||
return new HcsFile(
|
||||
null,
|
||||
response.Content.Headers.ContentType.ToString(),
|
||||
await response.Content.ReadAsStreamAsync());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Guid> UploadFile(HcsFile file, HcsFileStoreContext context, CancellationToken token)
|
||||
{
|
||||
if (file is null) throw new ArgumentNullException(nameof(file));
|
||||
|
||||
if (file.Length <= MAX_PART_LENGTH)
|
||||
{
|
||||
return await UploadSmallFile(file, context, token);
|
||||
}
|
||||
else
|
||||
{
|
||||
return await UploadLargeFile(file, context, token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправка большого файла по частям
|
||||
/// </summary>
|
||||
private async Task<Guid> UploadLargeFile(HcsFile file, HcsFileStoreContext context, CancellationToken token)
|
||||
{
|
||||
using var client = BuildHttpClient();
|
||||
|
||||
if (file.Length == 0) throw new ArgumentException("Нельзя передавать файл нулевой длины");
|
||||
int numParts = (int)Math.Ceiling((double)file.Length / MAX_PART_LENGTH);
|
||||
|
||||
Config.Log($"Запрашиваю UploadID для большого файла {file.FileName}");
|
||||
Guid uploadId = await QueryNewUploadId(client, context, file, numParts, token);
|
||||
Config.Log($"Получил UploadID {uploadId} для отправки файла {file.FileName} размером {file.Length} байт");
|
||||
|
||||
long partOffset = 0;
|
||||
for (int partNumber = 1; partNumber <= numParts; partNumber++)
|
||||
{
|
||||
|
||||
long lengthLeft = file.Length - partOffset;
|
||||
int partLength = (int)Math.Min(lengthLeft, MAX_PART_LENGTH);
|
||||
var partStream = new HcsPartialStream(file.Stream, partOffset, partLength);
|
||||
|
||||
Config.Log($"Отправляю часть {partNumber}/{numParts} размером {partLength} байт для файла {file.FileName}");
|
||||
await UploadFilePart(client, context, uploadId, partNumber, partStream, token);
|
||||
partOffset += partLength;
|
||||
}
|
||||
|
||||
Config.Log($"Отправляем признак завершения передачи файла {file.FileName}");
|
||||
await CompleteUpload(client, context, uploadId, token);
|
||||
|
||||
Config.Log($"Файл {file.FileName} успешно передан, получен код файла {uploadId}");
|
||||
return uploadId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение кода для загрузки большого файла из нескольких частей менее 5Мб
|
||||
/// </summary>
|
||||
private async Task<Guid> QueryNewUploadId(
|
||||
HttpClient client, HcsFileStoreContext context, HcsFile file, int numParts, CancellationToken token)
|
||||
{
|
||||
string endpointName = $"{ExtBusFileStoreServiceRest}/{context.GetName()}/?upload";
|
||||
string requestUri = Config.ComposeEndpointUri(endpointName);
|
||||
|
||||
var content = new StringContent("");
|
||||
content.Headers.Add("X-Upload-Filename", CleanUploadFileName(file.FileName));
|
||||
content.Headers.Add("X-Upload-Length", file.Length.ToString());
|
||||
content.Headers.Add("X-Upload-Part-Count", numParts.ToString());
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
|
||||
request.Content = content;
|
||||
var response = await SendRequestAsync(client, request, token);
|
||||
return ParseUploadIdFromReponse(response);
|
||||
}
|
||||
|
||||
private async Task UploadFilePart(
|
||||
HttpClient client, HcsFileStoreContext context, Guid uploadId, int partNumber, Stream partStream,
|
||||
CancellationToken token)
|
||||
{
|
||||
string endpointName = $"{ExtBusFileStoreServiceRest}/{context.GetName()}/{HcsUtil.FormatGuid(uploadId)}";
|
||||
string requestUri = Config.ComposeEndpointUri(endpointName);
|
||||
|
||||
var content = new StreamContent(partStream);
|
||||
content.Headers.Add("X-Upload-Partnumber", partNumber.ToString());
|
||||
content.Headers.ContentMD5 = ComputeMD5(partStream);
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Put, requestUri);
|
||||
request.Content = content;
|
||||
await SendRequestAsync(client, request, token);
|
||||
}
|
||||
|
||||
private async Task CompleteUpload(HttpClient client, HcsFileStoreContext context, Guid uploadId, CancellationToken token)
|
||||
{
|
||||
string endpointName = $"{ExtBusFileStoreServiceRest}/{context.GetName()}/{HcsUtil.FormatGuid(uploadId)}?completed";
|
||||
string requestUri = Config.ComposeEndpointUri(endpointName);
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
|
||||
await SendRequestAsync(client, request, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Загрузка в ГИС ЖКХ файла до 5Мб размером одной операцией
|
||||
/// </summary>
|
||||
private async Task<Guid> UploadSmallFile(HcsFile file, HcsFileStoreContext context, CancellationToken token)
|
||||
{
|
||||
using var client = BuildHttpClient();
|
||||
|
||||
string endpointName = $"{ExtBusFileStoreServiceRest}/{context.GetName()}";
|
||||
string requestUri = Config.ComposeEndpointUri(endpointName);
|
||||
|
||||
Config.Log($"Начинаю upload малого файла [{file.FileName}] типа [{file.ContentType}] длиной {file.Length}");
|
||||
|
||||
if (file.Stream.Length != file.Length)
|
||||
throw new HcsException($"Длина файла {file.Length} не соответствует размеру данных {file.Stream.Length}");
|
||||
|
||||
file.Stream.Position = 0;
|
||||
|
||||
var content = new StreamContent(file.Stream);
|
||||
content.Headers.Add("X-Upload-Filename", CleanUploadFileName(file.FileName));
|
||||
content.Headers.ContentMD5 = ComputeMD5(file.Stream);
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Put, requestUri);
|
||||
request.Content = content;
|
||||
var response = await SendRequestAsync(client, request, token);
|
||||
return ParseUploadIdFromReponse(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение информации о загружаемом или загруженном файле
|
||||
/// </summary>
|
||||
public async Task<long> GetFileLength(HcsFileStoreContext context, Guid fileId, CancellationToken token)
|
||||
{
|
||||
using var client = BuildHttpClient();
|
||||
|
||||
string endpointName = $"{ExtBusFileStoreServiceRest}/{context.GetName()}/{HcsUtil.FormatGuid(fileId)}";
|
||||
string requestUri = Config.ComposeEndpointUri(endpointName);
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Head, requestUri);
|
||||
var response = await SendRequestAsync(client, request, token);
|
||||
|
||||
long length = 0;
|
||||
var lengthString = SearchResponseHeader(response, "X-Upload-Length");
|
||||
if (!string.IsNullOrEmpty(lengthString) && long.TryParse(lengthString, out length)) return length;
|
||||
throw new HcsException("В ответе сервера не указана длина файла");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает вычисленное значение AttachmentHASH для данных файла @stream
|
||||
/// </summary>
|
||||
public string ComputeAttachmentHash(Stream stream)
|
||||
{
|
||||
var client = Config as HcsClient;
|
||||
if (client == null) throw new HcsException("Не доступен объект HcsClient для вычиления AttachmentHASH");
|
||||
|
||||
// TODO: Проверить комментарий
|
||||
// В декабре 2024 у меня сломалось вычисление AttachmentHASH для файлов, я стал вычислять
|
||||
// явно верным алгоритмом ГОСТ94 для больших файлов уже неверное значение суммы. В январе
|
||||
// 2025 путем перебора вариантов я обнаружил что ГИСЖКХ теперь вычисляет AttachmentHASH
|
||||
// только по первой части большого файла.
|
||||
//int hashSourceMaxLength = MAX_PART_LENGTH;
|
||||
//if (stream.Length <= hashSourceMaxLength) return client.ComputeGost94Hash(stream);
|
||||
//return client.ComputeGost94Hash(new HcsPartialStream(stream, 0, hashSourceMaxLength));
|
||||
|
||||
// 29.01.2025 СТП ГИС ЖКХ ответила что "проведены работы" и теперь
|
||||
// я вижу что они снова вычисляют AttachmantHASH по полному файлу
|
||||
return client.ComputeGost94Hash(stream);
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> SendRequestAsync(
|
||||
HttpClient client, HttpRequestMessage request, CancellationToken token)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
Config.Log($"Отправляю запрос {request.Method} \"{request.RequestUri}\"...");
|
||||
|
||||
var response = await client.SendAsync(request, token);
|
||||
if (response.IsSuccessStatusCode) return response;
|
||||
throw new HcsException(DescribeResponseError(response));
|
||||
}
|
||||
|
||||
private Guid ParseUploadIdFromReponse(HttpResponseMessage response)
|
||||
{
|
||||
string uploadIdheaderName = "X-Upload-UploadID";
|
||||
var uploadId = SearchResponseHeader(response, uploadIdheaderName);
|
||||
if (uploadId != null) return HcsUtil.ParseGuid(uploadId);
|
||||
throw new HcsException($"В ответе сервера нет заголовка {uploadIdheaderName}");
|
||||
}
|
||||
|
||||
private HttpClient BuildHttpClient()
|
||||
{
|
||||
var _clientHandler = new HttpClientHandler();
|
||||
_clientHandler.ClientCertificates.Add(Config.Certificate);
|
||||
_clientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
|
||||
|
||||
var client = new HttpClient(_clientHandler);
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
|
||||
client.DefaultRequestHeaders.Add("X-Upload-OrgPPAGUID", Config.OrgPPAGUID);
|
||||
return client;
|
||||
}
|
||||
|
||||
private string DescribeResponseError(HttpResponseMessage response)
|
||||
{
|
||||
string errorHeader = "X-Upload-Error";
|
||||
var message = SearchResponseHeader(response, errorHeader);
|
||||
if (message != null)
|
||||
{
|
||||
if (knownErrors.ContainsKey(message)) return $"{errorHeader}: {message} ({knownErrors[message]})";
|
||||
return $"{errorHeader}: {message}";
|
||||
}
|
||||
|
||||
return $"HTTP response status {response.StatusCode}";
|
||||
}
|
||||
|
||||
private string SearchResponseHeader(HttpResponseMessage response, string headerName)
|
||||
{
|
||||
if (response.Headers.Any(x => x.Key == headerName))
|
||||
{
|
||||
var pair = response.Headers.First(x => x.Key == headerName);
|
||||
if (pair.Value != null && pair.Value.Any())
|
||||
{
|
||||
return pair.Value.First();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> knownErrors = new Dictionary<string, string>() {
|
||||
{ "FieldValidationException", "не пройдены проверки на корректность заполнения полей (обязательность, формат и т.п.)" },
|
||||
{ "FileNotFoundException", "не пройдены проверки на существование файла" },
|
||||
{ "InvalidStatusException", "не пройдены проверки на корректный статус файла" },
|
||||
{ "InvalidSizeException", "некорректный запрашиваемый размер файла" },
|
||||
{ "FileVirusInfectionException", "содержимое файла инфицировано" },
|
||||
{ "FileVirusNotCheckedException", "проверка на вредоносное содержимое не выполнялась" },
|
||||
{ "FilePermissionException", "организация и внешняя система не имеют полномочий на скачивание файла" },
|
||||
{ "DataProviderValidationException", "поставщик данных не найден, заблокирован или неактивен" },
|
||||
{ "CertificateValidationException", "информационная система не найдена по отпечатку или заблокирована" },
|
||||
{ "HashConflictException", "не пройдены проверки на соответствие контрольной сумме" },
|
||||
{ "InvalidPartNumberException", "не пройдены проверки на номер части (номер превышает количество частей, указанных в инициализации)" },
|
||||
{ "ContextNotFoundException", "неверное имя хранилища файлов" },
|
||||
{ "ExtensionException", "недопустимое расширение файла" },
|
||||
{ "DetectionException", "не удалось определить MIME-тип загружаемого файла" },
|
||||
{ "INT002029", "сервис недоступен: выполняются регламентные работы" }
|
||||
};
|
||||
|
||||
private byte[] ComputeMD5(System.IO.Stream stream)
|
||||
{
|
||||
var position = stream.Position;
|
||||
var md5 = System.Security.Cryptography.MD5.Create().ComputeHash(stream);
|
||||
stream.Position = position;
|
||||
return md5;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Готовит имя размещаемого файла для помещения в заголовок HTTP-запроса
|
||||
/// </summary>
|
||||
private string CleanUploadFileName(string fileName)
|
||||
{
|
||||
if (fileName is null) return null;
|
||||
|
||||
string bannedSymbols = "<>?:|*%\\\"";
|
||||
|
||||
var buf = new StringBuilder();
|
||||
foreach (char ch in fileName)
|
||||
{
|
||||
if (bannedSymbols.Contains(ch)) buf.Append('_');
|
||||
else buf.Append(ch);
|
||||
}
|
||||
|
||||
// Спецификация предписывает кодировать имя файла по стандарту MIME RFC2047
|
||||
// https://datatracker.ietf.org/doc/html/rfc2047
|
||||
// Как имя кодировки можно явно использовать константу "windows-1251".
|
||||
string characterSet = Encoding.Default.WebName;
|
||||
return EncodedWord.RFC2047.Encode(
|
||||
buf.ToString(), EncodedWord.RFC2047.ContentEncoding.Base64, characterSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,374 +0,0 @@
|
||||
//===============================================================================
|
||||
// RFC2047 (Encoded Word) Decoder
|
||||
// https://github.com/grumpydev/RFC2047-Encoded-Word-Encoder-Decoder/blob/master/EncodedWord/RFC2047.cs
|
||||
// http://tools.ietf.org/html/rfc2047
|
||||
//===============================================================================
|
||||
// Copyright © Steven Robbins. All rights reserved.
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
|
||||
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//===============================================================================
|
||||
|
||||
namespace EncodedWord
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides support for decoding RFC2047 (Encoded Word) encoded text
|
||||
/// </summary>
|
||||
public static class RFC2047
|
||||
{
|
||||
/// <summary>
|
||||
/// Regex for parsing encoded word sections
|
||||
/// From http://tools.ietf.org/html/rfc2047#section-3
|
||||
/// encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
|
||||
/// </summary>
|
||||
private static readonly Regex EncodedWordFormatRegEx = new Regex(@"=\?(?<charset>.*?)\?(?<encoding>[qQbB])\?(?<encodedtext>.*?)\?=", RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Regex for removing CRLF SPACE separators from between encoded words
|
||||
/// </summary>
|
||||
private static readonly Regex EncodedWordSeparatorRegEx = new Regex(@"\?=\r\n =\?", RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Replacement string for removing CRLF SPACE separators
|
||||
/// </summary>
|
||||
private const string SeparatorReplacement = @"?==?";
|
||||
|
||||
/// <summary>
|
||||
/// The maximum line length allowed
|
||||
/// </summary>
|
||||
private const int MaxLineLength = 75;
|
||||
|
||||
/// <summary>
|
||||
/// Regex for "Q-Encoding" hex bytes from http://tools.ietf.org/html/rfc2047#section-4.2
|
||||
/// </summary>
|
||||
private static readonly Regex QEncodingHexCodeRegEx = new Regex(@"(=(?<hexcode>[0-9a-fA-F][0-9a-fA-F]))", RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Regex for replacing _ with space as declared in http://tools.ietf.org/html/rfc2047#section-4.2
|
||||
/// </summary>
|
||||
private static readonly Regex QEncodingSpaceRegEx = new Regex("_", RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Format for an encoded string
|
||||
/// </summary>
|
||||
private const string EncodedStringFormat = @"=?{0}?{1}?{2}?=";
|
||||
|
||||
/// <summary>
|
||||
/// Special characters, as defined by RFC2047
|
||||
/// </summary>
|
||||
private static readonly char[] SpecialCharacters = { '(', ')', '<', '>', '@', ',', ';', ':', '<', '>', '/', '[', ']', '?', '.', '=', '\t' };
|
||||
|
||||
/// <summary>
|
||||
/// Represents a content encoding type defined in RFC2047
|
||||
/// </summary>
|
||||
public enum ContentEncoding
|
||||
{
|
||||
/// <summary>
|
||||
/// Unknown / invalid encoding
|
||||
/// </summary>
|
||||
Unknown,
|
||||
|
||||
/// <summary>
|
||||
/// "Q Encoding" (reduced character set) encoding
|
||||
/// http://tools.ietf.org/html/rfc2047#section-4.2
|
||||
/// </summary>
|
||||
QEncoding,
|
||||
|
||||
/// <summary>
|
||||
/// Base 64 encoding
|
||||
/// http://tools.ietf.org/html/rfc2047#section-4.1
|
||||
/// </summary>
|
||||
Base64
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode a string into RFC2047
|
||||
/// </summary>
|
||||
/// <param name="plainString">Plain string to encode</param>
|
||||
/// <param name="contentEncoding">Content encoding to use</param>
|
||||
/// <param name="characterSet">Character set used by plainString</param>
|
||||
/// <returns>Encoded string</returns>
|
||||
public static string Encode(string plainString, ContentEncoding contentEncoding = ContentEncoding.QEncoding, string characterSet = "iso-8859-1")
|
||||
{
|
||||
if (String.IsNullOrEmpty(plainString))
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
if (contentEncoding == ContentEncoding.Unknown)
|
||||
{
|
||||
throw new ArgumentException("contentEncoding cannot be unknown for encoding.", "contentEncoding");
|
||||
}
|
||||
|
||||
if (!IsSupportedCharacterSet(characterSet))
|
||||
{
|
||||
throw new ArgumentException("characterSet is not supported", "characterSet");
|
||||
}
|
||||
|
||||
var textEncoding = Encoding.GetEncoding(characterSet);
|
||||
|
||||
var encoder = GetContentEncoder(contentEncoding);
|
||||
|
||||
var encodedContent = encoder.Invoke(plainString, textEncoding);
|
||||
|
||||
return BuildEncodedString(characterSet, contentEncoding, encodedContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode a string containing RFC2047 encoded sections
|
||||
/// </summary>
|
||||
/// <param name="encodedString">String contaning encoded sections</param>
|
||||
/// <returns>Decoded string</returns>
|
||||
public static string Decode(string encodedString)
|
||||
{
|
||||
// Remove separators
|
||||
var decodedString = EncodedWordSeparatorRegEx.Replace(encodedString, SeparatorReplacement);
|
||||
|
||||
return EncodedWordFormatRegEx.Replace(
|
||||
decodedString,
|
||||
m =>
|
||||
{
|
||||
var contentEncoding = GetContentEncodingType(m.Groups["encoding"].Value);
|
||||
if (contentEncoding == ContentEncoding.Unknown)
|
||||
{
|
||||
// Regex should never match, but return anyway
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var characterSet = m.Groups["charset"].Value;
|
||||
if (!IsSupportedCharacterSet(characterSet))
|
||||
{
|
||||
// Fall back to iso-8859-1 if invalid/unsupported character set found
|
||||
characterSet = @"iso-8859-1";
|
||||
}
|
||||
|
||||
var textEncoding = Encoding.GetEncoding(characterSet);
|
||||
var contentDecoder = GetContentDecoder(contentEncoding);
|
||||
var encodedText = m.Groups["encodedtext"].Value;
|
||||
|
||||
return contentDecoder.Invoke(encodedText, textEncoding);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a character set is supported
|
||||
/// </summary>
|
||||
/// <param name="characterSet">Character set name</param>
|
||||
/// <returns>Bool representing whether the character set is supported</returns>
|
||||
private static bool IsSupportedCharacterSet(string characterSet)
|
||||
{
|
||||
return Encoding.GetEncodings()
|
||||
.Where(e => String.Equals(e.Name, characterSet, StringComparison.InvariantCultureIgnoreCase))
|
||||
.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content encoding type from the encoding character
|
||||
/// </summary>
|
||||
/// <param name="contentEncodingCharacter">Content contentEncodingCharacter character</param>
|
||||
/// <returns>ContentEncoding type</returns>
|
||||
private static ContentEncoding GetContentEncodingType(string contentEncodingCharacter)
|
||||
{
|
||||
switch (contentEncodingCharacter)
|
||||
{
|
||||
case "Q":
|
||||
case "q":
|
||||
return ContentEncoding.QEncoding;
|
||||
case "B":
|
||||
case "b":
|
||||
return ContentEncoding.Base64;
|
||||
default:
|
||||
return ContentEncoding.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content decoder delegate for the given content encoding type
|
||||
/// </summary>
|
||||
/// <param name="contentEncoding">Content encoding type</param>
|
||||
/// <returns>Decoding delegate</returns>
|
||||
private static Func<string, Encoding, string> GetContentDecoder(ContentEncoding contentEncoding)
|
||||
{
|
||||
switch (contentEncoding)
|
||||
{
|
||||
case ContentEncoding.Base64:
|
||||
return DecodeBase64;
|
||||
case ContentEncoding.QEncoding:
|
||||
return DecodeQEncoding;
|
||||
default:
|
||||
// Will never get here, but return a "null" delegate anyway
|
||||
return (s, e) => String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content encoder delegate for the given content encoding type
|
||||
/// </summary>
|
||||
/// <param name="contentEncoding">Content encoding type</param>
|
||||
/// <returns>Encoding delegate</returns>
|
||||
private static Func<string, Encoding, string> GetContentEncoder(ContentEncoding contentEncoding)
|
||||
{
|
||||
switch (contentEncoding)
|
||||
{
|
||||
case ContentEncoding.Base64:
|
||||
return EncodeBase64;
|
||||
case ContentEncoding.QEncoding:
|
||||
return EncodeQEncoding;
|
||||
default:
|
||||
// Will never get here, but return a "null" delegate anyway
|
||||
return (s, e) => String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a base64 encoded string
|
||||
/// </summary>
|
||||
/// <param name="encodedText">Encoded text</param>
|
||||
/// <param name="textEncoder">Encoding instance for the code page required</param>
|
||||
/// <returns>Decoded string</returns>
|
||||
private static string DecodeBase64(string encodedText, Encoding textEncoder)
|
||||
{
|
||||
var encodedBytes = Convert.FromBase64String(encodedText);
|
||||
|
||||
return textEncoder.GetString(encodedBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes a base64 encoded string
|
||||
/// </summary>
|
||||
/// <param name="plainText">Plain text</param>
|
||||
/// <param name="textEncoder">Encoding instance for the code page required</param>
|
||||
/// <returns>Encoded string</returns>
|
||||
private static string EncodeBase64(string plainText, Encoding textEncoder)
|
||||
{
|
||||
var plainTextBytes = textEncoder.GetBytes(plainText);
|
||||
|
||||
return Convert.ToBase64String(plainTextBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a "Q encoded" string
|
||||
/// </summary>
|
||||
/// <param name="encodedText">Encoded text</param>
|
||||
/// <param name="textEncoder">Encoding instance for the code page required</param>
|
||||
/// <returns>Decoded string</returns>
|
||||
private static string DecodeQEncoding(string encodedText, Encoding textEncoder)
|
||||
{
|
||||
var decodedText = QEncodingSpaceRegEx.Replace(encodedText, " ");
|
||||
|
||||
decodedText = QEncodingHexCodeRegEx.Replace(
|
||||
decodedText,
|
||||
m =>
|
||||
{
|
||||
var hexString = m.Groups["hexcode"].Value;
|
||||
|
||||
int characterValue;
|
||||
if (!int.TryParse(hexString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out characterValue))
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
return textEncoder.GetString(new[] { (byte)characterValue });
|
||||
});
|
||||
|
||||
return decodedText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes a "Q encoded" string
|
||||
/// </summary>
|
||||
/// <param name="plainText">Plain text</param>
|
||||
/// <param name="textEncoder">Encoding instance for the code page required</param>
|
||||
/// <returns>Encoded string</returns>
|
||||
private static string EncodeQEncoding(string plainText, Encoding textEncoder)
|
||||
{
|
||||
if (textEncoder.GetByteCount(plainText) != plainText.Length)
|
||||
{
|
||||
throw new ArgumentException("Q encoding only supports single byte encodings", "textEncoder");
|
||||
}
|
||||
|
||||
var specialBytes = textEncoder.GetBytes(SpecialCharacters);
|
||||
|
||||
var sb = new StringBuilder(plainText.Length);
|
||||
|
||||
var plainBytes = textEncoder.GetBytes(plainText);
|
||||
|
||||
// Replace "high" values
|
||||
for (int i = 0; i < plainBytes.Length; i++)
|
||||
{
|
||||
if (plainBytes[i] <= 127 && !specialBytes.Contains(plainBytes[i]))
|
||||
{
|
||||
sb.Append(Convert.ToChar(plainBytes[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append("=");
|
||||
sb.Append(Convert.ToString(plainBytes[i], 16).ToUpper());
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString().Replace(" ", "_");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the full encoded string representation
|
||||
/// </summary>
|
||||
/// <param name="characterSet">Characterset to use</param>
|
||||
/// <param name="contentEncoding">Content encoding to use</param>
|
||||
/// <param name="encodedContent">Content, encoded to the above parameters</param>
|
||||
/// <returns>Valid RFC2047 string</returns>
|
||||
private static string BuildEncodedString(string characterSet, ContentEncoding contentEncoding, string encodedContent)
|
||||
{
|
||||
var encodingCharacter = String.Empty;
|
||||
|
||||
switch (contentEncoding)
|
||||
{
|
||||
case ContentEncoding.Base64:
|
||||
encodingCharacter = "B";
|
||||
break;
|
||||
case ContentEncoding.QEncoding:
|
||||
encodingCharacter = "Q";
|
||||
break;
|
||||
}
|
||||
|
||||
var wrapperLength = string.Format(EncodedStringFormat, characterSet, encodingCharacter, String.Empty).Length;
|
||||
var chunkLength = MaxLineLength - wrapperLength;
|
||||
|
||||
if (encodedContent.Length <= chunkLength)
|
||||
{
|
||||
return string.Format(EncodedStringFormat, characterSet, encodingCharacter, encodedContent);
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var chunk in SplitStringByLength(encodedContent, chunkLength))
|
||||
{
|
||||
sb.AppendFormat(EncodedStringFormat, characterSet, encodingCharacter, chunk);
|
||||
sb.Append("\r\n ");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a string into chunks
|
||||
/// </summary>
|
||||
/// <param name="inputString">Input string</param>
|
||||
/// <param name="chunkSize">Size of each chunk</param>
|
||||
/// <returns>String collection of chunked strings</returns>
|
||||
public static IEnumerable<string> SplitStringByLength(this string inputString, int chunkSize)
|
||||
{
|
||||
for (int index = 0; index < inputString.Length; index += chunkSize)
|
||||
{
|
||||
yield return inputString.Substring(index, Math.Min(chunkSize, inputString.Length - index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
public class HcsActionLogger : IHcsLogger
|
||||
{
|
||||
private Action<string> logger;
|
||||
|
||||
public HcsActionLogger(Action<string> logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
logger(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,96 +0,0 @@
|
||||
using GostCryptography.Base;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
public static class HcsCertificateHelper
|
||||
{
|
||||
public static bool IsGostPrivateKey(this X509Certificate2 certificate)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (certificate.HasPrivateKey)
|
||||
{
|
||||
var cspInfo = certificate.GetPrivateKeyInfo();
|
||||
if (cspInfo.ProviderType == (int)ProviderType.CryptoPro ||
|
||||
cspInfo.ProviderType == (int)ProviderType.VipNet ||
|
||||
cspInfo.ProviderType == (int)ProviderType.CryptoPro_2012_512 ||
|
||||
cspInfo.ProviderType == (int)ProviderType.CryptoPro_2012_1024)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static GostXades.CryptoProviderTypeEnum GetProviderType(this X509Certificate2 certificate)
|
||||
{
|
||||
return (GostXades.CryptoProviderTypeEnum)GetProviderInfo(certificate).Item1;
|
||||
}
|
||||
|
||||
public static Tuple<int, string> GetProviderInfo(this X509Certificate2 certificate)
|
||||
{
|
||||
if (certificate.HasPrivateKey)
|
||||
{
|
||||
var cspInfo = certificate.GetPrivateKeyInfo();
|
||||
return new Tuple<int, string>(cspInfo.ProviderType, cspInfo.ProviderName);
|
||||
}
|
||||
else
|
||||
throw new Exception("Certificate has no private key");
|
||||
}
|
||||
|
||||
public static X509Certificate2 FindCertificate(Func<X509Certificate2, bool> predicate)
|
||||
{
|
||||
if (predicate == null) throw new ArgumentException("Null subject predicate");
|
||||
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
|
||||
|
||||
try
|
||||
{
|
||||
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
|
||||
|
||||
var collection = store.Certificates
|
||||
.OfType<X509Certificate2>()
|
||||
.Where(x => x.HasPrivateKey && x.IsGostPrivateKey());
|
||||
|
||||
var now = DateTime.Now;
|
||||
return collection.First(
|
||||
x => now >= x.NotBefore && now <= x.NotAfter && predicate(x));
|
||||
}
|
||||
finally
|
||||
{
|
||||
store.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static X509Certificate2 ShowCertificateUI()
|
||||
{
|
||||
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
|
||||
try
|
||||
{
|
||||
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
|
||||
|
||||
var collection = store.Certificates
|
||||
.OfType<X509Certificate2>()
|
||||
.Where(x => x.HasPrivateKey && x.IsGostPrivateKey());
|
||||
|
||||
string prompt = "Выберите сертификат";
|
||||
var cert = X509Certificate2UI.SelectFromCollection(
|
||||
new X509Certificate2Collection(
|
||||
collection.ToArray()), prompt, "", X509SelectionFlag.SingleSelection)[0];
|
||||
return cert;
|
||||
}
|
||||
finally
|
||||
{
|
||||
store.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,74 +0,0 @@
|
||||
using GostCryptography.Gost_R3411;
|
||||
using Hcs.ClientApi.DebtRequestsApi;
|
||||
using Hcs.ClientApi.DeviceMeteringApi;
|
||||
using Hcs.ClientApi.FileStoreServiceApi;
|
||||
using Hcs.ClientApi.HouseManagementApi;
|
||||
using Hcs.ClientApi.NsiApi;
|
||||
using Hcs.ClientApi.NsiCommonApi;
|
||||
using Hcs.ClientApi.OrgRegistryCommonApi;
|
||||
using Hcs.ClientApi.RemoteCaller;
|
||||
using System;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Единый клиент для вызова всех реализованных функций интеграции с ГИС ЖКХ
|
||||
/// </summary>
|
||||
public class HcsClient : HcsClientConfig
|
||||
{
|
||||
public HcsClient()
|
||||
{
|
||||
HcsServicePointConfig.InitConfig();
|
||||
|
||||
// TODO: Вынести в конфиг
|
||||
// Роль поставщика информации по умолчанию
|
||||
Role = HcsOrganizationRoles.RSO;
|
||||
}
|
||||
|
||||
public void SetSigningCertificate(X509Certificate2 cert, string pin = null)
|
||||
{
|
||||
if (cert == null) throw new ArgumentNullException("Не указан сертификат для подписания данных");
|
||||
if (pin == null) pin = HcsConstants.DefaultCertificatePin;
|
||||
|
||||
Certificate = cert;
|
||||
CertificateThumbprint = cert.Thumbprint;
|
||||
CertificatePassword = pin;
|
||||
CryptoProviderType = cert.GetProviderType();
|
||||
}
|
||||
|
||||
public HcsDebtRequestsApi DebtRequests => new HcsDebtRequestsApi(this);
|
||||
public HcsHouseManagementApi HouseManagement => new HcsHouseManagementApi(this);
|
||||
public HcsOrgRegistryCommonApi OrgRegistryCommon => new HcsOrgRegistryCommonApi(this);
|
||||
public HcsFileStoreServiceApi FileStoreService => new HcsFileStoreServiceApi(this);
|
||||
public HcsDeviceMeteringApi DeviceMeteringService => new HcsDeviceMeteringApi(this);
|
||||
public HcsNsiApi Nsi => new HcsNsiApi(this);
|
||||
public HcsNsiCommonApi NsiCommon => new HcsNsiCommonApi(this);
|
||||
|
||||
public X509Certificate2 FindCertificate(Func<X509Certificate2, bool> predicate)
|
||||
{
|
||||
return HcsCertificateHelper.FindCertificate(predicate);
|
||||
}
|
||||
|
||||
public X509Certificate2 ShowCertificateUI()
|
||||
{
|
||||
return HcsCertificateHelper.ShowCertificateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Производит для потока хэш по алгоритму "ГОСТ Р 34.11-94" в строке binhex
|
||||
/// </summary>
|
||||
public string ComputeGost94Hash(System.IO.Stream stream)
|
||||
{
|
||||
// API HouseManagement указывает, что файлы приложенные к договору должны размещаться
|
||||
// с AttachmentHASH по стандарту ГОСТ. Оказывается, ГИСЖКХ требует применения устаревшего
|
||||
// алгоритма ГОСТ Р 34.11-94 (соответствует `rhash --gost94-cryptopro file` в linux).
|
||||
using var algorithm = new Gost_R3411_94_HashAlgorithm(GostCryptoProviderType);
|
||||
var savedPosition = stream.Position;
|
||||
stream.Position = 0;
|
||||
var hashValue = HcsUtil.ConvertToHexString(algorithm.ComputeHash(stream));
|
||||
stream.Position = savedPosition;
|
||||
return hashValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,95 +0,0 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Конфигурация клиента
|
||||
/// </summary>
|
||||
public class HcsClientConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Идентификатор поставщика данных ГИС
|
||||
/// </summary>
|
||||
public string OrgPPAGUID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Идентификатор организации в ГИС
|
||||
/// </summary>
|
||||
public string OrgEntityGUID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Тип криптопровайдера полученный из сертификата
|
||||
/// </summary>
|
||||
public GostXades.CryptoProviderTypeEnum CryptoProviderType { get; internal set; }
|
||||
|
||||
public GostCryptography.Base.ProviderType GostCryptoProviderType =>
|
||||
(GostCryptography.Base.ProviderType)CryptoProviderType;
|
||||
|
||||
/// <summary>
|
||||
/// Сертификат клиента для применения при формировании запросов
|
||||
/// </summary>
|
||||
public X509Certificate2 Certificate { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Отпечаток сертификата
|
||||
/// </summary>
|
||||
public string CertificateThumbprint { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Пароль доступа к сертификату
|
||||
/// </summary>
|
||||
public string CertificatePassword { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Исполнитель/сотрудник ГИСЖКХ от которого будут регистрироваться ответы
|
||||
/// </summary>
|
||||
public string ExecutorGUID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Признак - указывает на то, что используется внешний туннель (stunnel)
|
||||
/// </summary>
|
||||
public bool UseTunnel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// true - использовать адреса ППАК стенда иначе СИТ
|
||||
/// </summary>
|
||||
public bool IsPPAK { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Роль
|
||||
/// </summary>
|
||||
public HcsOrganizationRoles Role { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Устанавливаемый пользователем приемник отладочных сообщений
|
||||
/// </summary>
|
||||
public IHcsLogger Logger { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Выводит сообщение в установленный приемник отладочных сообщений
|
||||
/// </summary>
|
||||
public void Log(string message) => Logger?.WriteLine(message);
|
||||
|
||||
/// <summary>
|
||||
/// Устанавливаемый пользователем механизм перехвата содержимого отправляемых
|
||||
/// и принимаемых пакетов
|
||||
/// </summary>
|
||||
public IHcsMessageCapture MessageCapture;
|
||||
|
||||
/// <summary>
|
||||
/// Отправляет тело сообщения в установленный перехватчик
|
||||
/// </summary>
|
||||
public void MaybeCaptureMessage(bool sent, string messageBody)
|
||||
=> MessageCapture?.CaptureMessage(sent, messageBody);
|
||||
|
||||
public string ComposeEndpointUri(string endpointName)
|
||||
{
|
||||
if (UseTunnel)
|
||||
return $"http://{HcsConstants.Address.UriTunnel}/{endpointName}";
|
||||
|
||||
return IsPPAK ?
|
||||
$"https://{HcsConstants.Address.UriPPAK}/{endpointName}"
|
||||
: $"https://{HcsConstants.Address.UriSIT02}/{endpointName}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
public class HcsConsoleLogger : IHcsLogger
|
||||
{
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,119 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
public static class HcsConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// Имя XML-элемента в сообщении, которое будет подписываться в фильтре
|
||||
/// отправки подписывающем XML
|
||||
/// </summary>
|
||||
public const string SignedXmlElementId = "signed-data-container";
|
||||
|
||||
/// <summary>
|
||||
/// Если PIN сертификата не указан пользователем, применяется это значение
|
||||
/// по умолчанию для сертификатов RuToken
|
||||
/// </summary>
|
||||
public const string DefaultCertificatePin = "12345678";
|
||||
|
||||
public static class Address
|
||||
{
|
||||
public const string UriPPAK = "api.dom.gosuslugi.ru";
|
||||
public const string UriSIT01 = "sit01.dom.test.gosuslugi.ru:10081";
|
||||
public const string UriSIT02 = "sit02.dom.test.gosuslugi.ru:10081";
|
||||
public const string UriTunnel = "127.0.0.1:8080";
|
||||
}
|
||||
|
||||
public static class EndPointLocator
|
||||
{
|
||||
static Dictionary<HcsEndPoints, string> _endPoints;
|
||||
static EndPointLocator()
|
||||
{
|
||||
if (_endPoints == null)
|
||||
_endPoints = new Dictionary<HcsEndPoints, string>();
|
||||
|
||||
_endPoints.Add(HcsEndPoints.BillsAsync, "ext-bus-bills-service/services/BillsAsync");
|
||||
_endPoints.Add(HcsEndPoints.DeviceMetering, "ext-bus-device-metering-service/services/DeviceMetering");
|
||||
_endPoints.Add(HcsEndPoints.DeviceMeteringAsync, "ext-bus-device-metering-service/services/DeviceMeteringAsync");
|
||||
_endPoints.Add(HcsEndPoints.HomeManagement, "ext-bus-home-management-service/services/HomeManagement");
|
||||
_endPoints.Add(HcsEndPoints.HomeManagementAsync, "ext-bus-home-management-service/services/HomeManagementAsync");
|
||||
_endPoints.Add(HcsEndPoints.DebtRequestsAsync, "ext-bus-debtreq-service/services/DebtRequestsAsync");
|
||||
_endPoints.Add(HcsEndPoints.Licenses, "ext-bus-licenses-service/services/Licenses");
|
||||
_endPoints.Add(HcsEndPoints.LicensesAsync, "ext-bus-licenses-service/services/LicensesAsync");
|
||||
_endPoints.Add(HcsEndPoints.Nsi, "ext-bus-nsi-service/services/Nsi");
|
||||
_endPoints.Add(HcsEndPoints.NsiAsync, "ext-bus-nsi-service/services/NsiAsync");
|
||||
_endPoints.Add(HcsEndPoints.NsiCommon, "ext-bus-nsi-common-service/services/NsiCommon");
|
||||
_endPoints.Add(HcsEndPoints.NsiCommonAsync, "ext-bus-nsi-common-service/services/NsiCommonAsync");
|
||||
_endPoints.Add(HcsEndPoints.OrgRegistryCommon, "ext-bus-org-registry-common-service/services/OrgRegistryCommon");
|
||||
_endPoints.Add(HcsEndPoints.OrgRegistryCommonAsync, "ext-bus-org-registry-common-service/services/OrgRegistryCommonAsync");
|
||||
_endPoints.Add(HcsEndPoints.OrgRegistry, "ext-bus-org-registry-service/services/OrgRegistry");
|
||||
_endPoints.Add(HcsEndPoints.OrgRegistryAsync, "ext-bus-org-registry-service/services/OrgRegistryAsync");
|
||||
_endPoints.Add(HcsEndPoints.PaymentsAsync, "ext-bus-payment-service/services/PaymentAsync");
|
||||
}
|
||||
|
||||
public static string GetPath(HcsEndPoints endPoint)
|
||||
{
|
||||
return _endPoints[endPoint];
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserAuth
|
||||
{
|
||||
public const string Name = "sit";
|
||||
public const string Passwd = "xw{p&&Ee3b9r8?amJv*]";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Имена конечных точек
|
||||
/// </summary>
|
||||
public enum HcsEndPoints
|
||||
{
|
||||
OrgRegistry,
|
||||
OrgRegistryAsync,
|
||||
OrgRegistryCommon,
|
||||
OrgRegistryCommonAsync,
|
||||
NsiCommon,
|
||||
NsiCommonAsync,
|
||||
Nsi,
|
||||
NsiAsync,
|
||||
HomeManagement,
|
||||
HomeManagementAsync,
|
||||
DebtRequestsAsync,
|
||||
Bills,
|
||||
BillsAsync,
|
||||
Licenses,
|
||||
LicensesAsync,
|
||||
DeviceMetering,
|
||||
DeviceMeteringAsync,
|
||||
PaymentsAsync
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Роли организаций в ГИС
|
||||
/// </summary>
|
||||
public enum HcsOrganizationRoles
|
||||
{
|
||||
/// <summary>
|
||||
/// УК/ТСЖ/ЖСК
|
||||
/// </summary>
|
||||
UK,
|
||||
|
||||
/// <summary>
|
||||
/// Ресурсоснабжающая организация
|
||||
/// </summary>
|
||||
RSO,
|
||||
|
||||
/// <summary>
|
||||
/// Расчетный центр
|
||||
/// </summary>
|
||||
RC,
|
||||
}
|
||||
|
||||
public class HcsAsyncRequestStateTypes
|
||||
{
|
||||
public const int Received = 1;
|
||||
public const int InProgress = 2;
|
||||
public const int Ready = 3;
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
public class HcsException : Exception
|
||||
{
|
||||
public HcsMemoryMessageCapture MessageCapture { get; private set; }
|
||||
|
||||
public HcsException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public HcsException(string message, Exception nestedException) : base(message, nestedException)
|
||||
{
|
||||
}
|
||||
|
||||
public HcsException(string message, HcsMemoryMessageCapture capture, Exception nestedException)
|
||||
: base(message, nestedException)
|
||||
{
|
||||
MessageCapture = capture;
|
||||
}
|
||||
|
||||
public static HcsException FindHcsException(Exception e)
|
||||
{
|
||||
return HcsUtil.EnumerateInnerExceptions(e).OfType<HcsException>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
public class HcsFile
|
||||
{
|
||||
public string FileName { get; private set; }
|
||||
public string ContentType { get; private set; }
|
||||
public Stream Stream { get; private set; }
|
||||
|
||||
public long Length => Stream.Length;
|
||||
|
||||
public HcsFile(string fileName, string contentType, Stream stream)
|
||||
{
|
||||
FileName = fileName;
|
||||
ContentType = contentType ?? throw new ArgumentNullException(nameof(ContentType));
|
||||
Stream = stream ?? throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// По имени файла возвращает строку MIME Content-Type или null если тип MIME не найден
|
||||
/// </summary>
|
||||
public static string GetMimeContentTypeForFileName(string fileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName)) return null;
|
||||
string extension = Path.GetExtension(fileName).ToLower();
|
||||
var mimeType = AllowedMimeTypes.FirstOrDefault(x => x.Extension == extension);
|
||||
if (mimeType == null) return null;
|
||||
return mimeType.ContentType;
|
||||
}
|
||||
|
||||
public record struct MimeType(string Extension, string ContentType);
|
||||
|
||||
/// <summary>
|
||||
/// Типы MIME допустимые для загрузки в ГИС ЖКХ
|
||||
/// </summary>
|
||||
public static MimeType[] AllowedMimeTypes =
|
||||
{
|
||||
new MimeType(".pdf", "application/pdf"),
|
||||
new MimeType(".xls", "application/excel"),
|
||||
new MimeType(".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
|
||||
new MimeType(".doc", "application/msword"),
|
||||
new MimeType(".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
|
||||
new MimeType(".rtf", "application/rtf"),
|
||||
new MimeType(".jpg", "image/jpeg"),
|
||||
new MimeType(".jpeg", "image/jpeg"),
|
||||
new MimeType(".tif", "image/tiff"),
|
||||
new MimeType(".tiff", "image/tiff")
|
||||
// TODO: Проверить комментарий
|
||||
// В спецификации есть другие типы файлов .zip, .sgn и т.д.
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Раздел хранилища файлов (Attachment) из документации: "ГИС ЖКХ. Альбом ТФФ 14.5.0.1.docx"
|
||||
/// 2.6 Перечень контекстов хранилищ функциональных подсистем
|
||||
/// </summary>
|
||||
public enum HcsFileStoreContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Управление домами. Лицевые счета.
|
||||
/// </summary>
|
||||
homemanagement,
|
||||
|
||||
/// <summary>
|
||||
/// Управление контентом
|
||||
/// </summary>
|
||||
contentmanagement,
|
||||
|
||||
/// <summary>
|
||||
/// Электронные счета
|
||||
/// </summary>
|
||||
bills,
|
||||
|
||||
/// <summary>
|
||||
/// Запросов о наличии задолженности по оплате ЖКУ
|
||||
/// </summary>
|
||||
debtreq
|
||||
}
|
||||
|
||||
public static class HcsFileStoreContextExtensions
|
||||
{
|
||||
public static string GetName(this HcsFileStoreContext context)
|
||||
{
|
||||
return context.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Реализация механизма захвата содержимого сообщений SOAP записывающая
|
||||
/// каждое сообщение в отдельный файл на диске
|
||||
/// </summary>
|
||||
public class HcsFileWriterMessageCapture : IHcsMessageCapture
|
||||
{
|
||||
private string directory;
|
||||
private IHcsLogger logger;
|
||||
|
||||
public HcsFileWriterMessageCapture()
|
||||
{
|
||||
}
|
||||
|
||||
public HcsFileWriterMessageCapture(string directory, IHcsLogger logger)
|
||||
{
|
||||
this.directory = directory;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void CaptureMessage(bool sent, string body)
|
||||
{
|
||||
int index = 0;
|
||||
int maxIndex = 1000000;
|
||||
string fileName;
|
||||
|
||||
do
|
||||
{
|
||||
index += 1;
|
||||
if (index > maxIndex) throw new HcsException("Превышен максимум индекса файлов захвата сообщений");
|
||||
fileName = index.ToString("D3") + "_" + (sent ? "message" : "response") + ".xml";
|
||||
if (!string.IsNullOrEmpty(directory))
|
||||
{
|
||||
fileName = System.IO.Path.Combine(directory, fileName);
|
||||
}
|
||||
} while (System.IO.File.Exists(fileName));
|
||||
|
||||
if (logger != null) logger.WriteLine($"Writing message file: {fileName}...");
|
||||
System.IO.File.WriteAllText(fileName, body, Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Реализация захвата содержимого отправляемых и принимаемых SOAP сообщений,
|
||||
/// которая хранит данные в памяти
|
||||
/// </summary>
|
||||
public class HcsMemoryMessageCapture : IHcsMessageCapture
|
||||
{
|
||||
private MemoryStream messageCaptureStream;
|
||||
private StreamWriter messageCaptureWriter;
|
||||
|
||||
private Encoding encoding => Encoding.UTF8;
|
||||
|
||||
public HcsMemoryMessageCapture()
|
||||
{
|
||||
messageCaptureStream = new MemoryStream();
|
||||
messageCaptureWriter = new StreamWriter(messageCaptureStream, encoding);
|
||||
}
|
||||
|
||||
void IHcsMessageCapture.CaptureMessage(bool sentOrReceived, string messageBody)
|
||||
{
|
||||
if (messageCaptureStream.Position > 0) messageCaptureWriter.WriteLine("");
|
||||
messageCaptureWriter.Write("<!--");
|
||||
messageCaptureWriter.Write(sentOrReceived ? "SENT " : "RECV ");
|
||||
messageCaptureWriter.Write(DateTime.Now.ToString());
|
||||
messageCaptureWriter.WriteLine("-->");
|
||||
messageCaptureWriter.Write(messageBody);
|
||||
messageCaptureWriter.Flush();
|
||||
}
|
||||
|
||||
public byte[] GetData()
|
||||
{
|
||||
var buf = messageCaptureStream.GetBuffer();
|
||||
int size = (int)messageCaptureStream.Length;
|
||||
var data = new byte[size];
|
||||
Buffer.BlockCopy(buf, 0, data, 0, size);
|
||||
return data;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return encoding.GetString(GetData());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Исключение указывает на то что сервер обнаружил что у
|
||||
/// него нет объектов для выдачи по условию
|
||||
/// </summary>
|
||||
public class HcsNoResultsRemoteException : HcsRemoteException
|
||||
{
|
||||
public HcsNoResultsRemoteException(string description) :
|
||||
base(HcsRemoteException.KnownCodes.НетОбъектовДляЭкспорта, description)
|
||||
{
|
||||
}
|
||||
|
||||
public HcsNoResultsRemoteException(string errorCode, string description) :
|
||||
base(errorCode, description)
|
||||
{
|
||||
}
|
||||
|
||||
public HcsNoResultsRemoteException(string errorCode, string description, Exception nested) :
|
||||
base(errorCode, description, nested)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
public class HcsParallel
|
||||
{
|
||||
/// <summary>
|
||||
/// Асинхронно обрабатывает все элементы @values типа @T методом @processor в параллельном режиме,
|
||||
/// используя максимум @maxThreads потоков
|
||||
/// </summary>
|
||||
public static async Task ForEachAsync<T>(IEnumerable<T> values, Func<T, Task> processor, int maxThreads)
|
||||
{
|
||||
await Task.Run(() => ForEach(values, processor, maxThreads));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обрабатывает все элементы @values типа @T методом @processor в параллельном режиме,
|
||||
/// используя максимум @maxThreads потоков
|
||||
/// </summary>
|
||||
public static void ForEach<T>(IEnumerable<T> values, Func<T, Task> processor, int maxThreads)
|
||||
{
|
||||
var taskList = new List<Task>();
|
||||
var enumerator = values.GetEnumerator();
|
||||
|
||||
int numTasksFinished = 0;
|
||||
while (true)
|
||||
{
|
||||
// Наполняем массив ожидания следующими задачами
|
||||
while (taskList.Count < maxThreads)
|
||||
{
|
||||
if (!enumerator.MoveNext()) break;
|
||||
|
||||
// Запускаем новую задачу в отсоединенном потоке
|
||||
Task newTask = Task.Run(() => processor(enumerator.Current));
|
||||
taskList.Add(newTask);
|
||||
}
|
||||
|
||||
// Если массив ожидания пуст, работа окончена
|
||||
if (taskList.Count == 0) return;
|
||||
|
||||
// Ждем завершение любой задачи из массива ожидания
|
||||
int finishedIndex = Task.WaitAny(taskList.ToArray());
|
||||
var finishedTask = taskList[finishedIndex];
|
||||
numTasksFinished += 1;
|
||||
|
||||
// Удаляем задачу из массива ожидания чтобы более ее не ждать
|
||||
taskList.Remove(finishedTask);
|
||||
|
||||
// Если задача завершилась успешно уходим на добавление новой задачи
|
||||
if (!finishedTask.IsFaulted &&
|
||||
!finishedTask.IsCanceled) continue;
|
||||
|
||||
// Задача завершилась аномально, ждем завершения других запущенных задач
|
||||
if (taskList.Count > 0) Task.WaitAll(taskList.ToArray());
|
||||
|
||||
// Составляем список всех возникших ошибок включая первую
|
||||
taskList.Insert(0, finishedTask);
|
||||
var errors = new List<Exception>();
|
||||
foreach (var task in taskList)
|
||||
{
|
||||
if (task.IsFaulted) errors.Add(task.Exception);
|
||||
if (task.IsCanceled) errors.Add(new Exception("Task was cancelled"));
|
||||
}
|
||||
|
||||
// Аномально завершаем обработку
|
||||
string message =
|
||||
$"Ошибка параллельной обработки №{numTasksFinished} из {values.Count()}" +
|
||||
$" объектов типа {typeof(T).FullName}";
|
||||
throw new AggregateException(message, errors.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Поток байтов который является частью другого потока байтов
|
||||
/// https://stackoverflow.com/questions/60592147/partial-stream-of-filestream
|
||||
/// </summary>
|
||||
public class HcsPartialStream : Stream
|
||||
{
|
||||
public Stream Stream { get; private set; }
|
||||
public long StreamStart { get; private set; }
|
||||
public long StreamLength { get; private set; }
|
||||
public long StreamEnd { get; private set; }
|
||||
|
||||
public HcsPartialStream(Stream stream, long offset, long size)
|
||||
{
|
||||
Stream = stream;
|
||||
StreamStart = offset;
|
||||
StreamLength = size;
|
||||
StreamEnd = offset + size;
|
||||
stream.Seek(offset, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override long Length => Math.Min((Stream.Length - StreamStart), StreamLength);
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => Stream.Position - StreamStart;
|
||||
set => Stream.Position = StreamStart + value;
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
var p = Stream.Position;
|
||||
if (p < StreamStart)
|
||||
{
|
||||
Stream.Position = StreamStart;
|
||||
}
|
||||
if (p > StreamEnd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (p + count > StreamEnd)
|
||||
{
|
||||
count = (int)(StreamEnd - p);
|
||||
}
|
||||
return Stream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
// Seek will be complicated as there are three origin types.
|
||||
// You can do it yourself.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Сообщение об ошибке возникшей на удаленном сервере ГИС ЖКХ
|
||||
/// </summary>
|
||||
public class HcsRemoteException : HcsException
|
||||
{
|
||||
public string ErrorCode { get; private set; }
|
||||
public string Description { get; private set; }
|
||||
|
||||
public class KnownCodes
|
||||
{
|
||||
public const string НетОбъектовДляЭкспорта = "INT002012";
|
||||
public const string ОтсутствуетВРеестре = "INT002000";
|
||||
public const string ДоступЗапрещен = "AUT011003";
|
||||
}
|
||||
|
||||
public HcsRemoteException(string errorCode, string description)
|
||||
: base(MakeMessage(errorCode, description))
|
||||
{
|
||||
this.ErrorCode = errorCode;
|
||||
this.Description = description;
|
||||
}
|
||||
|
||||
public HcsRemoteException(string errorCode, string description, Exception nestedException)
|
||||
: base(MakeMessage(errorCode, description), nestedException)
|
||||
{
|
||||
this.ErrorCode = errorCode;
|
||||
this.Description = description;
|
||||
}
|
||||
|
||||
private static string MakeMessage(string errorCode, string description)
|
||||
=> $"Удаленная система вернула ошибку: [{errorCode}] {description}";
|
||||
|
||||
public static HcsRemoteException CreateNew(string errorCode, string description, Exception nested = null)
|
||||
{
|
||||
if (string.Compare(errorCode, KnownCodes.НетОбъектовДляЭкспорта) == 0)
|
||||
return new HcsNoResultsRemoteException(errorCode, description, nested);
|
||||
return new HcsRemoteException(errorCode, description);
|
||||
}
|
||||
|
||||
public static HcsRemoteException CreateNew(HcsRemoteException nested)
|
||||
{
|
||||
if (nested == null) throw new ArgumentNullException("nested exception");
|
||||
return CreateNew(nested.ErrorCode, nested.Description, nested);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает true если ошибка @e или ее вложенные ошибки модержат @errorCode
|
||||
/// </summary>
|
||||
public static bool ContainsErrorCode(Exception e, string errorCode)
|
||||
{
|
||||
if (e == null) return false;
|
||||
return HcsUtil.EnumerateInnerExceptions(e).OfType<HcsRemoteException>().Where(x => x.ErrorCode == errorCode).Any();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
public class HcsRestartTimeoutException : HcsException
|
||||
{
|
||||
public HcsRestartTimeoutException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public HcsRestartTimeoutException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,91 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
public class HcsUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Возвращает описание исключения одной строкой
|
||||
/// </summary>
|
||||
public static string DescribeException(Exception e)
|
||||
{
|
||||
string separator = "";
|
||||
var buf = new StringBuilder();
|
||||
buf.Append("[");
|
||||
foreach (var inner in EnumerateInnerExceptions(e))
|
||||
{
|
||||
buf.Append(separator);
|
||||
buf.Append(inner.GetType().Name);
|
||||
buf.Append(":");
|
||||
buf.Append(inner.Message);
|
||||
separator = "-->";
|
||||
}
|
||||
|
||||
buf.Append("]");
|
||||
return buf.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает список все вложенных исключений для данного исключения
|
||||
/// </summary>
|
||||
public static List<Exception> EnumerateInnerExceptions(Exception e)
|
||||
{
|
||||
var list = new List<Exception>();
|
||||
WalkInnerExceptionsRecurse(e, list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private static void WalkInnerExceptionsRecurse(Exception e, List<Exception> list)
|
||||
{
|
||||
if (e == null || list.Contains(e)) return;
|
||||
list.Add(e);
|
||||
|
||||
WalkInnerExceptionsRecurse(e.InnerException, list);
|
||||
|
||||
if (e is AggregateException)
|
||||
{
|
||||
var aggregate = e as AggregateException;
|
||||
foreach (var inner in aggregate.InnerExceptions)
|
||||
{
|
||||
WalkInnerExceptionsRecurse(inner, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FormatGuid(Guid guid) => guid.ToString();
|
||||
|
||||
public static Guid ParseGuid(string guid)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Guid.Parse(guid);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new HcsException($"Невозможно прочитать GUID из строки [{guid}]", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static string FormatDate(DateTime date)
|
||||
{
|
||||
return date.ToString("yyyyMMdd");
|
||||
}
|
||||
|
||||
public static string FormatDate(DateTime? date)
|
||||
{
|
||||
return (date == null) ? string.Empty : FormatDate((DateTime)date);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Преобразует массиб байтов в строку в формате binhex
|
||||
/// </summary>
|
||||
public static string ConvertToHexString(byte[] ba)
|
||||
{
|
||||
var buf = new StringBuilder(ba.Length * 2);
|
||||
foreach (byte b in ba) buf.AppendFormat("{0:x2}", b);
|
||||
return buf.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,229 +0,0 @@
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Методы работы с сертификатами X509, которых нет в системе
|
||||
/// </summary>
|
||||
public class HcsX509Tools
|
||||
{
|
||||
public static bool IsValidCertificate(X509Certificate2 cert)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
return (now >= cert.NotBefore && now <= GetNotAfterDate(cert));
|
||||
}
|
||||
|
||||
public static IEnumerable<X509Certificate2> EnumerateCertificates(bool includeInvalid = false)
|
||||
{
|
||||
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
|
||||
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
|
||||
try
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
foreach (var x in store.Certificates)
|
||||
{
|
||||
if (includeInvalid) yield return x;
|
||||
else if (IsValidCertificate(x)) yield return x;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
store.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static X509Certificate2 FindCertificate(Func<X509Certificate2, bool> predicate)
|
||||
{
|
||||
if (predicate == null) throw new ArgumentException("Null subject predicate");
|
||||
return EnumerateCertificates(true).FirstOrDefault(x => predicate(x));
|
||||
}
|
||||
|
||||
public static X509Certificate2 FindValidCertificate(Func<X509Certificate2, bool> predicate)
|
||||
{
|
||||
if (predicate == null) throw new ArgumentException("Null subject predicate");
|
||||
return EnumerateCertificates(false).FirstOrDefault(x => predicate(x));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает Common Name сертификата
|
||||
/// </summary>
|
||||
public static string GetCommonName(X509Certificate2 x509cert)
|
||||
{
|
||||
return x509cert.GetNameInfo(X509NameType.SimpleName, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает дату окончания действия сертификата
|
||||
/// </summary>
|
||||
public static DateTime GetNotAfterDate(X509Certificate2 x509cert)
|
||||
{
|
||||
// Сначала пытаемся определить срок первичного ключа, а затем уже самого сертификата
|
||||
DateTime? датаОкончания = GetPrivateKeyUsageEndDate(x509cert);
|
||||
if (датаОкончания != null) return (DateTime)датаОкончания;
|
||||
return x509cert.NotAfter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Известные номера расширений сертификата
|
||||
/// </summary>
|
||||
private class KnownOids
|
||||
{
|
||||
public const string PrivateKeyUsagePeriod = "2.5.29.16";
|
||||
}
|
||||
|
||||
public static DateTime? GetPrivateKeyUsageEndDate(X509Certificate2 x509cert)
|
||||
{
|
||||
foreach (var ext in x509cert.Extensions)
|
||||
{
|
||||
if (ext.Oid.Value == KnownOids.PrivateKeyUsagePeriod)
|
||||
{
|
||||
// Дата начала с индексом 0, дата окончания с индексом 1
|
||||
return ParseAsn1Datetime(ext, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Разбирает значение типа дата из серии значений ASN1 присоединенных к расширению
|
||||
/// </summary>
|
||||
private static DateTime? ParseAsn1Datetime(X509Extension ext, int valueIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
Asn1Object asnObject = (new Asn1InputStream(ext.RawData)).ReadObject();
|
||||
if (asnObject == null) return null;
|
||||
var asnSequence = Asn1Sequence.GetInstance(asnObject);
|
||||
if (asnSequence.Count <= valueIndex) return null;
|
||||
var asn = (Asn1TaggedObject)asnSequence[valueIndex];
|
||||
|
||||
var asnStr = Asn1OctetString.GetInstance(asn, false);
|
||||
string s = Encoding.UTF8.GetString(asnStr.GetOctets());
|
||||
int year = int.Parse(s.Substring(0, 4));
|
||||
int month = int.Parse(s.Substring(4, 2));
|
||||
int day = int.Parse(s.Substring(6, 2));
|
||||
int hour = int.Parse(s.Substring(8, 2));
|
||||
int minute = int.Parse(s.Substring(10, 2));
|
||||
int second = int.Parse(s.Substring(12, 2));
|
||||
// Последний символ - буква 'Z'
|
||||
return new DateTime(year, month, day, hour, minute, second);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ДатьСтрокуФИОСертификатаСДатойОкончания(X509Certificate2 x509cert)
|
||||
{
|
||||
var фио = ДатьФИОСертификата(x509cert);
|
||||
return фио.Фамилия + " " + фио.Имя + " " + фио.Отчество +
|
||||
" до " + GetNotAfterDate(x509cert).ToString("dd.MM.yyyy");
|
||||
}
|
||||
|
||||
public static string ДатьСтрокуФИОСертификата(X509Certificate2 x509cert)
|
||||
{
|
||||
var фио = ДатьФИОСертификата(x509cert);
|
||||
return фио.Фамилия + " " + фио.Имя + " " + фио.Отчество;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает массив из трех строк, содержащих соответственно Фамилию, Имя и Отчество
|
||||
/// полученных из данных сертификата. Если сертификат не содержит ФИО возвращается массив
|
||||
/// из трех пустых строк. Это не точный метод определять имя, он предполагает что
|
||||
/// поля SN, G, CN содержат ФИО в определенном порядке, что правдоподобно но не обязательно.
|
||||
/// </summary>
|
||||
public static (string Фамилия, string Имя, string Отчество) ДатьФИОСертификата(X509Certificate2 x509cert)
|
||||
{
|
||||
string фам = "", имя = "", отч = "";
|
||||
|
||||
// Сначала ищем поля surname (SN) и given-name (G)
|
||||
string sn = DecodeSubjectField(x509cert, "SN");
|
||||
string g = DecodeSubjectField(x509cert, "G");
|
||||
if (!string.IsNullOrEmpty(sn) && !string.IsNullOrEmpty(g))
|
||||
{
|
||||
фам = sn;
|
||||
string[] gParts = g.Split(' ');
|
||||
if (gParts != null && gParts.Length >= 1) имя = gParts[0];
|
||||
if (gParts != null && gParts.Length >= 2) отч = gParts[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Иначе берем три первых слова из common name (CN), игнорируя кавычки
|
||||
string cn = DecodeSubjectField(x509cert, "CN");
|
||||
if (!string.IsNullOrEmpty(cn))
|
||||
{
|
||||
cn = new StringBuilder(cn).Replace("\"", "").ToString();
|
||||
char[] separators = { ' ', ';' };
|
||||
string[] cnParts = cn.Split(separators);
|
||||
if (cnParts != null && cnParts.Length >= 1) фам = cnParts[0];
|
||||
if (cnParts != null && cnParts.Length >= 2) имя = cnParts[1];
|
||||
if (cnParts != null && cnParts.Length >= 3) отч = cnParts[2];
|
||||
}
|
||||
}
|
||||
|
||||
return (фам, имя, отч);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает строку ИНН владельца сертификата
|
||||
/// </summary>
|
||||
public static string ДатьИННСертификата(X509Certificate2 x509cert)
|
||||
{
|
||||
return DecodeSubjectField(x509cert, "ИНН");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает значение поля с именем @subName включенного в различимое имя Subject
|
||||
/// </summary>
|
||||
private static string DecodeSubjectField(X509Certificate2 x509cert, string subName)
|
||||
{
|
||||
// Чтобы посмотреть все поля сертификата
|
||||
//System.Diagnostics.Trace.WriteLine("x509decode=" + x509cert.SubjectName.Decode(
|
||||
//X500DistinguishedNameFlags.UseNewLines));
|
||||
|
||||
// Декодируем различимое имя на отдельные строки через переводы строк для надежности разбора
|
||||
string decoded = x509cert.SubjectName.Decode(X500DistinguishedNameFlags.UseNewLines);
|
||||
char[] separators = { '\n', '\r' };
|
||||
string[] parts = decoded.Split(separators, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts == null) return null;
|
||||
|
||||
// Каждая часть начинается с имени и отделяется от значения символом равно
|
||||
foreach (string part in parts)
|
||||
{
|
||||
if (part.Length <= subName.Length + 1) continue;
|
||||
if (part.StartsWith(subName) && part[subName.Length] == '=')
|
||||
{
|
||||
return part.Substring(subName.Length + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int Compare(X509Certificate2 x, X509Certificate2 y)
|
||||
{
|
||||
if (x == null && y != null) return -1;
|
||||
if (x != null && y == null) return 1;
|
||||
if (x == null && y == null) return 0;
|
||||
|
||||
// Сначала сравниваем ФИО
|
||||
int sign = string.Compare(ДатьСтрокуФИОСертификата(x), ДатьСтрокуФИОСертификата(y), true);
|
||||
if (sign != 0) return sign;
|
||||
|
||||
// Затем дату окончания действия
|
||||
return GetNotAfterDate(x).CompareTo(GetNotAfterDate(y));
|
||||
}
|
||||
|
||||
public class CertificateComparer : IComparer<X509Certificate2>
|
||||
{
|
||||
public int Compare(X509Certificate2 x, X509Certificate2 y) => HcsX509Tools.Compare(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,132 +0,0 @@
|
||||
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 все;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,189 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,162 +0,0 @@
|
||||
using Hcs.ClientApi.RemoteCaller;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using HouseManagement = Hcs.Service.Async.HouseManagement.v15_7_0_1;
|
||||
|
||||
namespace Hcs.Service.Async.HouseManagement.v15_7_0_1
|
||||
{
|
||||
public partial class AckRequestAck : IHcsAck { }
|
||||
public partial class getStateResult : IHcsGetStateResultMany { }
|
||||
public partial class Fault : IHcsFault { }
|
||||
public partial class HeaderType : IHcsHeaderType { }
|
||||
}
|
||||
|
||||
namespace Hcs.ClientApi.HouseManagementApi
|
||||
{
|
||||
public class HcsHouseManagementMethod : HcsRemoteCallMethod<IHcsGetStateResultMany>
|
||||
{
|
||||
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<IHcsGetStateResultMany> 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<IHcsGetStateResultMany> 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<IHcsGetStateResultMany> 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(IHcsGetStateResultMany stateResult)
|
||||
{
|
||||
return ParseImportResults(stateResult, 1, true).First();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Разбирает стандартный ответ HCS на операцию импорта с приемом ошибок
|
||||
/// </summary>
|
||||
protected HouseManagement.getStateResultImportResultCommonResult[] ParseImportResults(
|
||||
IHcsGetStateResultMany 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); });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,126 +0,0 @@
|
||||
using HouseManagement = Hcs.Service.Async.HouseManagement.v15_7_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 = "Электроснабжение"
|
||||
};
|
||||
|
||||
// TODO: Подставить корректный код и ГУИД
|
||||
public static HouseManagement.ContractSubjectTypeMunicipalResource ElectricSupplyMunicipalResource
|
||||
=> new HouseManagement.ContractSubjectTypeMunicipalResource()
|
||||
{
|
||||
Code = "8",
|
||||
GUID = "7379be86-6c95-4e41-b000-3bc703d35969",
|
||||
Name = "Электрическая энергия"
|
||||
};
|
||||
|
||||
public static HouseManagement.ContractSubjectTypeServiceType HeatingSupplyServiceType
|
||||
=> new HouseManagement.ContractSubjectTypeServiceType()
|
||||
{
|
||||
Code = "6",
|
||||
GUID = "74925764-ddf3-4b4b-b18d-85994187c13a",
|
||||
Name = "Отопление"
|
||||
};
|
||||
|
||||
public static HouseManagement.ContractSubjectTypeMunicipalResource HeatingSupplyMunicipalResource
|
||||
=> new HouseManagement.ContractSubjectTypeMunicipalResource()
|
||||
{
|
||||
// Значения взяты из справочника 239
|
||||
Code = "4",
|
||||
GUID = "eec6e4b8-76c8-4fce-99b7-c95718edad19",
|
||||
Name = null
|
||||
};
|
||||
|
||||
public static HouseManagement.ContractSubjectTypeServiceType HotWaterSupplyServiceType
|
||||
=> new HouseManagement.ContractSubjectTypeServiceType()
|
||||
{
|
||||
Code = "2",
|
||||
GUID = "ee8c6a41-aaf8-41c8-a1f6-5832cc622f88",
|
||||
Name = null
|
||||
};
|
||||
|
||||
// TODO: Подставить корректный код и ГУИД
|
||||
public static HouseManagement.ContractSubjectTypeMunicipalResource HotWaterSupplyMunicipalResource
|
||||
=> new HouseManagement.ContractSubjectTypeMunicipalResource()
|
||||
{
|
||||
Code = "2.2",
|
||||
GUID = "1471de55-c2e7-4101-9f2a-9bef6fffb896",
|
||||
Name = "Горячая вода 2"
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,190 +0,0 @@
|
||||
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.v15_7_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.ItemsChoiceType26> { };
|
||||
List<string> items = new List<string> { };
|
||||
|
||||
if (fiasHouseGuid != null)
|
||||
{
|
||||
itemNames.Add(HouseManagement.ItemsChoiceType26.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.ItemsChoiceType26.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.ItemsChoiceType17.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.ItemsChoiceType18.ContractGUID:
|
||||
основание.ГуидДоговора = ParseGuid(itemValue);
|
||||
break;
|
||||
case HouseManagement.ItemsChoiceType18.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.ItemChoiceType11.FIASHouseGuid: размещение.ГуидЗдания = ParseGuid(source.Item); break;
|
||||
case HouseManagement.ItemChoiceType11.PremisesGUID: размещение.ГуидПомещения = ParseGuid(source.Item); break;
|
||||
case HouseManagement.ItemChoiceType11.LivingRoomGUID: размещение.ГуидЖилойКомнаты = ParseGuid(source.Item); break;
|
||||
default: throw new HcsException("Неизвестный тип размещения ЛС: " + source.ItemElementName);
|
||||
}
|
||||
|
||||
return размещение;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
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.v15_7_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)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,165 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using Hcs.Service.Async.HouseManagement.v15_7_0_1;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using HouseManagement = Hcs.Service.Async.HouseManagement.v15_7_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.ItemsChoiceType24> itemNames = [HouseManagement.ItemsChoiceType24.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 прибор;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,297 +0,0 @@
|
||||
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.v15_7_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.ItemsChoiceType32> { };
|
||||
List<object> items = new List<object> { };
|
||||
|
||||
if (contractRootGuid != null)
|
||||
{
|
||||
itemNames.Add(HouseManagement.ItemsChoiceType32.ContractRootGUID);
|
||||
items.Add(FormatGuid(contractRootGuid));
|
||||
}
|
||||
|
||||
if (contractNumber != null)
|
||||
{
|
||||
itemNames.Add(HouseManagement.ItemsChoiceType32.ContractNumber);
|
||||
items.Add(contractNumber);
|
||||
}
|
||||
|
||||
if (exportNextGuid != null)
|
||||
{
|
||||
itemNames.Add(HouseManagement.ItemsChoiceType32.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,125 +0,0 @@
|
||||
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.v15_7_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.ItemsChoiceType34> { };
|
||||
List<string> items = new List<string> { };
|
||||
|
||||
if (договор.ГуидВерсииДоговора != default)
|
||||
{
|
||||
itemNames.Add(HouseManagement.ItemsChoiceType34.ContractGUID);
|
||||
items.Add(FormatGuid(договор.ГуидВерсииДоговора));
|
||||
}
|
||||
else
|
||||
{
|
||||
itemNames.Add(HouseManagement.ItemsChoiceType34.ContractRootGUID);
|
||||
items.Add(FormatGuid(договор.ГуидДоговора));
|
||||
}
|
||||
|
||||
// TODO: Проверить комментарий
|
||||
// Если указан guid следующей страницы данных, добавляем его в параметры
|
||||
// (на 20.12.2023 эта функция не работает, первый пакет содержит 1000 записей
|
||||
// и запрос второго пакета с ExportObjectGUID возвращает "Bad request")
|
||||
if (firstGuid != null)
|
||||
{
|
||||
itemNames.Add(HouseManagement.ItemsChoiceType34.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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,192 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using HouseManagement = Hcs.Service.Async.HouseManagement.v15_7_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.ItemsChoiceType17.ContractGUID]
|
||||
};
|
||||
account.AccountReasons = new HouseManagement.AccountReasonsImportType()
|
||||
{
|
||||
SupplyResourceContract = [reasonRSO]
|
||||
};
|
||||
|
||||
account.ItemElementName = HouseManagement.ItemChoiceType8.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.ItemChoiceType9.FIASHouseGuid;
|
||||
accomodation.Item = FormatGuid(размещение.ГуидЗдания);
|
||||
}
|
||||
else if (размещение.ГуидПомещения != null)
|
||||
{
|
||||
accomodation.ItemElementName = HouseManagement.ItemChoiceType9.PremisesGUID;
|
||||
accomodation.Item = FormatGuid(размещение.ГуидПомещения);
|
||||
}
|
||||
else if (размещение.ГуидЖилойКомнаты != null)
|
||||
{
|
||||
accomodation.ItemElementName = HouseManagement.ItemChoiceType9.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.ItemChoiceType26.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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,207 +0,0 @@
|
||||
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.v15_7_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.ItemChoiceType26.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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,392 +0,0 @@
|
||||
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.v15_7_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.ItemChoiceType32.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.ItemChoiceType26.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.HeatingSupplyServiceType,
|
||||
MunicipalResource = HcsHouseManagementNsi.HeatingSupplyMunicipalResource,
|
||||
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.ItemsChoiceType9.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; // Не указана дата окончания поставки ресурса
|
||||
// TODO: Необходимо указывать только для отопления и ГВС, нужен рефактор кода
|
||||
pair.HeatingSystemType = new HouseManagement.SupplyResourceContractTypeObjectAddressPairHeatingSystemType()
|
||||
{
|
||||
OpenOrNot = HouseManagement.SupplyResourceContractTypeObjectAddressPairHeatingSystemTypeOpenOrNot.Closed,
|
||||
CentralizedOrNot = HouseManagement.SupplyResourceContractTypeObjectAddressPairHeatingSystemTypeCentralizedOrNot.Centralized
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,135 +0,0 @@
|
||||
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.v15_7_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.ItemChoiceType34.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();
|
||||
|
||||
// TODO: Эти значения должны быть регулируемыми
|
||||
var serviceType = new HouseManagement.ContractSubjectObjectAdressTypeServiceType()
|
||||
{
|
||||
Code = HcsHouseManagementNsi.HeatingSupplyServiceType.Code,
|
||||
GUID = HcsHouseManagementNsi.HeatingSupplyServiceType.GUID,
|
||||
Name = HcsHouseManagementNsi.HeatingSupplyServiceType.Name
|
||||
};
|
||||
|
||||
// TODO: Эти значения должны быть регулируемыми
|
||||
var municipalResource = new HouseManagement.ContractSubjectObjectAdressTypeMunicipalResource()
|
||||
{
|
||||
Code = HcsHouseManagementNsi.HeatingSupplyMunicipalResource.Code,
|
||||
GUID = HcsHouseManagementNsi.HeatingSupplyMunicipalResource.GUID,
|
||||
Name = HcsHouseManagementNsi.HeatingSupplyMunicipalResource.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using Hcs.Service.Async.HouseManagement.v15_7_0_1;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using HouseManagement = Hcs.Service.Async.HouseManagement.v15_7_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 = ItemChoiceType35.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Интерфейс для механизма вывода отладочных сообщений для обработки вызывающей системой
|
||||
/// </summary>
|
||||
public interface IHcsLogger
|
||||
{
|
||||
void WriteLine(string message);
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
namespace Hcs.ClientApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Интерфейс для механизма захвата отправляемых и принимаемых
|
||||
/// SOAP сообщений в ходе коммуникации с ГИС ЖКХ
|
||||
/// </summary>
|
||||
public interface IHcsMessageCapture
|
||||
{
|
||||
void CaptureMessage(bool sentOrReceived, string messageBody);
|
||||
}
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Nsi = Hcs.Service.Async.Nsi.v15_7_0_1;
|
||||
|
||||
namespace Hcs.ClientApi.NsiApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Операции экспорта данных справочников поставщика информации ГИС ЖКХ
|
||||
/// </summary>
|
||||
internal class HcsMethodExportNsi : HcsNsiMethod
|
||||
{
|
||||
public HcsMethodExportNsi(HcsClientConfig config) : base(config)
|
||||
{
|
||||
EnableMinimalResponseWaitDelay = true;
|
||||
CanBeRestarted = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает данные справочников поставщика информации
|
||||
/// </summary>
|
||||
/// <param name="regNum">Реестровый номер справочника</param>
|
||||
/// <param name="token">Токен отмены</param>
|
||||
/// <returns>Список справочников</returns>
|
||||
public async Task<IEnumerable<ГисСправочник>> GetNsiItem(int regNum, CancellationToken token)
|
||||
{
|
||||
var request = new Nsi.exportDataProviderNsiItemRequest
|
||||
{
|
||||
Id = HcsConstants.SignedXmlElementId,
|
||||
RegistryNumber = GetRegNumFromInt(regNum),
|
||||
// http://open-gkh.ru/Nsi/exportDataProviderNsiItemRequest.html
|
||||
version = "10.0.1.2"
|
||||
};
|
||||
|
||||
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
|
||||
{
|
||||
var response = await portClient.exportDataProviderNsiItemAsync(CreateRequestHeader(), request);
|
||||
return response.AckRequest.Ack;
|
||||
}, token);
|
||||
|
||||
return stateResult.Items
|
||||
.OfType<Nsi.NsiItemType>()
|
||||
.Select(x => AdoptNsiItemType(x));
|
||||
}
|
||||
|
||||
private Nsi.exportDataProviderNsiItemRequestRegistryNumber GetRegNumFromInt(int regNum)
|
||||
{
|
||||
switch (regNum)
|
||||
{
|
||||
case 1:
|
||||
return Nsi.exportDataProviderNsiItemRequestRegistryNumber.Item1;
|
||||
case 51:
|
||||
return Nsi.exportDataProviderNsiItemRequestRegistryNumber.Item51;
|
||||
case 59:
|
||||
return Nsi.exportDataProviderNsiItemRequestRegistryNumber.Item59;
|
||||
case 219:
|
||||
return Nsi.exportDataProviderNsiItemRequestRegistryNumber.Item219;
|
||||
case 272:
|
||||
return Nsi.exportDataProviderNsiItemRequestRegistryNumber.Item272;
|
||||
case 302:
|
||||
return Nsi.exportDataProviderNsiItemRequestRegistryNumber.Item302;
|
||||
case 337:
|
||||
return Nsi.exportDataProviderNsiItemRequestRegistryNumber.Item337;
|
||||
default:
|
||||
throw new NotImplementedException($"Cannot convert {regNum} to {typeof(Nsi.exportDataProviderNsiItemRequestRegistryNumber)}");
|
||||
}
|
||||
}
|
||||
|
||||
private ГисСправочник AdoptNsiItemType(Nsi.NsiItemType input)
|
||||
{
|
||||
var справочник = new ГисСправочник()
|
||||
{
|
||||
реестровыйНомер = input.NsiItemRegistryNumber,
|
||||
датаФормирования = input.Created,
|
||||
элементы = AdoptNsiElementTypes(input.NsiElement)
|
||||
};
|
||||
|
||||
return справочник;
|
||||
}
|
||||
|
||||
private ГисЭлементСправочника[] AdoptNsiElementTypes(Nsi.NsiElementType[] input)
|
||||
{
|
||||
var элементыСправочника = new List<ГисЭлементСправочника>();
|
||||
foreach (var element in input)
|
||||
{
|
||||
var поляЭлементаСправочника = new List<ГисПолеЭлементаСправочника>();
|
||||
foreach (var field in element.NsiElementField)
|
||||
{
|
||||
CallOnType<Nsi.NsiElementStringFieldType>(field, x =>
|
||||
{
|
||||
поляЭлементаСправочника.Add(new ГисПолеЭлементаСправочника()
|
||||
{
|
||||
наименование = x.Name,
|
||||
значение = x.Value
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
элементыСправочника.Add(new ГисЭлементСправочника()
|
||||
{
|
||||
код = element.Code,
|
||||
гуид = ParseGuid(element.GUID),
|
||||
актуальный = element.IsActual,
|
||||
поля = [.. поляЭлементаСправочника],
|
||||
элементы = element.ChildElement?.Length > 0 ? AdoptNsiElementTypes(element.ChildElement) : null
|
||||
});
|
||||
}
|
||||
return [.. элементыСправочника];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hcs.ClientApi.NsiApi
|
||||
{
|
||||
public class HcsNsiApi
|
||||
{
|
||||
public HcsClientConfig Config { get; private set; }
|
||||
|
||||
public HcsNsiApi(HcsClientConfig config)
|
||||
{
|
||||
Config = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает данные справочников поставщика информации
|
||||
/// </summary>
|
||||
/// <param name="regNum">Реестровый номер справочника</param>
|
||||
/// <param name="token">Токен отмены</param>
|
||||
/// <returns>Список справочников</returns>
|
||||
public async Task<IEnumerable<ГисСправочник>> GetNsiItem(int regNum, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var method = new HcsMethodExportNsi(Config);
|
||||
return await method.GetNsiItem(regNum, token);
|
||||
}
|
||||
catch (HcsNoResultsRemoteException)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,112 +0,0 @@
|
||||
using Hcs.ClientApi.RemoteCaller;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Nsi = Hcs.Service.Async.Nsi.v15_7_0_1;
|
||||
|
||||
namespace Hcs.Service.Async.Nsi.v15_7_0_1
|
||||
{
|
||||
public partial class AckRequestAck : IHcsAck { }
|
||||
public partial class getStateResult : IHcsGetStateResultMany { }
|
||||
public partial class Fault : IHcsFault { }
|
||||
public partial class HeaderType : IHcsHeaderType { }
|
||||
}
|
||||
|
||||
namespace Hcs.ClientApi.NsiApi
|
||||
{
|
||||
internal class HcsNsiMethod : HcsRemoteCallMethod<IHcsGetStateResultMany>
|
||||
{
|
||||
public HcsEndPoints EndPoint => HcsEndPoints.NsiAsync;
|
||||
|
||||
public Nsi.RequestHeader CreateRequestHeader() =>
|
||||
HcsRequestHelper.CreateHeader<Nsi.RequestHeader>(ClientConfig);
|
||||
|
||||
public HcsNsiMethod(HcsClientConfig config) : base(config) { }
|
||||
|
||||
public System.ServiceModel.EndpointAddress RemoteAddress
|
||||
=> GetEndpointAddress(HcsConstants.EndPointLocator.GetPath(EndPoint));
|
||||
|
||||
private Nsi.NsiPortsTypeAsyncClient NewPortClient()
|
||||
{
|
||||
var client = new Nsi.NsiPortsTypeAsyncClient(_binding, RemoteAddress);
|
||||
ConfigureEndpointCredentials(client.Endpoint, client.ClientCredentials);
|
||||
return client;
|
||||
}
|
||||
|
||||
public async Task<IHcsGetStateResultMany> SendAndWaitResultAsync(
|
||||
object request,
|
||||
Func<Nsi.NsiPortsTypeAsyncClient, Task<IHcsAck>> sender,
|
||||
CancellationToken token)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await SendAndWaitResultAsyncImpl(request, sender, token);
|
||||
}
|
||||
catch (HcsRestartTimeoutException e)
|
||||
{
|
||||
if (!CanBeRestarted) throw new HcsException("Превышен лимит ожидания выполнения запроса", e);
|
||||
Log($"Перезапускаем запрос типа {request.GetType().Name}...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IHcsGetStateResultMany> SendAndWaitResultAsyncImpl(
|
||||
object request,
|
||||
Func<Nsi.NsiPortsTypeAsyncClient, Task<IHcsAck>> sender,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException("Null 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<Nsi.ErrorMessageType>().ToList().ForEach(x =>
|
||||
{
|
||||
throw HcsRemoteException.CreateNew(x.ErrorCode, x.Description);
|
||||
});
|
||||
|
||||
return stateResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполняет однократную проверку наличия результата.
|
||||
/// Возвращает null если результата еще нет.
|
||||
/// </summary>
|
||||
protected override async Task<IHcsGetStateResultMany> TryGetResultAsync(IHcsAck sourceAck, CancellationToken token)
|
||||
{
|
||||
using (var client = NewPortClient())
|
||||
{
|
||||
var requestHeader = HcsRequestHelper.CreateHeader<Nsi.RequestHeader>(_config);
|
||||
var requestBody = new Nsi.getStateRequest { MessageGUID = sourceAck.MessageGUID };
|
||||
|
||||
var response = await client.getStateAsync(requestHeader, requestBody);
|
||||
var resultBody = response.getStateResult;
|
||||
|
||||
if (resultBody.RequestState == HcsAsyncRequestStateTypes.Ready)
|
||||
{
|
||||
return resultBody;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,88 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using NsiCommon = Hcs.Service.Async.NsiCommon.v15_7_0_1;
|
||||
|
||||
namespace Hcs.ClientApi.NsiCommonApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Операции экспорта общих справочников подсистемы НСИ
|
||||
/// </summary>
|
||||
internal class HcsMethodExportNsiCommon : HcsNsiCommonMethod
|
||||
{
|
||||
public HcsMethodExportNsiCommon(HcsClientConfig config) : base(config)
|
||||
{
|
||||
EnableMinimalResponseWaitDelay = true;
|
||||
CanBeRestarted = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает общий справочник подсистемы НСИ
|
||||
/// </summary>
|
||||
/// <param name="regNum">Реестровый номер справочника</param>
|
||||
/// <param name="token">Токен отмены</param>
|
||||
/// <returns>Справочник</returns>
|
||||
public async Task<ГисСправочник> GetNsiItem(int regNum, CancellationToken token)
|
||||
{
|
||||
var request = new NsiCommon.exportNsiItemRequest
|
||||
{
|
||||
Id = HcsConstants.SignedXmlElementId,
|
||||
RegistryNumber = regNum.ToString(),
|
||||
// http://open-gkh.ru/NsiCommon/exportNsiItemRequest.html
|
||||
version = "10.0.1.2"
|
||||
};
|
||||
|
||||
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
|
||||
{
|
||||
var response = await portClient.exportNsiItemAsync(CreateRequestHeader(), request);
|
||||
return response.AckRequest.Ack;
|
||||
}, token);
|
||||
|
||||
return AdoptNsiItemType(stateResult.Item as NsiCommon.NsiItemType);
|
||||
}
|
||||
|
||||
private ГисСправочник AdoptNsiItemType(NsiCommon.NsiItemType input)
|
||||
{
|
||||
var справочник = new ГисСправочник()
|
||||
{
|
||||
реестровыйНомер = input.NsiItemRegistryNumber,
|
||||
датаФормирования = input.Created,
|
||||
элементы = AdoptNsiElementTypes(input.NsiElement)
|
||||
};
|
||||
|
||||
return справочник;
|
||||
}
|
||||
|
||||
private ГисЭлементСправочника[] AdoptNsiElementTypes(NsiCommon.NsiElementType[] input)
|
||||
{
|
||||
var элементыСправочника = new List<ГисЭлементСправочника>();
|
||||
foreach (var element in input)
|
||||
{
|
||||
var поляЭлементаСправочника = new List<ГисПолеЭлементаСправочника>();
|
||||
foreach (var field in element.NsiElementField)
|
||||
{
|
||||
CallOnType<NsiCommon.NsiElementStringFieldType>(field, x =>
|
||||
{
|
||||
поляЭлементаСправочника.Add(new ГисПолеЭлементаСправочника()
|
||||
{
|
||||
наименование = x.Name,
|
||||
значение = x.Value
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
элементыСправочника.Add(new ГисЭлементСправочника()
|
||||
{
|
||||
код = element.Code,
|
||||
гуид = ParseGuid(element.GUID),
|
||||
актуальный = element.IsActual,
|
||||
поля = [.. поляЭлементаСправочника],
|
||||
элементы = element.ChildElement?.Length > 0 ? AdoptNsiElementTypes(element.ChildElement) : null
|
||||
});
|
||||
}
|
||||
return [.. элементыСправочника];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hcs.ClientApi.NsiCommonApi
|
||||
{
|
||||
public class HcsNsiCommonApi
|
||||
{
|
||||
public HcsClientConfig Config { get; private set; }
|
||||
|
||||
public HcsNsiCommonApi(HcsClientConfig config)
|
||||
{
|
||||
Config = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает данные справочников поставщика информации
|
||||
/// </summary>
|
||||
/// <param name="regNum">Реестровый номер справочника</param>
|
||||
/// <param name="token">Токен отмены</param>
|
||||
/// <returns>Список справочников</returns>
|
||||
public async Task<ГисСправочник> GetNsiItem(int regNum, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var method = new HcsMethodExportNsiCommon(Config);
|
||||
return await method.GetNsiItem(regNum, token);
|
||||
}
|
||||
catch (HcsNoResultsRemoteException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,111 +0,0 @@
|
||||
using Hcs.ClientApi.RemoteCaller;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using NsiCommon = Hcs.Service.Async.NsiCommon.v15_7_0_1;
|
||||
|
||||
namespace Hcs.Service.Async.NsiCommon.v15_7_0_1
|
||||
{
|
||||
public partial class AckRequestAck : IHcsAck { }
|
||||
public partial class getStateResult : IHcsGetStateResultOne { }
|
||||
public partial class Fault : IHcsFault { }
|
||||
public partial class HeaderType : IHcsHeaderType { }
|
||||
}
|
||||
|
||||
namespace Hcs.ClientApi.NsiCommonApi
|
||||
{
|
||||
internal class HcsNsiCommonMethod : HcsRemoteCallMethod<IHcsGetStateResultOne>
|
||||
{
|
||||
public HcsEndPoints EndPoint => HcsEndPoints.NsiCommonAsync;
|
||||
|
||||
public NsiCommon.ISRequestHeader CreateRequestHeader() =>
|
||||
HcsRequestHelper.CreateHeader<NsiCommon.ISRequestHeader>(ClientConfig);
|
||||
|
||||
public HcsNsiCommonMethod(HcsClientConfig config) : base(config) { }
|
||||
|
||||
public System.ServiceModel.EndpointAddress RemoteAddress
|
||||
=> GetEndpointAddress(HcsConstants.EndPointLocator.GetPath(EndPoint));
|
||||
|
||||
private NsiCommon.NsiPortsTypeAsyncClient NewPortClient()
|
||||
{
|
||||
var client = new NsiCommon.NsiPortsTypeAsyncClient(_binding, RemoteAddress);
|
||||
ConfigureEndpointCredentials(client.Endpoint, client.ClientCredentials);
|
||||
return client;
|
||||
}
|
||||
|
||||
public async Task<IHcsGetStateResultOne> SendAndWaitResultAsync(
|
||||
object request,
|
||||
Func<NsiCommon.NsiPortsTypeAsyncClient, Task<IHcsAck>> sender,
|
||||
CancellationToken token)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await SendAndWaitResultAsyncImpl(request, sender, token);
|
||||
}
|
||||
catch (HcsRestartTimeoutException e)
|
||||
{
|
||||
if (!CanBeRestarted) throw new HcsException("Превышен лимит ожидания выполнения запроса", e);
|
||||
Log($"Перезапускаем запрос типа {request.GetType().Name}...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IHcsGetStateResultOne> SendAndWaitResultAsyncImpl(
|
||||
object request,
|
||||
Func<NsiCommon.NsiPortsTypeAsyncClient, Task<IHcsAck>> sender,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException("Null 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);
|
||||
|
||||
if (stateResult.Item is NsiCommon.ErrorMessageType x)
|
||||
{
|
||||
throw HcsRemoteException.CreateNew(x.ErrorCode, x.Description);
|
||||
}
|
||||
|
||||
return stateResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполняет однократную проверку наличия результата.
|
||||
/// Возвращает null если результата еще нет.
|
||||
/// </summary>
|
||||
protected override async Task<IHcsGetStateResultOne> TryGetResultAsync(IHcsAck sourceAck, CancellationToken token)
|
||||
{
|
||||
using (var client = NewPortClient())
|
||||
{
|
||||
var requestHeader = HcsRequestHelper.CreateHeader<NsiCommon.ISRequestHeader>(_config);
|
||||
var requestBody = new NsiCommon.getStateRequest { MessageGUID = sourceAck.MessageGUID };
|
||||
|
||||
var response = await client.getStateAsync(requestHeader, requestBody);
|
||||
var resultBody = response.getStateResult;
|
||||
|
||||
if (resultBody.RequestState == HcsAsyncRequestStateTypes.Ready)
|
||||
{
|
||||
return resultBody;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,133 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using OrgRegistryCommon = Hcs.Service.Async.OrgRegistryCommon.v15_7_0_1;
|
||||
|
||||
namespace Hcs.ClientApi.OrgRegistryCommonApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Операции экспорта данных из реестра организаций ГИС ЖКХ
|
||||
/// </summary>
|
||||
public class HcsMethodExportOrgRegistry : HcsOrgRegistryCommonMethod
|
||||
{
|
||||
public HcsMethodExportOrgRegistry(HcsClientConfig config) : base(config)
|
||||
{
|
||||
EnableMinimalResponseWaitDelay = true;
|
||||
CanBeRestarted = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает карточки организации в ГИС ЖКХ по номеру ОГРН организации.
|
||||
/// При отсутствии результатов будет выброшено HcsNoResultsRemoteException.
|
||||
/// </summary>
|
||||
public async Task<IEnumerable<ГисОрганизация>> GetOrgByOgrn(
|
||||
string ogrn, string kpp, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ogrn)) throw new ArgumentException("Не указан ОГРН для поиска организации");
|
||||
if (ogrn.Length != ГисОрганизация.ДлинаОГРН && ogrn.Length != ГисОрганизация.ДлинаОГРНИП)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"В строке ОГРН допускается или {ГисОрганизация.ДлинаОГРН} или {ГисОрганизация.ДлинаОГРНИП} символов: {ogrn}");
|
||||
}
|
||||
|
||||
var criteria = new OrgRegistryCommon.exportOrgRegistryRequestSearchCriteria();
|
||||
if (!string.IsNullOrEmpty(kpp))
|
||||
{
|
||||
criteria.ItemsElementName = [OrgRegistryCommon.ItemsChoiceType3.OGRN, OrgRegistryCommon.ItemsChoiceType3.KPP];
|
||||
criteria.Items = [ogrn, kpp];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ogrn.Length == ГисОрганизация.ДлинаОГРНИП)
|
||||
criteria.ItemsElementName = [OrgRegistryCommon.ItemsChoiceType3.OGRNIP];
|
||||
else criteria.ItemsElementName = [OrgRegistryCommon.ItemsChoiceType3.OGRN];
|
||||
criteria.Items = [ogrn];
|
||||
}
|
||||
|
||||
var request = new OrgRegistryCommon.exportOrgRegistryRequest
|
||||
{
|
||||
Id = HcsConstants.SignedXmlElementId,
|
||||
SearchCriteria = [criteria]
|
||||
};
|
||||
|
||||
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
|
||||
{
|
||||
var response = await portClient.exportOrgRegistryAsync(CreateRequestHeader(), request);
|
||||
return response.AckRequest.Ack;
|
||||
}, token);
|
||||
|
||||
// В возвращаемой структуре мало ценной информации, только ГУИД организации в ГИС ЖКХ
|
||||
// (необходимый для размещения договоров) и ГУИД поставщика информации OrgPPAGUID.
|
||||
// Для организаций с филиалами может вернуться список из нескольких ГУИД.
|
||||
return stateResult.Items
|
||||
.OfType<OrgRegistryCommon.exportOrgRegistryResultType>()
|
||||
.Select(x => Adopt(x));
|
||||
}
|
||||
|
||||
private ГисОрганизация Adopt(OrgRegistryCommon.exportOrgRegistryResultType orgResult)
|
||||
{
|
||||
if (orgResult.OrgVersion == null)
|
||||
throw new HcsException("В структуре exportOrgRegistryResultType не указано поле OrgVersion");
|
||||
|
||||
var организация = new ГисОрганизация()
|
||||
{
|
||||
ГуидОрганизации = ParseGuid(orgResult.orgRootEntityGUID),
|
||||
ГуидВерсииОрганизации = ParseGuid(orgResult.OrgVersion.orgVersionGUID),
|
||||
Действующая = orgResult.OrgVersion.IsActual
|
||||
};
|
||||
|
||||
switch (orgResult.OrgVersion.Item)
|
||||
{
|
||||
case OrgRegistryCommon.LegalType legal:
|
||||
организация.ТипОрганизации = ГисТипОрганизации.ЮЛ;
|
||||
организация.ИНН = legal.INN;
|
||||
организация.КПП = legal.KPP;
|
||||
организация.ОГРН = legal.OGRN;
|
||||
организация.ОКОПФ = legal.OKOPF;
|
||||
организация.КраткоеИмяОрганизации = legal.ShortName;
|
||||
организация.ПолноеИмяОрганизации = legal.FullName;
|
||||
организация.ЮридическийАдрес = legal.Address;
|
||||
if (legal.ActivityEndDateSpecified)
|
||||
организация.ДатаЛиквидации = legal.ActivityEndDate;
|
||||
break;
|
||||
|
||||
case OrgRegistryCommon.EntpsType entps:
|
||||
организация.ТипОрганизации = ГисТипОрганизации.ИП;
|
||||
организация.ИНН = entps.INN;
|
||||
организация.ОГРН = entps.OGRNIP;
|
||||
организация.Фамилия = entps.Surname;
|
||||
организация.Имя = entps.FirstName;
|
||||
организация.Отчество = entps.Patronymic;
|
||||
break;
|
||||
|
||||
case OrgRegistryCommon.SubsidiaryType sub:
|
||||
организация.ТипОрганизации = ГисТипОрганизации.Филиал;
|
||||
организация.ИНН = sub.INN;
|
||||
организация.КПП = sub.KPP;
|
||||
организация.ОГРН = sub.OGRN;
|
||||
организация.ОКОПФ = sub.OKOPF;
|
||||
организация.КраткоеИмяОрганизации = sub.ShortName;
|
||||
организация.ПолноеИмяОрганизации = sub.FullName;
|
||||
организация.ЮридическийАдрес = sub.Address;
|
||||
if (sub.ActivityEndDateSpecified)
|
||||
организация.ДатаЛиквидации = sub.ActivityEndDate;
|
||||
break;
|
||||
|
||||
case OrgRegistryCommon.ForeignBranchType foreign:
|
||||
организация.ТипОрганизации = ГисТипОрганизации.Иностранный;
|
||||
организация.ИНН = foreign.INN;
|
||||
организация.КПП = foreign.KPP;
|
||||
организация.КраткоеИмяОрганизации = foreign.ShortName;
|
||||
организация.ПолноеИмяОрганизации = foreign.FullName;
|
||||
организация.ЮридическийАдрес = foreign.Address;
|
||||
break;
|
||||
}
|
||||
|
||||
return организация;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hcs.ClientApi.OrgRegistryCommonApi
|
||||
{
|
||||
public class HcsOrgRegistryCommonApi
|
||||
{
|
||||
public HcsClientConfig Config { get; private set; }
|
||||
|
||||
public HcsOrgRegistryCommonApi(HcsClientConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает ГУИДы действующих организаций в ГИС ЖКХ по номеру ОГРН (КПП может быть не указан).
|
||||
/// Если организации не найдены, возвращается пустой список.
|
||||
/// </summary>
|
||||
public async Task<IEnumerable<Guid>> GetOrgRootEntityGuidByOgrn(
|
||||
string ogrn, string kpp, CancellationToken token = default)
|
||||
{
|
||||
var orgs = await GetOrgByOgrn(ogrn, kpp, token);
|
||||
return orgs.Where(x => x.Действующая).Select(x => x.ГуидОрганизации);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает карточки организации в ГИС ЖКХ по номеру ОГРН (КПП может быть не указан).
|
||||
/// Если организации не найдены, возвращается пустой список.
|
||||
/// </summary>
|
||||
public async Task<IEnumerable<ГисОрганизация>> GetOrgByOgrn(
|
||||
string ogrn, string kpp, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var method = new HcsMethodExportOrgRegistry(Config);
|
||||
return await method.GetOrgByOgrn(ogrn, kpp, token);
|
||||
}
|
||||
catch (HcsNoResultsRemoteException)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,112 +0,0 @@
|
||||
using Hcs.ClientApi.RemoteCaller;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using OrgRegistryCommon = Hcs.Service.Async.OrgRegistryCommon.v15_7_0_1;
|
||||
|
||||
namespace Hcs.Service.Async.OrgRegistryCommon.v15_7_0_1
|
||||
{
|
||||
public partial class AckRequestAck : IHcsAck { }
|
||||
public partial class getStateResult : IHcsGetStateResultMany { }
|
||||
public partial class Fault : IHcsFault { }
|
||||
public partial class HeaderType : IHcsHeaderType { }
|
||||
}
|
||||
|
||||
namespace Hcs.ClientApi.OrgRegistryCommonApi
|
||||
{
|
||||
public class HcsOrgRegistryCommonMethod : HcsRemoteCallMethod<IHcsGetStateResultMany>
|
||||
{
|
||||
public HcsEndPoints EndPoint => HcsEndPoints.OrgRegistryCommonAsync;
|
||||
|
||||
public OrgRegistryCommon.ISRequestHeader CreateRequestHeader() =>
|
||||
HcsRequestHelper.CreateHeader<OrgRegistryCommon.ISRequestHeader>(ClientConfig);
|
||||
|
||||
public HcsOrgRegistryCommonMethod(HcsClientConfig config) : base(config) { }
|
||||
|
||||
public System.ServiceModel.EndpointAddress RemoteAddress
|
||||
=> GetEndpointAddress(HcsConstants.EndPointLocator.GetPath(EndPoint));
|
||||
|
||||
private OrgRegistryCommon.RegOrgPortsTypeAsyncClient NewPortClient()
|
||||
{
|
||||
var client = new OrgRegistryCommon.RegOrgPortsTypeAsyncClient(_binding, RemoteAddress);
|
||||
ConfigureEndpointCredentials(client.Endpoint, client.ClientCredentials);
|
||||
return client;
|
||||
}
|
||||
|
||||
public async Task<IHcsGetStateResultMany> SendAndWaitResultAsync(
|
||||
object request,
|
||||
Func<OrgRegistryCommon.RegOrgPortsTypeAsyncClient, Task<IHcsAck>> sender,
|
||||
CancellationToken token)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await SendAndWaitResultAsyncImpl(request, sender, token);
|
||||
}
|
||||
catch (HcsRestartTimeoutException e)
|
||||
{
|
||||
if (!CanBeRestarted) throw new HcsException("Превышен лимит ожидания выполнения запроса", e);
|
||||
Log($"Перезапускаем запрос типа {request.GetType().Name}...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IHcsGetStateResultMany> SendAndWaitResultAsyncImpl(
|
||||
object request,
|
||||
Func<OrgRegistryCommon.RegOrgPortsTypeAsyncClient, Task<IHcsAck>> sender,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException("Null 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<OrgRegistryCommon.ErrorMessageType>().ToList().ForEach(x =>
|
||||
{
|
||||
throw HcsRemoteException.CreateNew(x.ErrorCode, x.Description);
|
||||
});
|
||||
|
||||
return stateResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполняет однократную проверку наличия результата.
|
||||
/// Возвращает null если результата еще нет.
|
||||
/// </summary>
|
||||
protected override async Task<IHcsGetStateResultMany> TryGetResultAsync(IHcsAck sourceAck, CancellationToken token)
|
||||
{
|
||||
using (var client = NewPortClient())
|
||||
{
|
||||
var requestHeader = HcsRequestHelper.CreateHeader<OrgRegistryCommon.ISRequestHeader>(_config);
|
||||
var requestBody = new OrgRegistryCommon.getStateRequest { MessageGUID = sourceAck.MessageGUID };
|
||||
|
||||
var response = await client.getStateAsync(requestHeader, requestBody);
|
||||
var resultBody = response.getStateResult;
|
||||
|
||||
if (resultBody.RequestState == HcsAsyncRequestStateTypes.Ready)
|
||||
{
|
||||
return resultBody;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Description;
|
||||
using System.ServiceModel.Dispatcher;
|
||||
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
public class GostSigningEndpointBehavior : IEndpointBehavior
|
||||
{
|
||||
private HcsClientConfig clientConfig;
|
||||
|
||||
public GostSigningEndpointBehavior(HcsClientConfig clientConfig)
|
||||
{
|
||||
this.clientConfig = clientConfig;
|
||||
}
|
||||
|
||||
public void Validate(ServiceEndpoint endpoint)
|
||||
{
|
||||
}
|
||||
|
||||
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
|
||||
{
|
||||
}
|
||||
|
||||
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
|
||||
{
|
||||
}
|
||||
|
||||
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
|
||||
{
|
||||
clientRuntime.MessageInspectors.Add(
|
||||
new GostSigningMessageInspector(clientConfig));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,120 +0,0 @@
|
||||
using GostXades;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Dispatcher;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
/// <summary>
|
||||
/// Фильтр сообщений добавляет в XML сообщение электронную подпись XADES/GOST.
|
||||
/// </summary>
|
||||
internal class GostSigningMessageInspector : IClientMessageInspector
|
||||
{
|
||||
private HcsClientConfig clientConfig;
|
||||
|
||||
public GostSigningMessageInspector(HcsClientConfig clientConfig)
|
||||
{
|
||||
this.clientConfig = clientConfig;
|
||||
}
|
||||
|
||||
public object BeforeSendRequest(ref Message request, IClientChannel channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
string filterHeader = " Фильтр отправки:";
|
||||
|
||||
PurgeDebuggerHeaders(ref request);
|
||||
var messageBody = GetMessageBodyString(ref request, Encoding.UTF8);
|
||||
|
||||
if (!messageBody.Contains(HcsConstants.SignedXmlElementId))
|
||||
{
|
||||
clientConfig.MaybeCaptureMessage(true, messageBody);
|
||||
}
|
||||
else
|
||||
{
|
||||
string certInfo = HcsX509Tools.ДатьСтрокуФИОСертификатаСДатойОкончания(clientConfig.Certificate);
|
||||
clientConfig.Log($"{filterHeader} подписываю сообщение ключем [{certInfo}]...");
|
||||
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
var service = new GostXadesBesService(clientConfig.CryptoProviderType);
|
||||
var signedXml = service.Sign(messageBody,
|
||||
HcsConstants.SignedXmlElementId,
|
||||
clientConfig.CertificateThumbprint,
|
||||
clientConfig.CertificatePassword);
|
||||
stopwatch.Stop();
|
||||
|
||||
clientConfig.Log($"{filterHeader} сообщение подписано за {stopwatch.ElapsedMilliseconds}мс.");
|
||||
|
||||
clientConfig.MaybeCaptureMessage(true, signedXml);
|
||||
|
||||
request = Message.CreateMessage(
|
||||
XmlReaderFromString(signedXml), int.MaxValue, request.Version);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string error = $"В {GetType().Name} произошло исключение";
|
||||
throw new Exception(error, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void AfterReceiveReply(ref Message reply, object correlationState)
|
||||
{
|
||||
clientConfig.MaybeCaptureMessage(false, reply.ToString());
|
||||
}
|
||||
|
||||
private void PurgeDebuggerHeaders(ref Message request)
|
||||
{
|
||||
int limit = request.Headers.Count;
|
||||
for (int i = 0; i < limit; ++i)
|
||||
{
|
||||
if (request.Headers[i].Name.Equals("VsDebuggerCausalityData"))
|
||||
{
|
||||
request.Headers.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string GetMessageBodyString(ref Message request, Encoding encoding)
|
||||
{
|
||||
MessageBuffer mb = request.CreateBufferedCopy(int.MaxValue);
|
||||
|
||||
request = mb.CreateMessage();
|
||||
|
||||
Stream s = new MemoryStream();
|
||||
XmlWriter xw = XmlWriter.Create(s);
|
||||
mb.CreateMessage().WriteMessage(xw);
|
||||
xw.Flush();
|
||||
s.Position = 0;
|
||||
|
||||
byte[] bXML = new byte[s.Length];
|
||||
s.Read(bXML, 0, (int)s.Length);
|
||||
|
||||
if (bXML[0] != (byte)'<')
|
||||
{
|
||||
return encoding.GetString(bXML, 3, bXML.Length - 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
return encoding.GetString(bXML, 0, bXML.Length);
|
||||
}
|
||||
}
|
||||
|
||||
XmlReader XmlReaderFromString(String xml)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var writer = new System.IO.StreamWriter(stream);
|
||||
writer.Write(xml);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
return XmlReader.Create(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
/// <summary>
|
||||
/// Состояние многостраничной выдачи для методов HCS выдыющих длинные списки.
|
||||
/// Списки выдаются порциями по 100 позиций и в каждой порции указано состояние
|
||||
/// многостраничной выдачи одним значением - это либо bool со значением true что
|
||||
/// означает что эта порция последняя IsLastPage, либо это строка содержащая
|
||||
/// guid объекта начала следующей порции - и этот guid надо указать в запросе
|
||||
/// чтобы получить следующую порцию.
|
||||
/// </summary>
|
||||
public class HcsPagedResultState
|
||||
{
|
||||
/// <summary>
|
||||
/// Состояние указыввает что это последняя страница
|
||||
/// </summary>
|
||||
public bool IsLastPage { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Состояние указывает что это не последняя страница и
|
||||
/// следующая страница начинается с NextGuid
|
||||
/// </summary>
|
||||
public Guid NextGuid { get; private set; }
|
||||
|
||||
private const string me = nameof(HcsPagedResultState);
|
||||
|
||||
public static readonly HcsPagedResultState IsLastPageResultState = new HcsPagedResultState(true);
|
||||
|
||||
/// <summary>
|
||||
/// Новый маркер состояния многостраничной выдачи метода HCS
|
||||
/// </summary>
|
||||
public HcsPagedResultState(object item)
|
||||
{
|
||||
if (item == null) throw new HcsException($"{me}.Item is null");
|
||||
|
||||
if (item is bool)
|
||||
{
|
||||
if ((bool)item == false) throw new HcsException($"{me}.IsLastPage is false");
|
||||
IsLastPage = true;
|
||||
}
|
||||
else if (item is string)
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLastPage = false;
|
||||
NextGuid = HcsUtil.ParseGuid((string)item);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new HcsException($"Failed to parse {me}.NextGuid value", e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new HcsException($"{me}.Item is of unrecognized type " + item.GetType().FullName);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{me}({nameof(IsLastPage)}={IsLastPage}" +
|
||||
(IsLastPage ? "" : $",{nameof(NextGuid)}={NextGuid}") + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,373 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Description;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
/// <summary>
|
||||
/// Базовый класс для методов HCS вызываемых удаленно
|
||||
/// </summary>
|
||||
public abstract class HcsRemoteCallMethod<T> where T : IHcsGetStateResult
|
||||
{
|
||||
public HcsClientConfig _config;
|
||||
protected CustomBinding _binding;
|
||||
|
||||
/// <summary>
|
||||
/// Для методов возвращающих мало данных можно попробовать сократить
|
||||
/// начальный период ожидания подготовки ответа
|
||||
/// </summary>
|
||||
public bool EnableMinimalResponseWaitDelay { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Для противодействия зависанию ожидания вводится предел ожидания в минутах
|
||||
/// для методов которые можно перезапустить заново с теми же параметрами.
|
||||
/// С периодом в 120 минут 09.2024 не успевали за ночь получить все данные.
|
||||
/// </summary>
|
||||
public int RestartTimeoutMinutes = 20;
|
||||
|
||||
/// <summary>
|
||||
/// Можно ли этот метод перезапускать в случае зависания ожидания или в случае сбоя на сервере?
|
||||
/// </summary>
|
||||
public bool CanBeRestarted { get; protected set; }
|
||||
|
||||
public HcsClientConfig ClientConfig => _config;
|
||||
|
||||
public HcsRemoteCallMethod(HcsClientConfig config)
|
||||
{
|
||||
this._config = config;
|
||||
ConfigureBinding();
|
||||
}
|
||||
|
||||
private void ConfigureBinding()
|
||||
{
|
||||
_binding = new CustomBinding();
|
||||
|
||||
// Эксперимент 19.07.2022 возникает ошибка WCF (TimeoutException 60 сек)
|
||||
_binding.ReceiveTimeout = TimeSpan.FromSeconds(180);
|
||||
_binding.OpenTimeout = TimeSpan.FromSeconds(180);
|
||||
_binding.SendTimeout = TimeSpan.FromSeconds(180);
|
||||
_binding.CloseTimeout = TimeSpan.FromSeconds(180);
|
||||
|
||||
_binding.Elements.Add(new TextMessageEncodingBindingElement
|
||||
{
|
||||
MessageVersion = MessageVersion.Soap11,
|
||||
WriteEncoding = Encoding.UTF8
|
||||
});
|
||||
|
||||
if (_config.UseTunnel)
|
||||
{
|
||||
if (System.Diagnostics.Process.GetProcessesByName("stunnel").Any() ? false : true)
|
||||
{
|
||||
throw new Exception("stunnel не запущен");
|
||||
}
|
||||
|
||||
_binding.Elements.Add(new HttpTransportBindingElement
|
||||
{
|
||||
AuthenticationScheme = (_config.IsPPAK ? System.Net.AuthenticationSchemes.Digest : System.Net.AuthenticationSchemes.Basic),
|
||||
MaxReceivedMessageSize = int.MaxValue,
|
||||
UseDefaultWebProxy = false
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_binding.Elements.Add(new HttpsTransportBindingElement
|
||||
{
|
||||
AuthenticationScheme = (_config.IsPPAK ? System.Net.AuthenticationSchemes.Digest : System.Net.AuthenticationSchemes.Basic),
|
||||
MaxReceivedMessageSize = int.MaxValue,
|
||||
UseDefaultWebProxy = false,
|
||||
RequireClientCertificate = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected EndpointAddress GetEndpointAddress(string endpointName)
|
||||
{
|
||||
return new EndpointAddress(_config.ComposeEndpointUri(endpointName));
|
||||
}
|
||||
|
||||
protected void ConfigureEndpointCredentials(
|
||||
ServiceEndpoint serviceEndpoint, ClientCredentials clientCredentials)
|
||||
{
|
||||
serviceEndpoint.EndpointBehaviors.Add(new GostSigningEndpointBehavior(_config));
|
||||
|
||||
if (!_config.IsPPAK)
|
||||
{
|
||||
clientCredentials.UserName.UserName = HcsConstants.UserAuth.Name;
|
||||
clientCredentials.UserName.Password = HcsConstants.UserAuth.Passwd;
|
||||
|
||||
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate (
|
||||
object sender, X509Certificate serverCertificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
bool letSystemValidateServerCertificate = false;
|
||||
if (!letSystemValidateServerCertificate)
|
||||
{
|
||||
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate (
|
||||
object sender, X509Certificate serverCertificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
// 06.06.2024 возникла ошибка "Это может быть связано с тем, что сертификат сервера
|
||||
// не настроен должным образом с помощью HTTP.SYS в случае HTTPS."
|
||||
// ГИС ЖКХ заменил сертификат сервера HTTPS и System.Net не смогла проверить новый.
|
||||
// В похожем случае необходимо включить "return true" чтобы любой сертификат
|
||||
// без проверки принимался (или найти файл lk_api_dom_gosuslugi_ru.cer нового сертификата
|
||||
// сервера ГИС ЖКХ API в разделе "Регламенты и инструкции" портала dom.gosuslugi.ru
|
||||
// и установить этот сертификат текущему пользователю).
|
||||
// Файл сертификата сервера API в разделе "Регламенты и инструкции" называется, например, так:
|
||||
// "Сертификат открытого ключа для организации защищенного TLS соединения с сервисами
|
||||
// легковесной интеграции (c 10.06.2024)".
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!_config.UseTunnel)
|
||||
{
|
||||
clientCredentials.ClientCertificate.SetCertificate(
|
||||
StoreLocation.CurrentUser,
|
||||
StoreName.My,
|
||||
X509FindType.FindByThumbprint,
|
||||
_config.CertificateThumbprint);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполнение одной попытки пооучить результат операции.
|
||||
/// Реализуется в производных классах.
|
||||
/// </summary>
|
||||
protected abstract Task<T> TryGetResultAsync(IHcsAck sourceAck, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Основной алгоритм ожидания ответа на асинхронный запрос.
|
||||
/// Из документации ГИС ЖКХ:
|
||||
/// Также рекомендуем придерживаться следующего алгоритма отправки запросов на получение статуса обработки пакета в случае использования асинхронных сервисов ГИС ЖКХ (в рамках одного MessageGUID):
|
||||
/// - первый запрос getState направлять не ранее чем через 10 секунд, после получения квитанции о приеме пакета с бизнес-данными от сервиса ГИС КЖХ;
|
||||
/// - в случае, если на первый запрос getSate получен результат с RequestState равным "1" или "2", то следующий запрос getState необходимо направлять не ранее чем через 60 секунд после отправки предыдущего запроса;
|
||||
/// - в случае, если на второй запрос getSate получен результат с RequestState равным "1" или "2", то следующий запрос getState необходимо направлять не ранее чем через 300 секунд после отправки предыдущего запроса;
|
||||
/// - в случае, если на третий запрос getSate получен результат с RequestState равным "1" или "2", то следующий запрос getState необходимо направлять не ранее чем через 900 секунд после отправки предыдущего запроса;
|
||||
/// - в случае, если на четвертый(и все последующие запросы) getState получен результат с RequestState равным "1" или "2", то следующий запрос getState необходимо направлять не ранее чем через 1800 секунд после отправки предыдущего запроса.
|
||||
/// </summary>
|
||||
protected async Task<T> WaitForResultAsync(
|
||||
IHcsAck ack, bool withInitialDelay, CancellationToken token)
|
||||
{
|
||||
var startTime = DateTime.Now;
|
||||
T result;
|
||||
for (int attempts = 1; ; attempts++)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
int delaySec = EnableMinimalResponseWaitDelay ? 2 : 5;
|
||||
if (attempts >= 2) delaySec = 5;
|
||||
if (attempts >= 3) delaySec = 10;
|
||||
if (attempts >= 5) delaySec = 20;
|
||||
if (attempts >= 7) delaySec = 40;
|
||||
if (attempts >= 9) delaySec = 80;
|
||||
if (attempts >= 12) delaySec = 300;
|
||||
|
||||
if (attempts > 1 || withInitialDelay)
|
||||
{
|
||||
var minutesElapsed = (int)(DateTime.Now - startTime).TotalMinutes;
|
||||
if (CanBeRestarted && minutesElapsed > RestartTimeoutMinutes)
|
||||
throw new HcsRestartTimeoutException($"Превышено ожидание в {RestartTimeoutMinutes} минут");
|
||||
|
||||
_config.Log($"Ожидаю {delaySec} сек. до попытки #{attempts}" +
|
||||
$" получить ответ (ожидание {minutesElapsed} минут(ы))...");
|
||||
|
||||
await Task.Delay(delaySec * 1000, token);
|
||||
}
|
||||
|
||||
_config.Log($"Запрашиваю ответ, попытка #{attempts} {ThreadIdText}...");
|
||||
result = await TryGetResultAsync(ack, token);
|
||||
if (result != null) break;
|
||||
}
|
||||
|
||||
_config.Log($"Ответ получен");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Исполнение повторяемой операции некоторое дпустимое число ошибок
|
||||
/// </summary>
|
||||
public async Task<T> RunRepeatableTaskAsync<T>(
|
||||
Func<Task<T>> taskFunc, Func<Exception, bool> canIgnoreFunc, int maxAttempts)
|
||||
{
|
||||
for (int attempts = 1; ; attempts++)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await taskFunc();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (canIgnoreFunc(e))
|
||||
{
|
||||
if (attempts < maxAttempts)
|
||||
{
|
||||
Log($"Игнорирую {attempts} из {maxAttempts} допустимых ошибок");
|
||||
continue;
|
||||
}
|
||||
throw new HcsException(
|
||||
$"Более {maxAttempts} продолжений после допустимых ошибок", e);
|
||||
}
|
||||
throw new HcsException("Вложенная ошибка", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Для запросов к серверу которые можно направлять несколько раз, разрешаем
|
||||
/// серверу аномально отказаться. Предполагается, что здесь мы игнорируем
|
||||
/// только жесткие отказы серверной инфраструктуры, которые указывают
|
||||
/// что запрос даже не был принят в обработку. Также все запросы на
|
||||
/// чтение можно повторять в случае их серверных системных ошибок.
|
||||
/// </summary>
|
||||
protected async Task<T> RunRepeatableTaskInsistentlyAsync<T>(
|
||||
Func<Task<T>> func, CancellationToken token)
|
||||
{
|
||||
int afterErrorDelaySec = 120;
|
||||
for (int attempt = 1; ; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await func();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string marker;
|
||||
if (CanIgnoreSuchException(e, out marker))
|
||||
{
|
||||
_config.Log($"Игнорирую ошибку #{attempt} типа [{marker}].");
|
||||
_config.Log($"Ожидаю {afterErrorDelaySec} сек. до повторения после ошибки...");
|
||||
await Task.Delay(afterErrorDelaySec * 1000, token);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e is HcsRestartTimeoutException)
|
||||
throw new HcsRestartTimeoutException("Наступило событие рестарта", e);
|
||||
|
||||
// Ошибки удаленной системы, которые нельзя игнорировать, дублируем для точности перехвата
|
||||
if (e is HcsRemoteException) throw HcsRemoteException.CreateNew(e as HcsRemoteException);
|
||||
throw new HcsException("Ошибка, которую нельзя игнорировать", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "[EXP001000] Произошла ошибка при передаче данных. Попробуйте осуществить передачу данных повторно",
|
||||
// Видимо, эту ошибку нельзя включать здесь. Предположительно это маркер DDOS защиты и если отправлять
|
||||
// точно такой же пакет повторно, то ошибка входит в бесконечный цикл - необходимо заново
|
||||
// собирать пакет с новыми кодами и временем и новой подписью. Такую ошибку надо обнаруживать
|
||||
// на более высоком уровне и заново отправлять запрос новым пакетом. (21.09.2022)
|
||||
private static string[] ignorableSystemErrorMarkers = {
|
||||
"Истекло время ожидания шлюза",
|
||||
"Базовое соединение закрыто: Соединение, которое должно было работать, было разорвано сервером",
|
||||
"Попробуйте осуществить передачу данных повторно", // Включено 18.10.2024, HouseManagement API сильно сбоит
|
||||
"(502) Недопустимый шлюз",
|
||||
"(503) Сервер не доступен"
|
||||
};
|
||||
|
||||
private bool CanIgnoreSuchException(Exception e, out string resultMarker)
|
||||
{
|
||||
foreach (var marker in ignorableSystemErrorMarkers)
|
||||
{
|
||||
var found = HcsUtil.EnumerateInnerExceptions(e).Find(
|
||||
x => x.Message != null && x.Message.Contains(marker));
|
||||
if (found != null)
|
||||
{
|
||||
resultMarker = marker;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
resultMarker = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверяет массив @items на содержание строго одного элемента типа @T и этот элемент
|
||||
/// </summary>
|
||||
protected T RequireSingleItem<T>(object[] items)
|
||||
{
|
||||
if (items == null)
|
||||
throw new HcsException($"Array of type {typeof(T)} must not be null");
|
||||
if (items.Length == 0)
|
||||
throw new HcsException($"Array of type {typeof(T)} must not be empty");
|
||||
if (items.Length > 1)
|
||||
throw new HcsException($"Array of type {typeof(T)} must contain 1 element, not {items.Length} of type {items[0].GetType().FullName}");
|
||||
return RequireType<T>(items[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверяет @obj на соответствие типу @T и возвращает преобразованный объект
|
||||
/// </summary>
|
||||
protected T RequireType<T>(object obj)
|
||||
{
|
||||
if (obj != null)
|
||||
{
|
||||
if (typeof(T) == obj.GetType()) return (T)obj;
|
||||
}
|
||||
|
||||
throw new HcsException(
|
||||
$"Require object of type {typeof(T)} but got" +
|
||||
(obj == null ? "null" : obj.GetType().FullName));
|
||||
}
|
||||
|
||||
internal static HcsException NewUnexpectedObjectException(object obj)
|
||||
{
|
||||
if (obj == null) return new HcsException("unexpected object is null");
|
||||
return new HcsException($"Unexpected object [{obj}] of type {obj.GetType().FullName}");
|
||||
}
|
||||
|
||||
public static string FormatGuid(Guid guid) => HcsUtil.FormatGuid(guid);
|
||||
|
||||
public static string FormatGuid(Guid? guid) => (guid != null) ? FormatGuid((Guid)guid) : null;
|
||||
|
||||
public static Guid ParseGuid(string guid) => HcsUtil.ParseGuid(guid);
|
||||
|
||||
public static Guid ParseGuid(object obj)
|
||||
{
|
||||
if (obj == null) throw new HcsException("Can't parse null as Guid");
|
||||
if (obj is Guid) return (Guid)obj;
|
||||
return ParseGuid(obj.ToString());
|
||||
}
|
||||
|
||||
public static Guid[] ParseGuidArray(string[] array)
|
||||
{
|
||||
if (array == null) return null;
|
||||
return array.ToList().Select(x => ParseGuid(x)).ToArray();
|
||||
}
|
||||
|
||||
public bool IsArrayEmpty(Array a) => (a == null || a.Length == 0);
|
||||
|
||||
public string MakeEmptyNull(string s)
|
||||
{
|
||||
return string.IsNullOrEmpty(s) ? null : s;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполняет @action на объекте @x если объект не пустой и приводится к типу @T
|
||||
/// </summary>
|
||||
public void CallOnType<T>(object x, Action<T> action) where T : class
|
||||
{
|
||||
var t = x as T;
|
||||
if (t != null) action(t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает индентификатор текущего исполняемого потока
|
||||
/// </summary>
|
||||
public int ThreadId => System.Environment.CurrentManagedThreadId;
|
||||
|
||||
public string ThreadIdText => $"(thread #{ThreadId})";
|
||||
|
||||
public void Log(string message) => ClientConfig.Log(message);
|
||||
}
|
||||
}
|
||||
@ -1,84 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
public static class HcsRequestHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Подготовка заголовка сообщения отправляемого в ГИС ЖКХ с обязательными атрибутами.
|
||||
/// Заголовки могут быть разного типа для разных типов сообщений но имена полей одинаковые.
|
||||
/// </summary>
|
||||
public static THeaderType CreateHeader<THeaderType>(HcsClientConfig config) where THeaderType : class
|
||||
{
|
||||
try
|
||||
{
|
||||
var instance = Activator.CreateInstance(typeof(THeaderType));
|
||||
|
||||
foreach (var prop in instance.GetType().GetProperties())
|
||||
{
|
||||
switch (prop.Name)
|
||||
{
|
||||
case "Item":
|
||||
prop.SetValue(instance, config.OrgPPAGUID);
|
||||
break;
|
||||
case "ItemElementName":
|
||||
prop.SetValue(instance, Enum.Parse(prop.PropertyType, "orgPPAGUID"));
|
||||
break;
|
||||
case "MessageGUID":
|
||||
prop.SetValue(instance, Guid.NewGuid().ToString());
|
||||
break;
|
||||
case "Date":
|
||||
prop.SetValue(instance, DateTime.Now);
|
||||
break;
|
||||
case "IsOperatorSignatureSpecified":
|
||||
if (config.Role == HcsOrganizationRoles.RC || config.Role == HcsOrganizationRoles.RSO)
|
||||
prop.SetValue(instance, true);
|
||||
break;
|
||||
case "IsOperatorSignature":
|
||||
if (config.Role == HcsOrganizationRoles.RC || config.Role == HcsOrganizationRoles.RSO)
|
||||
prop.SetValue(instance, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return instance as THeaderType;
|
||||
}
|
||||
catch (ArgumentNullException ex)
|
||||
{
|
||||
throw new ApplicationException($"При сборке заголовка запроса для ГИС произошла ошибка: {ex.Message}");
|
||||
}
|
||||
catch (SystemException exc)
|
||||
{
|
||||
throw new ApplicationException($"При сборке заголовка запроса для ГИС произошла не предвиденная ошибка {exc.GetBaseException().Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Для объекта запроса возвращает значение строки свойства version
|
||||
/// </summary>
|
||||
public static string GetRequestVersionString(object requestObject)
|
||||
{
|
||||
if (requestObject == null) return null;
|
||||
object versionHost = requestObject;
|
||||
|
||||
if (versionHost != null)
|
||||
{
|
||||
var versionProperty = versionHost.GetType().GetProperties().FirstOrDefault(x => x.Name == "version");
|
||||
if (versionProperty != null) return versionProperty.GetValue(versionHost) as string;
|
||||
}
|
||||
|
||||
foreach (var field in requestObject.GetType().GetFields())
|
||||
{
|
||||
versionHost = field.GetValue(requestObject);
|
||||
if (versionHost != null)
|
||||
{
|
||||
var versionProperty = versionHost.GetType().GetProperties().FirstOrDefault(x => x.Name == "version");
|
||||
if (versionProperty != null) return versionProperty.GetValue(versionHost) as string;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
/// <summary>
|
||||
/// Конфигурация ServicePointManager для работы с TLS. Скорее всего класс не нужен.
|
||||
/// </summary>
|
||||
public static class HcsServicePointConfig
|
||||
{
|
||||
public static void InitConfig()
|
||||
{
|
||||
// TODO: Проверить комментарий
|
||||
// Отключено 15.12.2023, работает и так
|
||||
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
|
||||
//ServicePointManager.CheckCertificateRevocationList = false;
|
||||
//ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
|
||||
//ServicePointManager.Expect100Continue = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
public interface IHcsAck
|
||||
{
|
||||
string MessageGUID { get; set; }
|
||||
string RequesterMessageGUID { get; set; }
|
||||
}
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
public interface IHcsFault
|
||||
{
|
||||
string ErrorCode { get; set; }
|
||||
string ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
/// <summary>
|
||||
/// Интерфейс-маркер
|
||||
/// </summary>
|
||||
public interface IHcsGetStateResult { }
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
public interface IHcsGetStateResultMany : IHcsGetStateResult
|
||||
{
|
||||
object[] Items { get; set; }
|
||||
}
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
public interface IHcsGetStateResultOne : IHcsGetStateResult
|
||||
{
|
||||
object Item { get; set; }
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.ClientApi.RemoteCaller
|
||||
{
|
||||
public interface IHcsHeaderType
|
||||
{
|
||||
string MessageGUID { get; set; }
|
||||
DateTime Date { get; set; }
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file is automatically generated by Visual Studio .Net. It is
|
||||
used to store generic object data source configuration information.
|
||||
Renaming the file extension or editing the content of this file may
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="AckRequest" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>Hcs.Service.Async.DebtRequests.v15_7_0_1.AckRequest, Connected Services.Service.Async.DebtRequests.v15_7_0_1.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file is automatically generated by Visual Studio .Net. It is
|
||||
used to store generic object data source configuration information.
|
||||
Renaming the file extension or editing the content of this file may
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="ResultHeader" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>Hcs.Service.Async.DebtRequests.v15_7_0_1.ResultHeader, Connected Services.Service.Async.DebtRequests.v15_7_0_1.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file is automatically generated by Visual Studio .Net. It is
|
||||
used to store generic object data source configuration information.
|
||||
Renaming the file extension or editing the content of this file may
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="exportDebtRequestsResponse" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>Hcs.Service.Async.DebtRequests.v15_7_0_1.exportDebtRequestsResponse, Connected Services.Service.Async.DebtRequests.v15_7_0_1.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file is automatically generated by Visual Studio .Net. It is
|
||||
used to store generic object data source configuration information.
|
||||
Renaming the file extension or editing the content of this file may
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="exportDebtSubrequestsResponse" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>Hcs.Service.Async.DebtRequests.v15_7_0_1.exportDebtSubrequestsResponse, Connected Services.Service.Async.DebtRequests.v15_7_0_1.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file is automatically generated by Visual Studio .Net. It is
|
||||
used to store generic object data source configuration information.
|
||||
Renaming the file extension or editing the content of this file may
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="getStateResponse" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>Hcs.Service.Async.DebtRequests.v15_7_0_1.getStateResponse, Connected Services.Service.Async.DebtRequests.v15_7_0_1.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file is automatically generated by Visual Studio .Net. It is
|
||||
used to store generic object data source configuration information.
|
||||
Renaming the file extension or editing the content of this file may
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="getStateResult" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>Hcs.Service.Async.DebtRequests.v15_7_0_1.getStateResult, Connected Services.Service.Async.DebtRequests.v15_7_0_1.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file is automatically generated by Visual Studio .Net. It is
|
||||
used to store generic object data source configuration information.
|
||||
Renaming the file extension or editing the content of this file may
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="importDebtRequestsResponse" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>Hcs.Service.Async.DebtRequests.v15_7_0_1.importDebtRequestsResponse, Connected Services.Service.Async.DebtRequests.v15_7_0_1.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file is automatically generated by Visual Studio .Net. It is
|
||||
used to store generic object data source configuration information.
|
||||
Renaming the file extension or editing the content of this file may
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="importResponsesResponse" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>Hcs.Service.Async.DebtRequests.v15_7_0_1.importResponsesResponse, Connected Services.Service.Async.DebtRequests.v15_7_0_1.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ReferenceGroup xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="b642da62-3cd9-49d7-b257-5a2a6b4baeb7" xmlns="urn:schemas-microsoft-com:xml-wcfservicemap">
|
||||
<ClientOptions>
|
||||
<GenerateAsynchronousMethods>false</GenerateAsynchronousMethods>
|
||||
<GenerateTaskBasedAsynchronousMethod>true</GenerateTaskBasedAsynchronousMethod>
|
||||
<EnableDataBinding>true</EnableDataBinding>
|
||||
<ExcludedTypes />
|
||||
<ImportXmlTypes>false</ImportXmlTypes>
|
||||
<GenerateInternalTypes>false</GenerateInternalTypes>
|
||||
<GenerateMessageContracts>false</GenerateMessageContracts>
|
||||
<NamespaceMappings />
|
||||
<CollectionMappings />
|
||||
<GenerateSerializableTypes>true</GenerateSerializableTypes>
|
||||
<Serializer>Auto</Serializer>
|
||||
<UseSerializerForFaults>true</UseSerializerForFaults>
|
||||
<ReferenceAllAssemblies>true</ReferenceAllAssemblies>
|
||||
<ReferencedAssemblies />
|
||||
<ReferencedDataContractTypes />
|
||||
<ServiceContractMappings />
|
||||
</ClientOptions>
|
||||
<MetadataSources>
|
||||
<MetadataSource Address="C:\Users\kshkulev\Documents\hcs\Hcs.Client\HcsWsdlSources\wsdl_xsd_v.15.7.0.1\debt-requests\hcs-debt-requests-service-async.wsdl" Protocol="file" SourceId="1" />
|
||||
</MetadataSources>
|
||||
<Metadata>
|
||||
<MetadataFile FileName="hcs-nsi-base.xsd" MetadataType="Schema" ID="22c761cf-4124-40b5-8db6-a7793d47c2f9" SourceId="1" SourceUrl="file:///C:/Users/kshkulev/Documents/hcs/Hcs.Client/HcsWsdlSources/wsdl_xsd_v.15.7.0.1/lib/hcs-nsi-base.xsd" />
|
||||
<MetadataFile FileName="hcs-debt-requests-service-async.wsdl" MetadataType="Wsdl" ID="0bfa5b2a-a70a-4704-8ca7-ef026e309351" SourceId="1" SourceUrl="file:///C:/Users/kshkulev/Documents/hcs/Hcs.Client/HcsWsdlSources/wsdl_xsd_v.15.7.0.1/debt-requests/hcs-debt-requests-service-async.wsdl" />
|
||||
<MetadataFile FileName="hcs-base.xsd" MetadataType="Schema" ID="82b9f743-c490-4475-b15f-e3356126b76f" SourceId="1" SourceUrl="file:///C:/Users/kshkulev/Documents/hcs/Hcs.Client/HcsWsdlSources/wsdl_xsd_v.15.7.0.1/lib/hcs-base.xsd" />
|
||||
<MetadataFile FileName="xmldsig-core-schema.xsd" MetadataType="Schema" ID="5beb2945-bc64-4c54-bffe-c7ac02e14e5f" SourceId="1" SourceUrl="file:///C:/Users/kshkulev/Documents/hcs/Hcs.Client/HcsWsdlSources/wsdl_xsd_v.15.7.0.1/lib/xmldsig-core-schema.xsd" />
|
||||
<MetadataFile FileName="hcs-debt-requests-types.xsd" MetadataType="Schema" ID="64971bf4-fd3d-4ee6-b3f0-7019e4185b38" SourceId="1" SourceUrl="file:///C:/Users/kshkulev/Documents/hcs/Hcs.Client/HcsWsdlSources/wsdl_xsd_v.15.7.0.1/debt-requests/hcs-debt-requests-types.xsd" />
|
||||
</Metadata>
|
||||
<Extensions>
|
||||
<ExtensionFile FileName="configuration91.svcinfo" Name="configuration91.svcinfo" />
|
||||
<ExtensionFile FileName="configuration.svcinfo" Name="configuration.svcinfo" />
|
||||
</Extensions>
|
||||
</ReferenceGroup>
|
||||
@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configurationSnapshot xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:schemas-microsoft-com:xml-wcfconfigurationsnapshot">
|
||||
<behaviors />
|
||||
<bindings>
|
||||
<binding digest="System.ServiceModel.Configuration.BasicHttpBindingElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089:<?xml version="1.0" encoding="utf-16"?><Data name="DebtRequestsAsyncBinding"><security mode="Transport" /></Data>" bindingType="basicHttpBinding" name="DebtRequestsAsyncBinding" />
|
||||
<binding digest="System.ServiceModel.Configuration.BasicHttpBindingElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089:<?xml version="1.0" encoding="utf-16"?><Data name="DebtRequestsAsyncBinding1" />" bindingType="basicHttpBinding" name="DebtRequestsAsyncBinding1" />
|
||||
</bindings>
|
||||
<endpoints>
|
||||
<endpoint normalizedDigest="<?xml version="1.0" encoding="utf-16"?><Data address="https://api.dom.gosuslugi.ru/ext-bus-debtreq-service/services/DebtRequestsAsync" binding="basicHttpBinding" bindingConfiguration="DebtRequestsAsyncBinding" contract="Service.Async.DebtRequests.v15_7_0_1.DebtRequestsAsyncPort" name="DebtRequestsAsyncPort" />" digest="<?xml version="1.0" encoding="utf-16"?><Data address="https://api.dom.gosuslugi.ru/ext-bus-debtreq-service/services/DebtRequestsAsync" binding="basicHttpBinding" bindingConfiguration="DebtRequestsAsyncBinding" contract="Service.Async.DebtRequests.v15_7_0_1.DebtRequestsAsyncPort" name="DebtRequestsAsyncPort" />" contractName="Service.Async.DebtRequests.v15_7_0_1.DebtRequestsAsyncPort" name="DebtRequestsAsyncPort" />
|
||||
</endpoints>
|
||||
</configurationSnapshot>
|
||||
@ -1,310 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<SavedWcfConfigurationInformation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="9.1" CheckSum="ULifDpf43Y229cZbpvxlIfRDy2V+0bJ32OpepzDCUtY=">
|
||||
<bindingConfigurations>
|
||||
<bindingConfiguration bindingType="basicHttpBinding" name="DebtRequestsAsyncBinding">
|
||||
<properties>
|
||||
<property path="/name" isComplexType="false" isExplicitlyDefined="true" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>DebtRequestsAsyncBinding</serializedValue>
|
||||
</property>
|
||||
<property path="/closeTimeout" isComplexType="false" isExplicitlyDefined="true" clrType="System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/openTimeout" isComplexType="false" isExplicitlyDefined="true" clrType="System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/receiveTimeout" isComplexType="false" isExplicitlyDefined="true" clrType="System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/sendTimeout" isComplexType="false" isExplicitlyDefined="true" clrType="System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/allowCookies" isComplexType="false" isExplicitlyDefined="true" clrType="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/bypassProxyOnLocal" isComplexType="false" isExplicitlyDefined="true" clrType="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/hostNameComparisonMode" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.HostNameComparisonMode, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>StrongWildcard</serializedValue>
|
||||
</property>
|
||||
<property path="/maxBufferPoolSize" isComplexType="false" isExplicitlyDefined="true" clrType="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/maxBufferSize" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>65536</serializedValue>
|
||||
</property>
|
||||
<property path="/maxReceivedMessageSize" isComplexType="false" isExplicitlyDefined="true" clrType="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/proxyAddress" isComplexType="false" isExplicitlyDefined="false" clrType="System.Uri, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/readerQuotas" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.XmlDictionaryReaderQuotasElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.XmlDictionaryReaderQuotasElement</serializedValue>
|
||||
</property>
|
||||
<property path="/readerQuotas/maxDepth" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>0</serializedValue>
|
||||
</property>
|
||||
<property path="/readerQuotas/maxStringContentLength" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>0</serializedValue>
|
||||
</property>
|
||||
<property path="/readerQuotas/maxArrayLength" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>0</serializedValue>
|
||||
</property>
|
||||
<property path="/readerQuotas/maxBytesPerRead" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>0</serializedValue>
|
||||
</property>
|
||||
<property path="/readerQuotas/maxNameTableCharCount" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>0</serializedValue>
|
||||
</property>
|
||||
<property path="/textEncoding" isComplexType="false" isExplicitlyDefined="false" clrType="System.Text.Encoding, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.Text.UTF8Encoding</serializedValue>
|
||||
</property>
|
||||
<property path="/transferMode" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.TransferMode, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>Buffered</serializedValue>
|
||||
</property>
|
||||
<property path="/useDefaultWebProxy" isComplexType="false" isExplicitlyDefined="true" clrType="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/messageEncoding" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.WSMessageEncoding, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>Text</serializedValue>
|
||||
</property>
|
||||
<property path="/security" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.BasicHttpSecurityElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.BasicHttpSecurityElement</serializedValue>
|
||||
</property>
|
||||
<property path="/security/mode" isComplexType="false" isExplicitlyDefined="true" clrType="System.ServiceModel.BasicHttpSecurityMode, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>Transport</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.HttpTransportSecurityElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.HttpTransportSecurityElement</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/clientCredentialType" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.HttpClientCredentialType, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>None</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/proxyCredentialType" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.HttpProxyCredentialType, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>None</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/extendedProtectionPolicy" isComplexType="true" isExplicitlyDefined="false" clrType="System.Security.Authentication.ExtendedProtection.Configuration.ExtendedProtectionPolicyElement, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.Security.Authentication.ExtendedProtection.Configuration.ExtendedProtectionPolicyElement</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/extendedProtectionPolicy/policyEnforcement" isComplexType="false" isExplicitlyDefined="false" clrType="System.Security.Authentication.ExtendedProtection.PolicyEnforcement, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>Never</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/extendedProtectionPolicy/protectionScenario" isComplexType="false" isExplicitlyDefined="false" clrType="System.Security.Authentication.ExtendedProtection.ProtectionScenario, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>TransportSelected</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/extendedProtectionPolicy/customServiceNames" isComplexType="true" isExplicitlyDefined="false" clrType="System.Security.Authentication.ExtendedProtection.Configuration.ServiceNameElementCollection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>(Коллекция)</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/realm" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/security/message" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.BasicHttpMessageSecurityElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.BasicHttpMessageSecurityElement</serializedValue>
|
||||
</property>
|
||||
<property path="/security/message/clientCredentialType" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.BasicHttpMessageCredentialType, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>UserName</serializedValue>
|
||||
</property>
|
||||
<property path="/security/message/algorithmSuite" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.Security.SecurityAlgorithmSuite, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>Default</serializedValue>
|
||||
</property>
|
||||
</properties>
|
||||
</bindingConfiguration>
|
||||
<bindingConfiguration bindingType="basicHttpBinding" name="DebtRequestsAsyncBinding1">
|
||||
<properties>
|
||||
<property path="/name" isComplexType="false" isExplicitlyDefined="true" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>DebtRequestsAsyncBinding1</serializedValue>
|
||||
</property>
|
||||
<property path="/closeTimeout" isComplexType="false" isExplicitlyDefined="true" clrType="System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/openTimeout" isComplexType="false" isExplicitlyDefined="true" clrType="System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/receiveTimeout" isComplexType="false" isExplicitlyDefined="true" clrType="System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/sendTimeout" isComplexType="false" isExplicitlyDefined="true" clrType="System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/allowCookies" isComplexType="false" isExplicitlyDefined="true" clrType="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/bypassProxyOnLocal" isComplexType="false" isExplicitlyDefined="true" clrType="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/hostNameComparisonMode" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.HostNameComparisonMode, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>StrongWildcard</serializedValue>
|
||||
</property>
|
||||
<property path="/maxBufferPoolSize" isComplexType="false" isExplicitlyDefined="true" clrType="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/maxBufferSize" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>65536</serializedValue>
|
||||
</property>
|
||||
<property path="/maxReceivedMessageSize" isComplexType="false" isExplicitlyDefined="true" clrType="System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/proxyAddress" isComplexType="false" isExplicitlyDefined="false" clrType="System.Uri, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/readerQuotas" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.XmlDictionaryReaderQuotasElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.XmlDictionaryReaderQuotasElement</serializedValue>
|
||||
</property>
|
||||
<property path="/readerQuotas/maxDepth" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>0</serializedValue>
|
||||
</property>
|
||||
<property path="/readerQuotas/maxStringContentLength" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>0</serializedValue>
|
||||
</property>
|
||||
<property path="/readerQuotas/maxArrayLength" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>0</serializedValue>
|
||||
</property>
|
||||
<property path="/readerQuotas/maxBytesPerRead" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>0</serializedValue>
|
||||
</property>
|
||||
<property path="/readerQuotas/maxNameTableCharCount" isComplexType="false" isExplicitlyDefined="false" clrType="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>0</serializedValue>
|
||||
</property>
|
||||
<property path="/textEncoding" isComplexType="false" isExplicitlyDefined="false" clrType="System.Text.Encoding, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.Text.UTF8Encoding</serializedValue>
|
||||
</property>
|
||||
<property path="/transferMode" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.TransferMode, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>Buffered</serializedValue>
|
||||
</property>
|
||||
<property path="/useDefaultWebProxy" isComplexType="false" isExplicitlyDefined="true" clrType="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/messageEncoding" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.WSMessageEncoding, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>Text</serializedValue>
|
||||
</property>
|
||||
<property path="/security" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.BasicHttpSecurityElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.BasicHttpSecurityElement</serializedValue>
|
||||
</property>
|
||||
<property path="/security/mode" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.BasicHttpSecurityMode, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>None</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.HttpTransportSecurityElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.HttpTransportSecurityElement</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/clientCredentialType" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.HttpClientCredentialType, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>None</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/proxyCredentialType" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.HttpProxyCredentialType, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>None</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/extendedProtectionPolicy" isComplexType="true" isExplicitlyDefined="false" clrType="System.Security.Authentication.ExtendedProtection.Configuration.ExtendedProtectionPolicyElement, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.Security.Authentication.ExtendedProtection.Configuration.ExtendedProtectionPolicyElement</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/extendedProtectionPolicy/policyEnforcement" isComplexType="false" isExplicitlyDefined="false" clrType="System.Security.Authentication.ExtendedProtection.PolicyEnforcement, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>Never</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/extendedProtectionPolicy/protectionScenario" isComplexType="false" isExplicitlyDefined="false" clrType="System.Security.Authentication.ExtendedProtection.ProtectionScenario, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>TransportSelected</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/extendedProtectionPolicy/customServiceNames" isComplexType="true" isExplicitlyDefined="false" clrType="System.Security.Authentication.ExtendedProtection.Configuration.ServiceNameElementCollection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>(Коллекция)</serializedValue>
|
||||
</property>
|
||||
<property path="/security/transport/realm" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/security/message" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.BasicHttpMessageSecurityElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.BasicHttpMessageSecurityElement</serializedValue>
|
||||
</property>
|
||||
<property path="/security/message/clientCredentialType" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.BasicHttpMessageCredentialType, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>UserName</serializedValue>
|
||||
</property>
|
||||
<property path="/security/message/algorithmSuite" isComplexType="false" isExplicitlyDefined="false" clrType="System.ServiceModel.Security.SecurityAlgorithmSuite, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>Default</serializedValue>
|
||||
</property>
|
||||
</properties>
|
||||
</bindingConfiguration>
|
||||
</bindingConfigurations>
|
||||
<endpoints>
|
||||
<endpoint name="DebtRequestsAsyncPort" contract="Service.Async.DebtRequests.v15_7_0_1.DebtRequestsAsyncPort" bindingType="basicHttpBinding" address="https://api.dom.gosuslugi.ru/ext-bus-debtreq-service/services/DebtRequestsAsync" bindingConfiguration="DebtRequestsAsyncBinding">
|
||||
<properties>
|
||||
<property path="/address" isComplexType="false" isExplicitlyDefined="true" clrType="System.Uri, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>https://api.dom.gosuslugi.ru/ext-bus-debtreq-service/services/DebtRequestsAsync</serializedValue>
|
||||
</property>
|
||||
<property path="/behaviorConfiguration" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/binding" isComplexType="false" isExplicitlyDefined="true" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>basicHttpBinding</serializedValue>
|
||||
</property>
|
||||
<property path="/bindingConfiguration" isComplexType="false" isExplicitlyDefined="true" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>DebtRequestsAsyncBinding</serializedValue>
|
||||
</property>
|
||||
<property path="/contract" isComplexType="false" isExplicitlyDefined="true" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>Service.Async.DebtRequests.v15_7_0_1.DebtRequestsAsyncPort</serializedValue>
|
||||
</property>
|
||||
<property path="/headers" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.AddressHeaderCollectionElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.AddressHeaderCollectionElement</serializedValue>
|
||||
</property>
|
||||
<property path="/headers/headers" isComplexType="false" isExplicitlyDefined="true" clrType="System.ServiceModel.Channels.AddressHeaderCollection, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue><Header /></serializedValue>
|
||||
</property>
|
||||
<property path="/identity" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.IdentityElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.IdentityElement</serializedValue>
|
||||
</property>
|
||||
<property path="/identity/userPrincipalName" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.UserPrincipalNameElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.UserPrincipalNameElement</serializedValue>
|
||||
</property>
|
||||
<property path="/identity/userPrincipalName/value" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/identity/servicePrincipalName" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.ServicePrincipalNameElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.ServicePrincipalNameElement</serializedValue>
|
||||
</property>
|
||||
<property path="/identity/servicePrincipalName/value" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/identity/dns" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.DnsElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.DnsElement</serializedValue>
|
||||
</property>
|
||||
<property path="/identity/dns/value" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/identity/rsa" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.RsaElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.RsaElement</serializedValue>
|
||||
</property>
|
||||
<property path="/identity/rsa/value" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/identity/certificate" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.CertificateElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.CertificateElement</serializedValue>
|
||||
</property>
|
||||
<property path="/identity/certificate/encodedValue" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/identity/certificateReference" isComplexType="true" isExplicitlyDefined="false" clrType="System.ServiceModel.Configuration.CertificateReferenceElement, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>System.ServiceModel.Configuration.CertificateReferenceElement</serializedValue>
|
||||
</property>
|
||||
<property path="/identity/certificateReference/storeName" isComplexType="false" isExplicitlyDefined="false" clrType="System.Security.Cryptography.X509Certificates.StoreName, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>My</serializedValue>
|
||||
</property>
|
||||
<property path="/identity/certificateReference/storeLocation" isComplexType="false" isExplicitlyDefined="false" clrType="System.Security.Cryptography.X509Certificates.StoreLocation, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>LocalMachine</serializedValue>
|
||||
</property>
|
||||
<property path="/identity/certificateReference/x509FindType" isComplexType="false" isExplicitlyDefined="false" clrType="System.Security.Cryptography.X509Certificates.X509FindType, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>FindBySubjectDistinguishedName</serializedValue>
|
||||
</property>
|
||||
<property path="/identity/certificateReference/findValue" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/identity/certificateReference/isChainIncluded" isComplexType="false" isExplicitlyDefined="false" clrType="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>False</serializedValue>
|
||||
</property>
|
||||
<property path="/name" isComplexType="false" isExplicitlyDefined="true" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue>DebtRequestsAsyncPort</serializedValue>
|
||||
</property>
|
||||
<property path="/kind" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
<property path="/endpointConfiguration" isComplexType="false" isExplicitlyDefined="false" clrType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<serializedValue />
|
||||
</property>
|
||||
</properties>
|
||||
</endpoint>
|
||||
</endpoints>
|
||||
</SavedWcfConfigurationInformation>
|
||||
@ -1,862 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:tns="http://dom.gosuslugi.ru/schema/integration/base/" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://dom.gosuslugi.ru/schema/integration/base/" version="13.1.10.2" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:import schemaLocation="xmldsig-core-schema.xsd" namespace="http://www.w3.org/2000/09/xmldsig#" />
|
||||
<xs:simpleType name="String2000Type">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Строка не более 2000 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="2000" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="String1500Type">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Строка не более 1500 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="1500" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="String300Type">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Строка не более 300 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="300" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="String255Type">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Скалярный тип. Строка не более 255 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255" />
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="String100Type">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Скалярный тип. Строка не более 100 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="100" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="String250Type">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Скалярный тип. Строка не более 250 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="250" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="String500Type">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Скалярный тип. Строка не более 500 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="500" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="String60Type">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Строка не более 60 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="60" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="LongTextType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Текстовое поле 2000</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="2000" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="NonEmptyStringType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Непустая строка</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1" />
|
||||
<xs:pattern value=".*[^\s].*" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="BaseType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Базовый тип бизнес-сообщения с подписью</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" ref="ds:Signature" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Id" />
|
||||
</xs:complexType>
|
||||
<xs:element name="RequestHeader">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Заголовок запроса</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:HeaderType">
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<xs:element name="SenderID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор поставщика данных</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="orgPPAGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор зарегистрированной организации</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Citizen">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Информация о физическом лице</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:choice>
|
||||
<xs:element name="CitizenPPAGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор физического лица, зарегистрированного в ГИС ЖКХ </xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="SNILS">
|
||||
<xs:annotation>
|
||||
<xs:documentation>СНИЛС</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="\d{11}" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="Document">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Документ, удостоверяющий личность</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="DocumentType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Вид документа, удостоверяющего личность (НСИ №95)</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Code">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код записи справочника</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="20" />
|
||||
<xs:pattern value="(A{0,1}\d{1,4}(\.)?)+" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="GUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор записи в соответствующем справочнике ГИС ЖКХ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="Name">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Значение</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="tns:LongTextType">
|
||||
<xs:maxLength value="1200" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="Series">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Серия документа</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1" />
|
||||
<xs:maxLength value="45" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="Number">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Номер документа</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1" />
|
||||
<xs:maxLength value="45" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
<xs:element minOccurs="0" fixed="true" name="IsOperatorSignature" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Используется подпись Оператора ИС</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="tns:ISCreator">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Сведения об иной ИС, с использованием которой была сформирована информация (589/944/,п.164). Только для запросов размещения информации.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="ISRequestHeader">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Заголовок запроса</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:HeaderType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="tns:ISCreator" />
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="ResultHeader">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Заголовок ответа</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:HeaderType" />
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="ResultType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Базовый тип ответа на запрос создания, редактирования, удаления </xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<xs:element name="TransportGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Транспортный идентификатор, определенный постащиком информации</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="UpdateGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор объекта в ГИС ЖКХ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
<xs:choice>
|
||||
<xs:sequence>
|
||||
<xs:element name="GUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор объекта в ГИС ЖКХ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="UpdateDate" type="xs:dateTime">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата модификации</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="UniqueNumber" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Уникальный номер </xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" name="CreateOrUpdateError" type="tns:ErrorMessageType" />
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="HeaderType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Базовый тип заголовка</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Date" type="xs:dateTime">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата отправки пакета</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="MessageGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор сообщения</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="Attachment">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Вложение</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="AttachmentGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор сохраненного вложения</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="AttachmentType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Вложение</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Name">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Наименование вложения</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="1024" />
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="Description">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Описание вложения</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="500" />
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element ref="tns:Attachment" />
|
||||
<xs:element minOccurs="0" name="AttachmentHASH">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Хэш-тег вложения по алгоритму ГОСТ в binhex.
|
||||
|
||||
Элемент обязателен в запросах импорта</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="AttachmentWODescriptionType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Вложение</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Name">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Наименование вложения</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="1024" />
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="Description">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Описание вложения</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="500" />
|
||||
<xs:minLength value="0" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element ref="tns:Attachment" />
|
||||
<xs:element minOccurs="0" name="AttachmentHASH">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Хэш-тег вложения по алгоритму ГОСТ в binhex</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="SignedAttachmentType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Базовый тип, описывающий вложение с открепленными (detached) подписями. В сервисах ГИС ЖКХ, использущих тип SignedAttachmentType, может быть наложено ограничение на максимальное количесво элементов в блоке Signature (см. контроль INT002039). </xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Attachment" type="tns:AttachmentType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Вложение</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element maxOccurs="unbounded" name="Signature" type="tns:AttachmentWODescriptionType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Открепленная (detached) подпись</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="Fault">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Элемент Fault (для параметра Fault в операции)</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:annotation>
|
||||
<xs:documentation>Базовый тип для fault-ошибки</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="ErrorCode" type="xs:string" />
|
||||
<xs:element minOccurs="0" name="ErrorMessage" type="xs:string" />
|
||||
<xs:element minOccurs="0" name="StackTrace" type="xs:string" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="ErrorMessage" type="tns:ErrorMessageType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Описание ошибок контролей или бизнес-процесса. Элемент не заполянется. Оставлен для совместимости
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:complexType name="ErrorMessageType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Базовый тип ошибки контроля или бизнес-процесса</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="ErrorCode" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код ошибки</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Description" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Описание ошибки</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="StackTrace" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>StackTrace в случае возникновения исключения</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:attribute name="version" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Версия элемента, начиная с которой поддерживается совместимость</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:element name="AckRequest">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Возврат квитанции приема сообщения</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Ack">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Квитанция</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="MessageGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор сообщения, присвоенный ГИС ЖКХ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="RequesterMessageGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор сообщения, присвоенный поставщиком</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="getStateRequest">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Запрос статуса отправленного сообщения</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="MessageGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор сообщения, присвоенный ГИС ЖКХ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="getRequestsStateRequest">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Запрос списка обработанных сообщений</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="10000" name="MessageGUIDList" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Массив идентификаторов сообщений, присвоенных ГИС ЖКХ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="getRequestsStateResult">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Ответ на запрос списка обработанных сообщений</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:BaseType">
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="10000" name="MessageGUIDList" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Список идентификаторов сообщений, присвоенный ГИС ЖКХ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="BaseAsyncResponseType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Базовый тип ответа на запрос статуса</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:BaseType">
|
||||
<xs:sequence>
|
||||
<xs:element name="RequestState" type="tns:AsyncRequestStateType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Статус обработки</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="MessageGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор сообщения, присвоенный ГИС ЖКХ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="CommonResultType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Результат выполнения C_UD</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="GUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор создаваемой/изменяемой сущности</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="1" name="TransportGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Транспортный идентификатор</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:choice>
|
||||
<xs:sequence>
|
||||
<xs:annotation>
|
||||
<xs:documentation>Операция выполнена успешно</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:element minOccurs="0" name="UniqueNumber" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Уникальный реестровый номер</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="UpdateDate" type="xs:dateTime">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата модификации</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" name="Error">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Описание ошибки</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:ErrorMessageType" />
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="AsyncRequestStateType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Статус обработки сообщения в асинхронном обмене (1- получено; 2 - в обработке; 3- обработано)</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:byte">
|
||||
<xs:enumeration value="1" />
|
||||
<xs:enumeration value="2" />
|
||||
<xs:enumeration value="3" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="TransportGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Транспортный идентификатор</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:simpleType name="GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>GUID-тип.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="ModificationDate" type="xs:dateTime">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата модификации объекта</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:simpleType name="YearType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Тип, описывающий год</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:short">
|
||||
<xs:minInclusive value="1600" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="MonthType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Тип, описывающий месяц</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:int">
|
||||
<xs:maxInclusive value="12" />
|
||||
<xs:minInclusive value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Month" type="tns:MonthType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Месяц</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Year">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Год</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:short">
|
||||
<xs:minInclusive value="1920" />
|
||||
<xs:maxInclusive value="2050" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:complexType name="YearMonth">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Определенный месяц определенного года</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element ref="tns:Year" />
|
||||
<xs:element ref="tns:Month" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Period">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Временной период (обе даты обязательны)</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="startDate" type="xs:date">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Начало периода</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="endDate" type="xs:date">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Конец периода</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PeriodOpen">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Открытый временной период (даты необязательны)</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="startDate" type="xs:date">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Начало периода</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="endDate" type="xs:date">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Конец периода</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="VolumeType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Тип объема</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:fractionDigits value="3" />
|
||||
<xs:minInclusive value="0" />
|
||||
<xs:totalDigits value="11" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="RegionType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Ссылка на субъект РФ (ФИАС)</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="code">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код региона (ФИАС)</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:length value="2" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="name">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Полное наименование</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="500" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="OKTMORefType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Ссылка на ОКТМО</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="code">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код по ОКТМО</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="11" />
|
||||
<xs:pattern value="\d{11}|\d{8}" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="name">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Полное наименование</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="500" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="OKEIType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="A{0,1}\d{3,4}" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="OKEI" type="tns:OKEIType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код ОКЕИ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="orgPPAGUID" type="tns:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор зарегистрированной организации</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:complexType name="DocumentPortalType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Базовый тип документа ОЧ</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Name">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Наименование документа</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1" />
|
||||
<xs:maxLength value="500" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="DocNumber">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Номер документа</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1" />
|
||||
<xs:maxLength value="500" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="ApproveDate" type="xs:date">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата принятия документа органом власти</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Attachment" type="tns:AttachmentType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Вложение</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="ISCreator">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Сведения об иной ИС, с использованием которой была сформирована информация (589/944/,п.164)</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="ISName" type="tns:String255Type">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Наименование ИС</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="ISOperatorName" type="tns:String255Type">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Наименование Оператора ИС</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:simpleType name="OKTMOType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код по ОКТМО</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="11" />
|
||||
<xs:pattern value="\d{11}|\d{8}" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="OKTMOImportType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код по ОКТМО</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="8" />
|
||||
<xs:pattern value="\d{8}" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
@ -1,163 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<wsdl:definitions xmlns:base="http://dom.gosuslugi.ru/schema/integration/base/" xmlns:ns="http://www.w3.org/2000/09/xmldsig#" xmlns:drs="http://dom.gosuslugi.ru/schema/integration/drs/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://dom.gosuslugi.ru/schema/integration/nsi-base/" xmlns:tns="http://dom.gosuslugi.ru/schema/integration/drs-service-async" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://dom.gosuslugi.ru/schema/integration/drs-service-async" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
|
||||
<wsdl:types>
|
||||
<xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified" version="13.1.2.6">
|
||||
<xs:import schemaLocation="hcs-debt-requests-types.xsd" namespace="http://dom.gosuslugi.ru/schema/integration/drs/" />
|
||||
<xs:import schemaLocation="../lib/hcs-base.xsd" namespace="http://dom.gosuslugi.ru/schema/integration/base/" />
|
||||
</xs:schema>
|
||||
</wsdl:types>
|
||||
<wsdl:message name="RequestHeader">
|
||||
<wsdl:part name="Header" element="base:RequestHeader" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="ResultHeader">
|
||||
<wsdl:part name="Header" element="base:ResultHeader" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="importDRsRequest">
|
||||
<wsdl:part name="importDRsRequest" element="drs:importDRsRequest" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="importDRsResult">
|
||||
<wsdl:part name="importDRsResult" element="base:AckRequest" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="exportDRsRequest">
|
||||
<wsdl:part name="exportDRsRequest" element="drs:exportDRsRequest" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="exportDRsResult">
|
||||
<wsdl:part name="exportDRsResult" element="base:AckRequest" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="importDSRsRequest">
|
||||
<wsdl:part name="importDSRsRequest" element="drs:importDSRResponsesRequest" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="importDSRsResult">
|
||||
<wsdl:part name="importDSRsResult" element="base:AckRequest" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="exportDSRsRequest">
|
||||
<wsdl:part name="exportDSRsRequest" element="drs:exportDSRsRequest" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="exportDSRsResult">
|
||||
<wsdl:part name="exportDSRsResult" element="base:AckRequest" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="getStateRequest">
|
||||
<wsdl:part name="getStateRequest" element="base:getStateRequest" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="getStateResult">
|
||||
<wsdl:part name="getStateResult" element="drs:getStateResult" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="Fault">
|
||||
<wsdl:part name="Fault" element="base:Fault" />
|
||||
</wsdl:message>
|
||||
<wsdl:portType name="DebtRequestsAsyncPort">
|
||||
<wsdl:operation name="importDebtRequests">
|
||||
<wsdl:documentation>Загрузка в ГИС ЖКХ запросов о наличии задолженности за ЖКУ (организациями, направляющими запросы)</wsdl:documentation>
|
||||
<wsdl:input message="tns:importDRsRequest" />
|
||||
<wsdl:output message="tns:importDRsResult" />
|
||||
<wsdl:fault name="InvalidRequest" message="tns:Fault" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="exportDebtSubrequests">
|
||||
<wsdl:documentation>Выгрузка из ГИС ЖКХ подзапросов о наличии задолженности за ЖКУ (организациями, предоставляющими ЖКУ)</wsdl:documentation>
|
||||
<wsdl:input message="tns:exportDSRsRequest" />
|
||||
<wsdl:output message="tns:exportDSRsResult" />
|
||||
<wsdl:fault name="InvalidRequest" message="tns:Fault" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="importResponses">
|
||||
<wsdl:documentation>Загрузка в ГИС ЖКХ ответов на запросы о наличии задолженности за ЖКУ (организациями, предоставляющими ЖКУ)</wsdl:documentation>
|
||||
<wsdl:input message="tns:importDSRsRequest" />
|
||||
<wsdl:output message="tns:importDSRsResult" />
|
||||
<wsdl:fault name="InvalidRequest" message="tns:Fault" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="exportDebtRequests">
|
||||
<wsdl:documentation>Выгрузка из ГИС ЖКХ запросов о наличии задолженности за ЖКУ (организациями, направляющими запросы)</wsdl:documentation>
|
||||
<wsdl:input message="tns:exportDRsRequest" />
|
||||
<wsdl:output message="tns:exportDRsResult" />
|
||||
<wsdl:fault name="InvalidRequest" message="tns:Fault" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="getState">
|
||||
<wsdl:documentation>Результат обработки асинхронного вызова</wsdl:documentation>
|
||||
<wsdl:input message="tns:getStateRequest" />
|
||||
<wsdl:output message="tns:getStateResult" />
|
||||
<wsdl:fault name="InvalidRequest" message="tns:Fault" />
|
||||
</wsdl:operation>
|
||||
</wsdl:portType>
|
||||
<wsdl:binding name="DebtRequestsAsyncBinding" type="tns:DebtRequestsAsyncPort">
|
||||
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
|
||||
<wsdl:operation name="importDebtRequests">
|
||||
<wsdl:documentation>Загрузка в ГИС ЖКХ запросов о наличии задолженности за ЖКУ (организациями, направляющими запросы)</wsdl:documentation>
|
||||
<soap:operation soapAction="urn:importDebtRequests" />
|
||||
<wsdl:input>
|
||||
<soap:body use="literal" />
|
||||
<soap:header message="tns:RequestHeader" part="Header" use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" />
|
||||
<soap:header message="tns:ResultHeader" part="Header" use="literal" />
|
||||
</wsdl:output>
|
||||
<wsdl:fault name="InvalidRequest">
|
||||
<soap:fault use="literal" name="InvalidRequest" namespace="" />
|
||||
</wsdl:fault>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="exportDebtSubrequests">
|
||||
<wsdl:documentation>Выгрузка из ГИС ЖКХ подзапросов о наличии задолженности за ЖКУ (организациями, предоставляющими ЖКУ)</wsdl:documentation>
|
||||
<soap:operation soapAction="urn:exportDebtSubrequests" />
|
||||
<wsdl:input>
|
||||
<soap:body use="literal" />
|
||||
<soap:header message="tns:RequestHeader" part="Header" use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" />
|
||||
<soap:header message="tns:ResultHeader" part="Header" use="literal" />
|
||||
</wsdl:output>
|
||||
<wsdl:fault name="InvalidRequest">
|
||||
<soap:fault use="literal" name="InvalidRequest" namespace="" />
|
||||
</wsdl:fault>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="importResponses">
|
||||
<wsdl:documentation>Загрузка в ГИС ЖКХ ответов на запросы о наличии задолженности за ЖКУ (организациями, предоставляющими ЖКУ)</wsdl:documentation>
|
||||
<soap:operation soapAction="urn:importResponses" />
|
||||
<wsdl:input>
|
||||
<soap:body use="literal" />
|
||||
<soap:header message="tns:RequestHeader" part="Header" use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" />
|
||||
<soap:header message="tns:ResultHeader" part="Header" use="literal" />
|
||||
</wsdl:output>
|
||||
<wsdl:fault name="InvalidRequest">
|
||||
<soap:fault use="literal" name="InvalidRequest" namespace="" />
|
||||
</wsdl:fault>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="exportDebtRequests">
|
||||
<wsdl:documentation>Выгрузка из ГИС ЖКХ запросов о наличии задолженности за ЖКУ (организациями, направляющими запросы)</wsdl:documentation>
|
||||
<soap:operation soapAction="urn:exportDebtRequests" />
|
||||
<wsdl:input>
|
||||
<soap:body use="literal" />
|
||||
<soap:header message="tns:RequestHeader" part="Header" use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" />
|
||||
<soap:header message="tns:ResultHeader" part="Header" use="literal" />
|
||||
</wsdl:output>
|
||||
<wsdl:fault name="InvalidRequest">
|
||||
<soap:fault use="literal" name="InvalidRequest" namespace="" />
|
||||
</wsdl:fault>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="getState">
|
||||
<soap:operation soapAction="urn:getState" />
|
||||
<wsdl:input>
|
||||
<soap:body use="literal" />
|
||||
<soap:header message="tns:RequestHeader" part="Header" use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" />
|
||||
<soap:header message="tns:ResultHeader" part="Header" use="literal" />
|
||||
</wsdl:output>
|
||||
<wsdl:fault name="InvalidRequest">
|
||||
<soap:fault use="literal" name="InvalidRequest" namespace="" />
|
||||
</wsdl:fault>
|
||||
</wsdl:operation>
|
||||
</wsdl:binding>
|
||||
<wsdl:service name="DebtRequestsServiceAsync">
|
||||
<wsdl:documentation>Сервис управления запросами о наличии задолженности за ЖКУ</wsdl:documentation>
|
||||
<wsdl:port name="DebtRequestsAsyncPort" binding="tns:DebtRequestsAsyncBinding">
|
||||
<soap:address location="https://api.dom.gosuslugi.ru/ext-bus-debtreq-service/services/DebtRequestsAsync" />
|
||||
</wsdl:port>
|
||||
</wsdl:service>
|
||||
</wsdl:definitions>
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,427 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:base="http://dom.gosuslugi.ru/schema/integration/base/" xmlns:tns="http://dom.gosuslugi.ru/schema/integration/nsi-base/" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://dom.gosuslugi.ru/schema/integration/nsi-base/" version="11.2.1.1" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:import schemaLocation="hcs-base.xsd" namespace="http://dom.gosuslugi.ru/schema/integration/base/" />
|
||||
<xs:simpleType name="nsiCodeType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="20" />
|
||||
<xs:pattern value="(A{0,1}\d{1,4}(\.)?)+" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="nsiRef">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Ссылка на справочник</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Code" type="tns:nsiCodeType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код записи справочника</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="GUID" type="base:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификатор записи в соответствующем справочнике ГИС ЖКХ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" name="Name">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Значение</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="base:LongTextType">
|
||||
<xs:maxLength value="1200" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="NsiItemNameType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Скалярный тип. Наименование справочника. Строка не более 200 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="2500" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="NsiItemRegistryNumberType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Скалярный тип. Реестровый номер справочника. Код не более 10 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:positiveInteger">
|
||||
<xs:totalDigits value="10" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="NsiItemInfoType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование, дата и время последнего изменения справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="RegistryNumber" type="tns:NsiItemRegistryNumberType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Реестровый номер справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Name" type="tns:NsiItemNameType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Наименование справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Modified" type="xs:dateTime">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата и время последнего изменения справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiListType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Перечень справочников с датой последнего изменения каждого из них.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Created" type="xs:dateTime">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата и время формирования перечня справочников.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element maxOccurs="unbounded" name="NsiItemInfo" type="tns:NsiItemInfoType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Наименование, дата и время последнего изменения справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="tns:ListGroup" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiItemType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Данные справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="NsiItemRegistryNumber" type="tns:NsiItemRegistryNumberType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Реестровый номер справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Created" type="xs:dateTime">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата и время формирования данных справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element maxOccurs="unbounded" name="NsiElement" type="tns:NsiElementType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Элемент справочника верхнего уровня.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Элемент справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Code" type="tns:nsiCodeType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код элемента справочника, уникальный в пределах справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="GUID" type="base:GUIDType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Глобально-уникальный идентификатор элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:choice>
|
||||
<xs:element name="Modified" type="xs:dateTime">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата и время последнего изменения элемента справочника (в том числе создания).</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:sequence>
|
||||
<xs:element name="StartDate" type="xs:dateTime">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата начала действия значения</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="EndDate" type="xs:dateTime">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дата окончания действия значения</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:element name="IsActual" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Признак актуальности элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" name="NsiElementField" type="tns:NsiElementFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Наименование и значение поля для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" name="ChildElement" type="tns:NsiElementType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Дочерний элемент.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementFieldType" abstract="true">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля для элемента справочника. Абстрактный тип.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Name" type="tns:FieldNameType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Наименование поля элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementStringFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля типа "Строка" для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="Value" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Значение поля элемента справочника типа "Строка".</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementBooleanFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля типа "Да/Нет" для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="Value" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Значение поля элемента справочника типа "Да/Нет".</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementFloatFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля типа "Вещественное" для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="Value" type="xs:float">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Значение поля элемента справочника типа "Вещественное".</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementDateFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля типа "Дата" для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="Value" type="xs:date">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Значение поля элемента справочника типа "Дата".</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementIntegerFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля типа "Целое число" для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="Value" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Значение поля элемента справочника типа "Целое число".</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementEnumFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля типа "Перечислимый" для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" name="Position">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Запись элемента справочника типа "Перечислимый".</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="GUID">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код поля элемента справочника типа "Перечислимый".</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Value" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Значение поля элемента справочника типа "Перечислимый".</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementNsiFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля типа "Ссылка на справочник" для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="NsiRef">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Ссылка на справочник.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="NsiItemRegistryNumber" type="tns:NsiItemRegistryNumberType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Реестровый номер справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="tns:ListGroup" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementNsiRefFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля типа "Ссылка на элемент внутреннего справочника" для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="NsiRef">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Ссылка на элемент внутреннего справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="NsiItemRegistryNumber" type="tns:NsiItemRegistryNumberType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Реестровый номер справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Ref" type="tns:nsiRef">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Ссылка на элемент справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementOkeiRefFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля типа "Ссылка на элемент справочника ОКЕИ" для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="Code" type="tns:nsiCodeType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Код единицы измерения по справочнику ОКЕИ.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementFiasAddressRefFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля типа "Ссылка на элемент справочника ФИАС" для элемента справочника.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" name="NsiRef">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Ссылка на элемент справочника ФИАС.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Guid" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Идентификационный код позиции в справочнике ФИАС.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="aoGuid" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Глобально-уникальный идентификатор адресного объекта в справочнике ФИАС.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NsiElementAttachmentFieldType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Составной тип. Наименование и значение поля "Вложение"</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexContent mixed="false">
|
||||
<xs:extension base="tns:NsiElementFieldType">
|
||||
<xs:sequence>
|
||||
<xs:element name="Document" type="base:AttachmentType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Документ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="FieldNameType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Скалярный тип. Наименование поля элемента справочника. Строка не более 200 символов.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="200" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="ListGroup">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Группа справочника:
|
||||
NSI - (по умолчанию) общесистемный
|
||||
NSIRAO - ОЖФ</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="NSI" />
|
||||
<xs:enumeration value="NSIRAO" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
@ -1,213 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<schema xmlns:ds="http://www.w3.org/2000/09/xmldsig#" elementFormDefault="qualified" targetNamespace="http://www.w3.org/2000/09/xmldsig#" version="0.1" xmlns="http://www.w3.org/2001/XMLSchema">
|
||||
<simpleType name="CryptoBinary">
|
||||
<restriction base="base64Binary" />
|
||||
</simpleType>
|
||||
<element name="Signature" type="ds:SignatureType" />
|
||||
<complexType name="SignatureType">
|
||||
<sequence>
|
||||
<element ref="ds:SignedInfo" />
|
||||
<element ref="ds:SignatureValue" />
|
||||
<element minOccurs="0" ref="ds:KeyInfo" />
|
||||
<element minOccurs="0" maxOccurs="unbounded" ref="ds:Object" />
|
||||
</sequence>
|
||||
<attribute name="Id" type="ID" use="optional" />
|
||||
</complexType>
|
||||
<element name="SignatureValue" type="ds:SignatureValueType" />
|
||||
<complexType name="SignatureValueType">
|
||||
<simpleContent>
|
||||
<extension base="base64Binary">
|
||||
<attribute name="Id" type="ID" use="optional" />
|
||||
</extension>
|
||||
</simpleContent>
|
||||
</complexType>
|
||||
<element name="SignedInfo" type="ds:SignedInfoType" />
|
||||
<complexType name="SignedInfoType">
|
||||
<sequence>
|
||||
<element ref="ds:CanonicalizationMethod" />
|
||||
<element ref="ds:SignatureMethod" />
|
||||
<element maxOccurs="unbounded" ref="ds:Reference" />
|
||||
</sequence>
|
||||
<attribute name="Id" type="ID" use="optional" />
|
||||
</complexType>
|
||||
<element name="CanonicalizationMethod" type="ds:CanonicalizationMethodType" />
|
||||
<complexType name="CanonicalizationMethodType" mixed="true">
|
||||
<sequence>
|
||||
<any minOccurs="0" maxOccurs="unbounded" namespace="##any" />
|
||||
</sequence>
|
||||
<attribute name="Algorithm" type="anyURI" use="required" />
|
||||
</complexType>
|
||||
<element name="SignatureMethod" type="ds:SignatureMethodType" />
|
||||
<complexType name="SignatureMethodType" mixed="true">
|
||||
<sequence>
|
||||
<element minOccurs="0" name="HMACOutputLength" type="ds:HMACOutputLengthType" />
|
||||
<any minOccurs="0" maxOccurs="unbounded" namespace="##other" />
|
||||
</sequence>
|
||||
<attribute name="Algorithm" type="anyURI" use="required" />
|
||||
</complexType>
|
||||
<element name="Reference" type="ds:ReferenceType" />
|
||||
<complexType name="ReferenceType">
|
||||
<sequence>
|
||||
<element minOccurs="0" ref="ds:Transforms" />
|
||||
<element ref="ds:DigestMethod" />
|
||||
<element ref="ds:DigestValue" />
|
||||
</sequence>
|
||||
<attribute name="Id" type="ID" use="optional" />
|
||||
<attribute name="URI" type="anyURI" use="optional" />
|
||||
<attribute name="Type" type="anyURI" use="optional" />
|
||||
</complexType>
|
||||
<element name="Transforms" type="ds:TransformsType" />
|
||||
<complexType name="TransformsType">
|
||||
<sequence>
|
||||
<element maxOccurs="unbounded" ref="ds:Transform" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<element name="Transform" type="ds:TransformType" />
|
||||
<complexType name="TransformType" mixed="true">
|
||||
<choice minOccurs="0" maxOccurs="unbounded">
|
||||
<any namespace="##other" processContents="lax" />
|
||||
<element name="XPath" type="string" />
|
||||
</choice>
|
||||
<attribute name="Algorithm" type="anyURI" use="required" />
|
||||
</complexType>
|
||||
<element name="DigestMethod" type="ds:DigestMethodType" />
|
||||
<complexType name="DigestMethodType" mixed="true">
|
||||
<sequence>
|
||||
<any minOccurs="0" maxOccurs="unbounded" namespace="##other" processContents="lax" />
|
||||
</sequence>
|
||||
<attribute name="Algorithm" type="anyURI" use="required" />
|
||||
</complexType>
|
||||
<element name="DigestValue" type="ds:DigestValueType" />
|
||||
<simpleType name="DigestValueType">
|
||||
<restriction base="base64Binary" />
|
||||
</simpleType>
|
||||
<element name="KeyInfo" type="ds:KeyInfoType" />
|
||||
<complexType name="KeyInfoType" mixed="true">
|
||||
<choice maxOccurs="unbounded">
|
||||
<element ref="ds:KeyName" />
|
||||
<element ref="ds:KeyValue" />
|
||||
<element ref="ds:RetrievalMethod" />
|
||||
<element ref="ds:X509Data" />
|
||||
<element ref="ds:PGPData" />
|
||||
<element ref="ds:SPKIData" />
|
||||
<element ref="ds:MgmtData" />
|
||||
<any namespace="##other" processContents="lax" />
|
||||
</choice>
|
||||
<attribute name="Id" type="ID" use="optional" />
|
||||
</complexType>
|
||||
<element name="KeyName" type="string" />
|
||||
<element name="MgmtData" type="string" />
|
||||
<element name="KeyValue" type="ds:KeyValueType" />
|
||||
<complexType name="KeyValueType" mixed="true">
|
||||
<choice>
|
||||
<element ref="ds:DSAKeyValue" />
|
||||
<element ref="ds:RSAKeyValue" />
|
||||
<any namespace="##other" processContents="lax" />
|
||||
</choice>
|
||||
</complexType>
|
||||
<element name="RetrievalMethod" type="ds:RetrievalMethodType" />
|
||||
<complexType name="RetrievalMethodType">
|
||||
<sequence>
|
||||
<element minOccurs="0" ref="ds:Transforms" />
|
||||
</sequence>
|
||||
<attribute name="URI" type="anyURI" />
|
||||
<attribute name="Type" type="anyURI" use="optional" />
|
||||
</complexType>
|
||||
<element name="X509Data" type="ds:X509DataType" />
|
||||
<complexType name="X509DataType">
|
||||
<sequence maxOccurs="unbounded">
|
||||
<choice>
|
||||
<element name="X509IssuerSerial" type="ds:X509IssuerSerialType" />
|
||||
<element name="X509SKI" type="base64Binary" />
|
||||
<element name="X509SubjectName" type="string" />
|
||||
<element name="X509Certificate" type="base64Binary" />
|
||||
<element name="X509CRL" type="base64Binary" />
|
||||
<any namespace="##other" processContents="lax" />
|
||||
</choice>
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="X509IssuerSerialType">
|
||||
<sequence>
|
||||
<element name="X509IssuerName" type="string" />
|
||||
<element name="X509SerialNumber" type="integer" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<element name="PGPData" type="ds:PGPDataType" />
|
||||
<complexType name="PGPDataType">
|
||||
<choice>
|
||||
<sequence>
|
||||
<element name="PGPKeyID" type="base64Binary" />
|
||||
<element minOccurs="0" name="PGPKeyPacket" type="base64Binary" />
|
||||
<any minOccurs="0" maxOccurs="unbounded" namespace="##other" processContents="lax" />
|
||||
</sequence>
|
||||
<sequence>
|
||||
<element name="PGPKeyPacket" type="base64Binary" />
|
||||
<any minOccurs="0" maxOccurs="unbounded" namespace="##other" processContents="lax" />
|
||||
</sequence>
|
||||
</choice>
|
||||
</complexType>
|
||||
<element name="SPKIData" type="ds:SPKIDataType" />
|
||||
<complexType name="SPKIDataType">
|
||||
<sequence maxOccurs="unbounded">
|
||||
<element name="SPKISexp" type="base64Binary" />
|
||||
<any minOccurs="0" namespace="##other" processContents="lax" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<element name="Object" type="ds:ObjectType" />
|
||||
<complexType name="ObjectType" mixed="true">
|
||||
<sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<any namespace="##any" processContents="lax" />
|
||||
</sequence>
|
||||
<attribute name="Id" type="ID" use="optional" />
|
||||
<attribute name="MimeType" type="string" use="optional" />
|
||||
<attribute name="Encoding" type="anyURI" use="optional" />
|
||||
</complexType>
|
||||
<element name="Manifest" type="ds:ManifestType" />
|
||||
<complexType name="ManifestType">
|
||||
<sequence>
|
||||
<element maxOccurs="unbounded" ref="ds:Reference" />
|
||||
</sequence>
|
||||
<attribute name="Id" type="ID" use="optional" />
|
||||
</complexType>
|
||||
<element name="SignatureProperties" type="ds:SignaturePropertiesType" />
|
||||
<complexType name="SignaturePropertiesType">
|
||||
<sequence>
|
||||
<element maxOccurs="unbounded" ref="ds:SignatureProperty" />
|
||||
</sequence>
|
||||
<attribute name="Id" type="ID" use="optional" />
|
||||
</complexType>
|
||||
<element name="SignatureProperty" type="ds:SignaturePropertyType" />
|
||||
<complexType name="SignaturePropertyType" mixed="true">
|
||||
<choice maxOccurs="unbounded">
|
||||
<any namespace="##other" processContents="lax" />
|
||||
</choice>
|
||||
<attribute name="Target" type="anyURI" use="required" />
|
||||
<attribute name="Id" type="ID" use="optional" />
|
||||
</complexType>
|
||||
<simpleType name="HMACOutputLengthType">
|
||||
<restriction base="integer" />
|
||||
</simpleType>
|
||||
<element name="DSAKeyValue" type="ds:DSAKeyValueType" />
|
||||
<complexType name="DSAKeyValueType">
|
||||
<sequence>
|
||||
<sequence minOccurs="0">
|
||||
<element name="P" type="ds:CryptoBinary" />
|
||||
<element name="Q" type="ds:CryptoBinary" />
|
||||
</sequence>
|
||||
<element minOccurs="0" name="G" type="ds:CryptoBinary" />
|
||||
<element name="Y" type="ds:CryptoBinary" />
|
||||
<element minOccurs="0" name="J" type="ds:CryptoBinary" />
|
||||
<sequence minOccurs="0">
|
||||
<element name="Seed" type="ds:CryptoBinary" />
|
||||
<element name="PgenCounter" type="ds:CryptoBinary" />
|
||||
</sequence>
|
||||
</sequence>
|
||||
</complexType>
|
||||
<element name="RSAKeyValue" type="ds:RSAKeyValueType" />
|
||||
<complexType name="RSAKeyValueType">
|
||||
<sequence>
|
||||
<element name="Modulus" type="ds:CryptoBinary" />
|
||||
<element name="Exponent" type="ds:CryptoBinary" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
</schema>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file is automatically generated by Visual Studio .Net. It is
|
||||
used to store generic object data source configuration information.
|
||||
Renaming the file extension or editing the content of this file may
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="AckRequest" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>Hcs.Service.Async.DeviceMetering.v15_7_0_1.AckRequest, Connected Services.Service.Async.DeviceMetering.v15_7_0_1.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file is automatically generated by Visual Studio .Net. It is
|
||||
used to store generic object data source configuration information.
|
||||
Renaming the file extension or editing the content of this file may
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="ResultHeader" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>Hcs.Service.Async.DeviceMetering.v15_7_0_1.ResultHeader, Connected Services.Service.Async.DeviceMetering.v15_7_0_1.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user