Версия для печати темы (https://pro1c.org.ua/index.php?showtopic=41520)
Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7 _ Программирование в 1С Предприятие 8.3 _ И снова перевод на управляемые блокировки
Автор: vbi 01.11.17, 12:19
Конфигурация УТ для Украины 2.3 (доработанная много чем), платформа 8.3.8.1784.
И вот снова конфликт блокировки транзакций, где около 200 пользователей одновременно блокируют друг друга. Отложенное проведение по партиям уже не помагает, прижало до реализации управляемых блокировок.
На основе http://pro1c.org.ua/redirect.php?http://www.forum.mista.ru/topic.php?id=511356 придумал реализовать блокировки по складу следующим образом:
1. Переводим саму конфигурацию на чисто управляемые блокировки.
2. Создаем подписку на событие "ОбработкаПроверкиЗаполнения", источник - ДокументОбъект.
3. Процедура подписки:
Код Процедура УправляемыеБлокировкиОбработкаПроверкиЗаполнения(Источник, Отказ, ПроверяемыеРеквизиты) Экспорт
Если Отказ Тогда
Возврат;
КонецЕсли;
РежимБлокировки = РежимБлокировкиДанных.Исключительный;
Блокировка = Новый БлокировкаДанных();
//Определения имени пространства для "Документ"
Если Метаданные.Документы.Индекс(Источник.Метаданные()) <> - 1 Тогда
ИмяОбъектаПространстваБлокировок = "Документ." + Источник.Метаданные().Имя;
//Блокировка самого документа
ЭлементБлокировки = Блокировка.Добавить(ИмяОбъектаПространстваБлокировок);
ЭлементБлокировки.Режим = РежимБлокировки;
ЭлементБлокировки.УстановитьЗначение("Ссылка", Источник.Ссылка);
КонецЕсли;
//Определения имени пространства для "Последовательность"
Для Каждого ТекПоследовательность Из Последовательности Цикл
Если ТекПоследовательность.Принадлежит(Источник.Ссылка) Тогда
//Необходимо заблокировать последовательность
ЭлементБлокировки = Блокировка.Добавить("Последовательность." + Прав(Строка(ТекПоследовательность), СтрДлина(Строка(ТекПоследовательность)) - Найти(Строка(ТекПоследовательность), ".")) + ".НаборЗаписей");
ЭлементБлокировки.Режим = РежимБлокировки;
КонецЕсли;
КонецЦикла;
//Определения имени пространства для "Регистров"
КоллекцияДвижений = Источник.Метаданные().Движения;
Для Каждого ТекРегистрДвижения Из КоллекцияДвижений Цикл
ИмяРегистра = ТекРегистрДвижения.Имя;
ТипРегистра = "";
Если Метаданные.РегистрыНакопления.Найти(ИмяРегистра) <> Неопределено Тогда
ТипРегистра = "РегистрНакопления";
ИначеЕсли Метаданные.РегистрыБухгалтерии.Найти(ИмяРегистра) <> Неопределено Тогда
ТипРегистра = "РегистрБухгалтерии";
Иначе
ТипРегистра = "РегистрСведений";
КонецЕсли;
Если ТипРегистра <> "" Тогда
ЭлементБлокировки = Блокировка.Добавить(ТипРегистра + "." + ИмяРегистра + ".НаборЗаписей");
ЭлементБлокировки.Режим = РежимБлокировки;
Если ТекРегистрДвижения.Измерения.Найти("Склад") <> Неопределено Тогда
Если Источник.Метаданные().Реквизиты.Найти("СкладОрдер") <> Неопределено Тогда
ЭлементБлокировки.УстановитьЗначение("Склад", Источник.СкладОрдер);
ИначеЕсли Источник.Метаданные().Реквизиты.Найти("Склад") <> Неопределено Тогда
ЭлементБлокировки.УстановитьЗначение("Склад", Источник.Склад);
ИначеЕсли Источник.Метаданные().Реквизиты.Найти("СкладОтправитель") <> Неопределено Тогда
тз = Новый ТаблицаЗначений;
тз.Колонки.Добавить("Склад");
строка = тз.Добавить();
строка.Склад = Источник.СкладОтправитель;
строка = тз.Добавить();
строка.Склад = Источник.СкладПолучатель;
ЭлементБлокировки.ИсточникДанных = тз;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Склад", "Склад");
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
//Установка блокировки
Попытка
Блокировка.Заблокировать();
Исключение
ОбщегоНазначения.СообщитьОбОшибке(ОписаниеОшибки(), Отказ, "Не удалось заблокировать объекты");
ВызватьИсключение "Операция не выполнена";
КонецПопытки;
КонецПроцедуры
Подписка на "ОбработкаПроверкиЗаполнения" выполняется раньше чем "ПередЗаписью" в модуле объекта. Блокировка работает так:
По умолчанию блокируется все без отбора. Но если регистр имеет измерение "Склад", а источник "Склад", "СкладОрдер", "СкладОтправитель" - то устанавливается отбор по складу. Теоретически такая блокировка должна увеличить параллельность. Кто что думает?
Сделал я вот это все. На тестовой базе зашел под двумя пользователями и одновременно запустил перепроведение всех реализаций и там и там, но первый пользователь - все реализации с одного склада "Склад1" второй - "Склад2". Теоретически взаимоблокировок не должно быть. Но постоянно вижу Конфликт блокировки транзакций по регистру партий. В месте где вызывается запрос по партиям и списанным товарам. В запросе по партиям есть отбор по складу, а вот списанные товары не блокируются....
Автор: Vofka 01.11.17, 13:13
С блокировками существует 2 проблемы:
1) кто-то отваливается по таймауту, потому что не дожидается освобождения ресурсов
2) кто-то отваливается из-за взаимоблокировок
У вас что именно?
Автор: vbi 01.11.17, 14:58
Цитата
С блокировками существует 2 проблемы:
1) кто-то отваливается по таймауту, потому что не дожидается освобождения ресурсов
2) кто-то отваливается из-за взаимоблокировок
У вас что именно?
По таймауту
Автор: vbi 01.11.17, 16:02
По таймауту в центральной базе. А в этом примере - жертва взаимоблокировок.
Автор: Vofka 01.11.17, 16:37
Перечитываю много раз что вы написали, но непонятно нифига что у вас происходит. Кроме того вы, видимо, путаете между собой эти две проблемы (о которых я выше писал), считая, что это одно и то же. Вы сейчас запускаете проведение расходных накладных под двумя пользователями по разным складам и у вас в какой-то момент возникают именно взаимоблокировки?
Автор: vbi 01.11.17, 17:21
Цитата
Перечитываю много раз что вы написали, но непонятно нифига что у вас происходит. Кроме того вы, видимо, путаете между собой эти две проблемы (о которых я выше писал), считая, что это одно и то же. Вы сейчас запускаете проведение расходных накладных под двумя пользователями по разным складам и у вас в какой-то момент возникают именно взаимоблокировки?
Да, путаю. Но уже не путаю, уже вроде разобрался в их различии.
Именно взаимоблокировки, так как пишет ошибку "... стала жертвой взаимоблокировки". - Значит менеджер взаимоблокировок одну транзакцию принес в жертву.
Но вот незадача: отключил ту процедуру что описал выше, которая осуществляет блокировки. - результат тот же. Блокировок не ставлю - откуда взаимоблокировки?Конфигурация в режиме чисто управляемых блокировок.
Автор: Vofka 01.11.17, 17:40
Ошибку пишет русским языком? Кстати, а какая СУБД?
Автор: vbi 01.11.17, 17:48
MS SQL 2014
Автор: Vofka 01.11.17, 18:03
Сейчас у вас конфа стоит в режиме Управляемый, вы проводите под разными пользователями только Расходные накладные и возникает взаимоблокировка? А не видно в каком именно месте в коде?
Автор: vbi 01.11.17, 18:19
Другие документы не пробовал.
Ошибка возникает в строчке: "Запрос.Выполнить()" в процедуре:
Код Функция ПолучитьДеревоПартийНаСкладахУпр (МоментКон, СтруктураПараметров)
Запрос = Новый Запрос;
ОсновнойДокумент = Неопределено;
СтруктураПараметров.Свойство("ОсновнойДокумент",ОсновнойДокумент);
Регистратор = СтруктураПараметров.Регистратор;
СпособОценкиМПЗ = СтруктураПараметров.СпособОценкиМПЗУпр;
СтратегияСтатусПартии = СтруктураПараметров.СтратегияСтатусПартииУпр;
ВестиПартионныйУчетПоСкладам = СтруктураПараметров.ВестиПартионныйУчетПоСкладамУпр;
// Для повышения быстродействия остатки партий получаются различными способами
Если СтруктураПараметров.Свойство("ЗакрытиеЗаказовПокупателей") Тогда
ЗаполнитьЗапросПартийНаСкладахДляЗакрытияЗаказовПокупателей(Запрос);
ИначеЕсли ОсновнойДокумент <> Неопределено И НЕ СтруктураПараметров.СписыватьПартииРасходнымОрдером
И ТипЗнч(ОсновнойДокумент) = Тип("ДокументСсылка.РеализацияТоваровУслуг")тогда
// Списание расходным ордером товара реализованного и принятого на ответственное хранение (отложенная отгрузка)
ЗаполнитьЗапросПартийНаСкладахДляОтложеннойОтгрузкиУпр(Запрос, ВестиПартионныйУчетПоСкладам);
ИначеЕсли ОсновнойДокумент <> Неопределено тогда
// Списание партий по ордерной схеме:
// - Списание партий по расходному ордеру
// - Перемещение партий по приходному ордеру
// - Перемещение партий поступлением товаров и услуг в НТТ
// Движения реализации выполняет расходный ордер, движения перемещения выполняет приходный ордер
ЗаполнитьЗапросПартийНаСкладахДляСписанияПоОрдернойСхемеУпр(Запрос, ВестиПартионныйУчетПоСкладам, СтратегияСтатусПартии, СпособОценкиМПЗ);
Иначе
// Общий случай списания
ЗаполнитьЗапросПартийНаСкладахУпр(Запрос, ВестиПартионныйУчетПоСкладам, СтратегияСтатусПартии, СпособОценкиМПЗ);
Если НЕ СтруктураПараметров.ИспользоватьУказаниеСерийНоменклатурыПриРезервировании тогда
Запрос.Текст = СтрЗаменить(Запрос.Текст,"ИЛИ ПартииТоваровНаСкладах.СерияНоменклатуры = &ПустаяСерияНоменклатуры",
"ИЛИ ПартииТоваровНаСкладах.СерияНоменклатуры = &ПустаяСерияНоменклатуры
|ИЛИ СписанныеТовары.КодОперацииПартииТоваров = &КодРезервирование");
Запрос.УстановитьПараметр("КодРезервирование" , СтруктураПараметров.КодыОпераций.РезервированиеПодЗаказ)
КонецЕсли;
КонецЕсли;
Запрос.УстановитьПараметр("ПустаяСерияНоменклатуры", Справочники.СерииНоменклатуры.ПустаяСсылка());
Запрос.УстановитьПараметр("ПустойЗаказ", Документы.ЗаказПокупателя.ПустаяСсылка());
Запрос.УстановитьПараметр("ПустойСтатус", Перечисления.СтатусыПартийТоваров.ПустаяСсылка());
Запрос.УстановитьПараметр("СтатусПартииПоОрдеру", Перечисления.СтатусыПартийТоваров.ПоОрдеру);
Запрос.УстановитьПараметр("ПустоеКачество", Справочники.Качество.ПустаяСсылка());
Запрос.УстановитьПараметр("КачествоНовый", Справочники.Качество.Новый);
Запрос.УстановитьПараметр("ПустойСклад", Справочники.Склады.ПустаяСсылка());
Запрос.УстановитьПараметр("Ссылка", Регистратор);
Если ОсновнойДокумент <> Неопределено Тогда
Запрос.УстановитьПараметр("ОсновнойДокумент", ОсновнойДокумент);
Иначе
Запрос.УстановитьПараметр("ОсновнойДокумент", Регистратор);
КонецЕсли;
Запрос.УстановитьПараметр("Дат", МоментКон);
Запрос.УстановитьПараметр("НаКомиссию", Перечисления.СтатусыПартийТоваров.НаКомиссию);
Если ТипЗнч(Регистратор) = Тип("ДокументСсылка.ОтчетОРозничныхПродажах") или ТипЗнч(Регистратор) = Тип("ДокументСсылка.РеализацияТоваровУслуг") ИЛИ ТипЗнч(Регистратор) = Тип("ДокументСсылка.ПеремещениеТоваров") Тогда
//или ТипЗнч(Регистратор) = Тип("ДокументСсылка.ВозвратТоваровПоставщику") Тогда
Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
| СписанныеТовары.НомерСтрокиДокумента КАК НомерСтрокиДокумента,
| ПартииТоваровНаСкладах.Номенклатура,
| ПартииТоваровНаСкладах.ДокументОприходования КАК ДокументОприходования,
| ПартииТоваровНаСкладах.ДокументОприходования.Дата КАК ДокументОприходованияДата,
| ПартииТоваровНаСкладах.Склад,
| ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры,
| ПартииТоваровНаСкладах.СерияНоменклатуры,
| ПартииТоваровНаСкладах.Качество,
| ПартииТоваровНаСкладах.Заказ,
| ПартииТоваровНаСкладах.КоличествоОстаток КАК Количество,
| ПартииТоваровНаСкладах.СтоимостьОстаток КАК Стоимость,
| ПартииТоваровНаСкладах.СтатусПартии,
| ВЫБОР
| КОГДА СписанныеТовары.СерияНоменклатуры = ПартииТоваровНаСкладах.СерияНоменклатуры
| ТОГДА 0
| ИНАЧЕ 1
| КОНЕЦ КАК ЧислоСерияНоменклатуры,
| ВЫБОР
| КОГДА СписанныеТовары.ДокументПартии = НЕОПРЕДЕЛЕНО
| ТОГДА 0
| ИНАЧЕ ВЫБОР
| КОГДА СписанныеТовары.ДокументПартии = ПартииТоваровНаСкладах.ДокументОприходования
| ТОГДА 0
| ИНАЧЕ 1
| КОНЕЦ
| КОНЕЦ КАК ЧислоДокументОприходования,
| ВЫБОР
| КОГДА СписанныеТовары.ЗаказПартии = НЕОПРЕДЕЛЕНО
| ТОГДА 0
| ИНАЧЕ ВЫБОР
| КОГДА ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ
| ТОГДА 1
| ИНАЧЕ 0
| КОНЕЦ
| КОНЕЦ КАК ЧислоЗаказ,
| ВЫБОР
| КОГДА ПартииТоваровНаСкладах.СтатусПартии = &НаКомиссию
| ТОГДА 1
| ИНАЧЕ 0
| КОНЕЦ КАК ЧислоСтатусПартии
|ИЗ
| РегистрСведений.СписанныеТовары КАК СписанныеТовары
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ПартииТоваровНаСкладах.Остатки(&Дат, Склад = &Склад) КАК ПартииТоваровНаСкладах
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СписанныеТовары КАК СписанныеТовары1
| ПО СписанныеТовары1.Номенклатура = ПартииТоваровНаСкладах.Номенклатура
| ПО СписанныеТовары.Номенклатура = ПартииТоваровНаСкладах.Номенклатура
| И СписанныеТовары.ХарактеристикаНоменклатуры = ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры
| И (ВЫБОР
| КОГДА ПартииТоваровНаСкладах.Качество = &ПустоеКачество
| ТОГДА ИСТИНА
| ИНАЧЕ ВЫБОР
| КОГДА СписанныеТовары.Качество = &ПустоеКачество
| ТОГДА ПартииТоваровНаСкладах.Качество = &КачествоНовый
| ИНАЧЕ ПартииТоваровНаСкладах.Качество = СписанныеТовары.Качество
| КОНЕЦ
| КОНЕЦ)
| И (ПартииТоваровНаСкладах.Склад = СписанныеТовары.Склад
| ИЛИ ПартииТоваровНаСкладах.Склад = &ПустойСклад)
| И (ВЫБОР
| КОГДА СписанныеТовары.ДопустимыйСтатус1 <> &ПустойСтатус
| ИЛИ СписанныеТовары.ДопустимыйСтатус2 <> &ПустойСтатус
| ИЛИ СписанныеТовары.ДопустимыйСтатус3 <> &ПустойСтатус
| ИЛИ СписанныеТовары.ДопустимыйСтатус4 <> &ПустойСтатус
| ТОГДА ПартииТоваровНаСкладах.СтатусПартии = &ПустойСтатус
| ИЛИ ПартииТоваровНаСкладах.СтатусПартии = &СтатусПартииПоОрдеру
| ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус1
| ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус2
| ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус3
| ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус4
| ИНАЧЕ ИСТИНА
| КОНЕЦ)
| И (ВЫБОР
| КОГДА СписанныеТовары.СписыватьТолькоПоЗаказу = ИСТИНА
| ТОГДА ВЫБОР
| КОГДА ПартииТоваровНаСкладах.Заказ <> СписанныеТовары.ЗаказПартии
| ТОГДА ВЫБОР
| КОГДА НЕ СписанныеТовары.ЗаказПартии = НЕОПРЕДЕЛЕНО
| ТОГДА ЛОЖЬ
| ИНАЧЕ ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ
| КОНЕЦ
| ИНАЧЕ ИСТИНА
| КОНЕЦ
| ИНАЧЕ ВЫБОР
| КОГДА ПартииТоваровНаСкладах.Заказ <> СписанныеТовары.ЗаказПартии
| ТОГДА ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ
| ИНАЧЕ ИСТИНА
| КОНЕЦ
| КОНЕЦ)
| И (СписанныеТовары.СерияНоменклатуры = ПартииТоваровНаСкладах.СерияНоменклатуры
| ИЛИ ПартииТоваровНаСкладах.СерияНоменклатуры = &ПустаяСерияНоменклатуры
| ИЛИ СписанныеТовары.КодОперацииПартииТоваров = &КодРезервирование)
|ГДЕ
| СписанныеТовары.Регистратор = &ОсновнойДокумент
| И СписанныеТовары.Склад = &Склад
| И СписанныеТовары1.Регистратор = &Ссылка
|
|УПОРЯДОЧИТЬ ПО
| ЧислоСерияНоменклатуры,
| ЧислоДокументОприходования,
| ЧислоЗаказ,
| ЧислоСтатусПартии,
| ДокументОприходованияДата,
| ДокументОприходования
|ИТОГИ ПО
| НомерСтрокиДокумента";
Если ТипЗнч(Регистратор) = Тип("ДокументСсылка.ПеремещениеТоваров") Тогда
Запрос.УстановитьПараметр("Склад", Регистратор.СкладОтправитель);
Иначе
Запрос.УстановитьПараметр("Склад", Регистратор.Склад);
КонецЕсли;
КонецЕсли;
Возврат Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
КонецФункции//ПолучитьДеревоПартийНаСкладахУпр
причем всегда на том же месте ошибка. Запрос выполняется по партиям. На партии стоит отбор по складу. На списанные товары блокировку вообще не ставил. Да и проблема в том что если вообще блокировку не ставить то ошибка та же. Такое впечатление что как то они автоматически ставятся.
Автор: Acid 02.11.17, 11:26
Регистр Партии товаров на складах заблокирован в следствии транзакции при групповом проведении документов. Вы хотите во время данной транзакции параллельно запустить еще одно групповое проведение по данному регистру?
Автор: Vofka 02.11.17, 11:54
Попробуйте где-то перед этим запросом установить управляемую блокировку на регистр Партий по измерению Склад.
Автор: vbi 05.11.17, 21:06
Цитата
Вы хотите во время данной транзакции параллельно запустить еще одно групповое проведение по данному регистру?
Да, но с отбором по разным складам.
Цитата
Попробуйте где-то перед этим запросом установить управляемую блокировку на регистр Партий по измерению Склад.
Попробовал, но результат - тот же:
...
РежимБлокировки = РежимБлокировкиДанных.Исключительный;
Блокировка = Новый БлокировкаДанных();
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ПартииТоваровНаСкладах");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьЗначение("Склад", Регистратор.Склад);
Блокировка.Заблокировать();
Возврат Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
КонецФункции//ПолучитьДеревоПартийНаСкладахУпр
На возврате - ошибка.
Автор: Acid 06.11.17, 8:33
vbi @ Вчера, 22:06
,
Не нужно использовать транзакции, в вашем случае.
Автор: Vofka 06.11.17, 9:28
Цитата(vbi @ 05.11.17, 21:06)
Попробовал, но результат - тот же
А если эту блокировку сделать в самом начале ОбработкиПроведения?
Цитата(Acid @ 06.11.17, 8:33)
Не нужно использовать транзакции, в вашем случае.
А подробней можно?
Автор: Acid 06.11.17, 11:38
Цитата(Vofka @ 06.11.17, 10:28)
Цитата(Acid @ 06.11.17, 8:33) *
Не нужно использовать транзакции, в вашем случае.
А подробней можно?
В обработке группового проведения, в настройках снять галочку "Выполнять в транзакции".
Автор: vbi 06.11.17, 20:03
Цитата
В обработке группового проведения, в настройках снять галочку "Выполнять в транзакции".
Я проведение делаю там и там в Запроснику. Выполняю запрос - нахожу все реализации по складу, В обработке результата запроса - перепровожу.
Вообщем может делаю что не так:
Есть УТ. Включаю в настройках конфигурации режим блокировок "Управляемый". Дальше что делать, чтобы реализации одновременно проводились по партиям, по разным складам. Как блокировать партии только по конкретному складу?
Автор: vbi 06.11.17, 21:11
Разобрался. http://pro1c.org.ua/redirect.php?http://v8.1c.ru/overview/Term_000000642.htm:
Цитата
Управляемый режим позволяет повысить параллельность работы пользователей в клиент-серверном варианте работы за счет использования более низкого уровня изоляции транзакций базы данных (Read Committed). При записи данных в транзакции объекты встроенного языка автоматически блокируют необходимые данные. Разработчику требуется управлять блокировками данных в тех случаях, когда бизнес-логика требует согласованного и целостного чтения данных в транзакции.
То есть, насколько я понял, если не блокировать в коде при управляемом режиме, то конфигурация всеравно блокирует данные но более на низком уровне. Но если блокировать - тогда работает твой код. Следовательно в примере выше я не блокировал регситр сведений "СписанныеТовары". Когда я прописал в коде:
Блокировка = Новый БлокировкаДанных();
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СписанныеТовары");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ПартииТоваровНаСкладах");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьЗначение("Склад", Склад);
Блокировка.Заблокировать();
- блокировки исчезли. Мы в СписанныеТовары ничего не пишем - только читаем из него. Если мы его явно в коде не упоминали - он блокировался полностью и исключительно.
Причем блокировка работает почемуто только в ОбработкеПроведения документа. В подписках не работает...
Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7
https://pro1c.org.ua