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 { /// /// Метод передачи в ГИС ЖКХ сведений о договоре РСО (новом или уже существующем) /// public class HcsMethodImportSupplyResourceContractData : HcsHouseManagementMethod { public HcsMethodImportSupplyResourceContractData(HcsClientConfig config) : base(config) { CanBeRestarted = false; } /// /// Размещение нового договора если ГисДоговор.ГуидДоговора не заполнен, /// размещение новой версии договора если заполнен /// http://open-gkh.ru/HouseManagement/SupplyResourceContractType.html /// public async Task 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); } /// /// Вызывает удаленный метод импорта договора с @contractGuid и данными операции импорта @contractItem. /// Чтобы перевести договор из состояния "Проект" в состояние "Размещен" необходимо вызвать /// importSupplyResourceContractProjectData/PlacingContractProject=true /// http://open-gkh.ru/HouseManagement/importSupplyResourceContractRequest.html /// private async Task 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(commonResult.Item); var датаИмпорта = RequireSingleItem(commonResult.Items); return датаИмпорта; default: throw new HcsException($"Неожиданная структура в пакете результата: {commonResult.ItemElementName}"); } } /// /// Преобразует модель данных ГисДоговор в модель данных HouseManagement.SupplyResourceContractType /// http://open-gkh.ru/HouseManagement/SupplyResourceContractType.html /// private HouseManagement.SupplyResourceContractType ConvertToSupplyResourceContract( ГисДоговор договор, IEnumerable<ГисАдресныйОбъект> адреса) { var contract = new HouseManagement.SupplyResourceContractType(); if (договор.ЭтоДоговорНежилогоПомещения) { var isNotContract = new HouseManagement.SupplyResourceContractTypeIsNotContract(); isNotContract.ContractNumber = договор.НомерДоговора; if (договор.ДатаЗаключения != null) isNotContract.SigningDate = (DateTime)договор.ДатаЗаключения; if (!IsArrayEmpty(договор.ПриложенияДоговора)) isNotContract.ContractAttachment = договор.ПриложенияДоговора.Select(ConvertToAttachment).ToArray(); contract.Item = isNotContract; } if (договор.ЭтоДоговорИКУ) { var isContract = new HouseManagement.SupplyResourceContractTypeIsContract(); isContract.ContractNumber = договор.НомерДоговора; var нужнаДатаЗаключения = (договор.ДатаЗаключения != null) ? (DateTime)договор.ДатаЗаключения : DateTime.Now; isContract.SigningDate = isContract.EffectiveDate = нужнаДатаЗаключения; // Для ИКУ обязательно приложение файла договора (иначе 400 Bad request) if (IsArrayEmpty(договор.ПриложенияДоговора)) throw new HcsException($"Для размещения договора ИКУ {договор.НомерДоговора} необходимо указать файл приложения"); isContract.ContractAttachment = договор.ПриложенияДоговора.Select(ConvertToAttachment).ToArray(); contract.Item = isContract; } if (договор.Контрагент == null) throw new HcsException($"В договоре {договор.НомерДоговора} не указан Контрагент"); if (договор.ЭтоДоговорНежилогоПомещения) { contract.Item1 = new HouseManagement.SupplyResourceContractTypeApartmentBuildingOwner() { Item = ConvertToDRSOContragent(договор.Контрагент) }; contract.ContractBase = [HcsHouseManagementNsi.ОснованиеЗаключенияДоговора.ЗаявлениеПотребителя]; } if (договор.ЭтоДоговорИКУ) { if (договор.Контрагент.ГуидОрганизации == null) throw new HcsException($"В договоре ИКУ {договор.НомерДоговора} не указан ГУИД организации"); contract.Item1 = new HouseManagement.SupplyResourceContractTypeOrganization() { orgRootEntityGUID = FormatGuid(договор.Контрагент.ГуидОрганизации) }; contract.ContractBase = [HcsHouseManagementNsi.ОснованиеЗаключенияДоговора.ДоговорУправления]; } Guid contractSubjectGuid = Guid.NewGuid(); contract.ContractSubject = [ new HouseManagement.SupplyResourceContractTypeContractSubject() { ServiceType = HcsHouseManagementNsi.ElectricSupplyServiceType, MunicipalResource = HcsHouseManagementNsi.ElectricSupplyMunicipalResource, StartSupplyDate = (договор.ДатаЗаключения != null ? (DateTime)договор.ДатаЗаключения : DateTime.Now), EndSupplyDate = DateTime.Now.AddYears(50), TransportGUID = FormatGuid(contractSubjectGuid) } ]; // Порядок размещения информации о начислениях за коммунальные услуги ведется. // "D" - в разрезе договора. "O" - в разрезе объектов. Обязательно для ИКУ. if (договор.ЭтоДоговорИКУ) { contract.AccrualProcedure = HouseManagement.SupplyResourceContractTypeAccrualProcedure.D; contract.AccrualProcedureSpecified = true; } if (договор.ЭтоДоговорИКУ) { // Размещение информации о начислениях за коммунальные услуги осуществляет. // R(SO)- РСО. P(roprietor)-Исполнитель коммунальных услуг. Обязательно для ИКУ. contract.CountingResource = договор.НачисленияРазмещаетРСО ? HouseManagement.SupplyResourceContractTypeCountingResource.R : HouseManagement.SupplyResourceContractTypeCountingResource.P; contract.CountingResourceSpecified = true; if (договор.НачисленияРазмещаетРСО) { if (договор.ПриборыРазмещаетРСО) { contract.MeteringDeviceInformation = true; contract.MeteringDeviceInformationSpecified = true; } } // В договоре нет планового объема потребления contract.IsPlannedVolume = false; } if (договор.НачисленияРазмещаетРСО) { // Cрок предоставления платежных документов, не позднее contract.BillingDate = new HouseManagement.SupplyResourceContractTypeBillingDate() { Date = 15, DateType = HouseManagement.SupplyResourceContractTypeBillingDateDateType.N // Следующий месяц }; // Срок предоставления информации о поступивших платежах, не позднее contract.ProvidingInformationDate = new HouseManagement.SupplyResourceContractTypeProvidingInformationDate() { Date = 15, DateType = HouseManagement.SupplyResourceContractTypeProvidingInformationDateDateType.N // Следующий месяц }; } if (договор.ПриборыРазмещаетРСО) { // Период передачи текущих показаний должен быть указан, если ИПУ размещает РСО contract.Period = new HouseManagement.SupplyResourceContractTypePeriod() { Start = new HouseManagement.SupplyResourceContractTypePeriodStart() { StartDate = 1 }, End = new HouseManagement.SupplyResourceContractTypePeriodEnd() { EndDate = 25 } }; } // Срок представления (выставления) платежных документов, не позднее. Является обязательным, // если вторая сторона договора отличается от "Управляющая организация". if (договор.ЭтоДоговорНежилогоПомещения) { contract.BillingDate = new HouseManagement.SupplyResourceContractTypeBillingDate() { Date = -1, // последний день месяца DateType = HouseManagement.SupplyResourceContractTypeBillingDateDateType.N // следующего месяца }; // Объем поставки определяется на основании прибора учета (признак необходим чтобы // ГИС разрешал размещать ПУ на лицевых счетах договора) (признак запрещен для ИКУ) contract.VolumeDepends = true; contract.VolumeDependsSpecified = true; // Период передачи текущих показаний должен быть указан если указано VolumeDepends contract.Period = new HouseManagement.SupplyResourceContractTypePeriod() { Start = new HouseManagement.SupplyResourceContractTypePeriodStart() { StartDate = 1 }, End = new HouseManagement.SupplyResourceContractTypePeriodEnd() { EndDate = 25 } }; } // Срок действия договора contract.ItemsElementName = [HouseManagement.ItemsChoiceType9.IndefiniteTerm]; contract.Items = [true]; // Данные об объекте жилищного фонда. При импорте договора должен быть добавлен // как минимум один адрес объекта жилищного фонда. if (адреса != null) { contract.ObjectAddress = адреса.Select( адрес => ConvertToObjectAddress(договор, адрес, contractSubjectGuid)).ToArray(); } return contract; } /// /// Сборка сведений для отправки указателя на файл приложения к договору /// http://open-gkh.ru/Base/AttachmentType.html /// private HouseManagement.AttachmentType ConvertToAttachment(ГисПриложение приложение) { return new HouseManagement.AttachmentType() { Name = приложение.ИмяПриложения ?? throw new HcsException("Не указано имя файла приложения"), Description = приложение.ОписаниеПриложения != null ? приложение.ОписаниеПриложения : приложение.ИмяПриложения, AttachmentHASH = приложение.ХэшПриложения ?? throw new HcsException("Не указан хэш файла приложения"), Attachment = new HouseManagement.Attachment() { AttachmentGUID = FormatGuid(приложение.ГуидПриложения) } }; } private HouseManagement.SupplyResourceContractTypeObjectAddress ConvertToObjectAddress( ГисДоговор договор, ГисАдресныйОбъект адрес, Guid contractSubjectGuid) { // Дату начала снабжения выводим из даты заключения договора DateTime startSupplyDate = (договор.ДатаЗаключения != null) ? (DateTime)договор.ДатаЗаключения : DateTime.Now; // Ссылка на пару определения ресурсов предмета договора var pair = new HouseManagement.SupplyResourceContractTypeObjectAddressPair(); pair.PairKey = FormatGuid(contractSubjectGuid); pair.StartSupplyDate = startSupplyDate; // TODO: Проверить комментарий pair.EndSupplyDateSpecified = false; // Не указана дата окончания поставки ресурса var address = new HouseManagement.SupplyResourceContractTypeObjectAddress() { TransportGUID = FormatGuid(Guid.NewGuid()), FIASHouseGuid = FormatGuid(адрес.ГуидЗданияФиас), ApartmentNumber = MakeEmptyNull(адрес.НомерПомещения), RoomNumber = MakeEmptyNull(адрес.НомерКомнаты), Pair = [pair] }; if (!string.IsNullOrEmpty(адрес.ТипЗдания)) { address.HouseTypeSpecified = true; address.HouseType = ConvertToHouseType(адрес.ТипЗдания); } return address; } private HouseManagement.ObjectAddressTypeHouseType ConvertToHouseType(string типЗдания) { return типЗдания switch { ГисАдресныйОбъект.ИзвестныеТипыЗдания.MKD => HouseManagement.ObjectAddressTypeHouseType.MKD, ГисАдресныйОбъект.ИзвестныеТипыЗдания.ZHD => HouseManagement.ObjectAddressTypeHouseType.ZHD, ГисАдресныйОбъект.ИзвестныеТипыЗдания.ZHDBlockZastroyki => HouseManagement.ObjectAddressTypeHouseType.ZHDBlockZastroyki, _ => throw new HcsException($"Указан неизвестный тип здания [{типЗдания}]") }; } /// /// Преобразует реквизиты контрагента в модель данных ГИС ЖКХ /// 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; } /// /// Выполнение операции размещения факта расторжения договора /// http://open-gkh.ru/HouseManagement/importSupplyResourceContractRequest/Contract/TerminateContract.html /// public async Task TerminateContract( ГисДоговор договор, DateTime датаРасторжения, CancellationToken token) { var terminate = new HouseManagement.importSupplyResourceContractRequestContractTerminateContract(); terminate.Terminate = датаРасторжения; terminate.ReasonRef = HcsHouseManagementNsi.ПричинаРасторженияДоговора.ПоВзаимномуСогласиюСторон; return await CallImportContract(договор.ГуидДоговора, terminate, token); } /// /// Выполнение операции размещения факта аннулирование договора /// http://open-gkh.ru/HouseManagement/AnnulmentType.html /// public async Task AnnulContract(ГисДоговор договор, string причина, CancellationToken token) { var annulment = new HouseManagement.AnnulmentType(); annulment.ReasonOfAnnulment = причина; return await CallImportContract(договор.ГуидДоговора, annulment, token); } } }