Управляемое приложение (8.2, 8.3)

Интерфейс строится для конкретного пользователя, учитывая его права, настройки и функциональные опции.


При создании Общего модуля, правилом хорошего тона считается не указывать директивы компиляции. Т.е. доступность процедур и функций должна определяться свойствами самого модуля. Например создаются модули РегламентныеПроцедурыСервер, РегламентныеПроцедурыКлиент. Модули, у которых установлено несколько флагов компиляции, на практике используются крайне редко. Это некоторые общие действия, доступные как на Клиенте, так и на Сервере. Обычно, это какие-то простейшие вычисления.


Если необходима глобальная переменная, то можно использовать либо параметры сеанса, либо экспортные переменные модуля приложения.


Чтобы получить макет внешней обработки в процедуре, выполняющейся &НаСервере, надо использовать:

Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("ИмяМакета");

вывод табличного документа также осуществлять &НаСервере.


Если на форму вынести реквизит с типом «строка», который будет содержать навигационную ссылку на графические данные или адрес временного хранилища которое содержит такие данные, то форма сможет отобразить сами графические данные. Надо вывести реквизит на форму и выбрать вид «Поле картинки».


В контексте управляемой формы недоступны свойства и методы Объекта, основного реквизита формы. Доступ к нему возможен только в серверных процедурах, преобразовав реквизиты формы «Объект» в объект:

&НаСервере
Процедура ОбработатьРеквизитНаСервере()
    РеквизитОбъект = РеквизитФормыВЗначение("ИмяРеквизита", ТипРеквизита);
    . . .
    . . .
    ЗначениеВРеквизитФормы(РеквизитОбъект, "ИмяРеквизита");
КонецПроцедуры

Установка отбора динамического списка.

    Отбор = ИмяСписка.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    Отбор.Использование = Истина;
    Отбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("РеквизитСпискаДляОтбора");
    Отбор.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
    Отбор.ПравоеЗначение = ЗначениеОтбора;

Обновление элементов управляемой формы

// динамический список "ДинСп"
Элементы.ДинСп.Обновить();

// реквизиты
ЭтаФорма.Прочитать();

// данные
ЭтаФорма.ОбновитьОтображениеДанных();

Програмный вывод реквизита на управляемую форму

Элемент = ЭтаФорма.Элементы.Добавить("Поле", Тип("ПолеФормы"), ЭтаФорма);
Элемент.Вид = ВидПоляФормы.ПолеВвода;
Элемент.ПутьКДанным = "Объект.НазваниеРевизита";

Процедура для вывода произвольной ТаблицыЗначений на управляемую форму.

// *******************************************************************************************
 
// ПРИМЕЧАНИЕ: 
//        Эту процедуру можно разместить в общем модуле, для дальнейшего вызова из любого места

//        Для отображения таблицы необходиом чтобы на форме предварительно был создан реквизит типа "таблица значений",
//            и чтобы он был размещен среди элементов формы

//
// ОПИСАНИЕ: 

//         Создает и отображает на управляемой форме таблицу значений, переданную в качестве параметра 
//         Дополнительно может подключить обработчики событий для таблицы

//
// ПАРАМЕТРЫ:
//
// УФ - управляемая форма, на которую нужно вывести ТаблицуЗначений
// ИмяТЗНаФорме - имя ТаблицыЗначений (реквизита формы)
// ТЗ - таблица значений, которую нужно отобразить на форме
// ТЗОбработчиковСобытий - таблица со структурой данных, описывающих обработчики событий. Не обязательна.
//            Процедура обработки события должна именоваться как <ИмяЭлемента + ИмяСобытия>
&НаСервере
Процедура ВывестиТаблицуНаФорму(УФ,ИмяТЗНаФорме,ТЗ, ТЗОбработчиковСобытий = Неопределено) Экспорт
    
   // СОЗДАНИЕ РЕКВИЗИТОВ ФОРМЫ
 
    МассивДобавляемыхРеквизитов = Новый Массив; 
    
    Для Каждого Колонка Из ТЗ.Колонки Цикл
        // Новый РеквизитФормы(... - Создает описание реквизита управляемой формы на основе переданных параметров
        МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения,ИмяТЗНаФорме ,Колонка.Заголовок));    
    КонецЦикла; 
    
    МассивУдаляемыхРеквизитов = УФ.ПолучитьРеквизиты(ИмяТЗНаФорме);
    МассивИменУдаляемыхРеквизитов = Новый Массив;
    
    Для каждого Элемент Из МассивУдаляемыхРеквизитов Цикл
        МассивИменУдаляемыхРеквизитов.Добавить(ИмяТЗНаФорме + "." + Элемент.Имя);
    КонецЦикла; 
    
    УФ.ИзменитьРеквизиты(МассивДобавляемыхРеквизитов,МассивИменУдаляемыхРеквизитов); 
    
   // СОЗДАНИЕ ЭЛЕМЕНТОВ ФОРМЫ
 
    Для каждого Элемент Из МассивУдаляемыхРеквизитов Цикл
        УдаляемыйЭлемент = УФ.Элементы.Найти(ИмяТЗНаФорме + Элемент.Имя);
        УФ.Элементы.Удалить(УдаляемыйЭлемент);
    КонецЦикла; 
    
    Для Каждого Колонка Из ТЗ.Колонки Цикл
        НоваяКолонка = УФ.Элементы.Добавить(ИмяТЗНаФорме + Колонка.Имя, Тип("ПолеФормы"), УФ.Элементы[ИмяТЗНаФорме]); 
        НоваяКолонка.Заголовок = Колонка.Заголовок; 
        НоваяКолонка.ПутьКДанным = ИмяТЗНаФорме + "." + Колонка.Имя;
        НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода; 
        НоваяКолонка.РежимРедактирования = РежимРедактированияКолонки.ВходПриВводе;    
    КонецЦикла;     
    
    УФ[ИмяТЗНаФорме].Загрузить(ТЗ);
    
   // Привязка обработчиков событий
 
    Если ТЗОбработчиковСобытий = Неопределено Тогда
        Возврат;
    КонецЕсли;    
    
    Для Каждого Строка Из ТЗОбработчиковСобытий Цикл
        УФ.Элементы[Строка.ИмяЭлемента].УстановитьДействие(Строка.ИмяСобытия, Строка.ИмяЭлемента + Строка.ИмяСобытия); 
    КонецЦикла;    
    
КонецПроцедуры

Програмное добавление таблицы значений на управляемую форму

&НаСервере
Процедура ИзменитьФорму()
        
    МассивДобавляемыхРеквизитов = Новый Массив;
    МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы(ИмяТаблицы, Новый ОписаниеТипов("ТаблицаЗначений")));
    ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);

    ТабПоле = Элементы.Добавить(ИмяТаблицы, Тип("ТаблицаФормы"), НоваяСтраница);
    ТабПоле.ПутьКДанным = ИмяТаблицы;
    ТабПоле.Отображение = ОтображениеТаблицы.Список;
    
КонецПроцедуры

Програмное добавление страницы на управляемую форму

&НаСервере
Процедура ИзменитьФорму()
        
    НовыйЭлемент1 = Элементы.Добавить("НоваяСтраница",Тип("ГруппаФормы"),Элементы.ГруппаСтраницы);
    НовыйЭлемент1.Вид = ВидГруппыФормы.Страница;
    НовыйЭлемент1.Заголовок = "НоваяСтраница";
        
    НовыйЭлемент2 = Элементы.Добавить("НоваяНадпись",Тип("ДекорацияФормы"),НовыйЭлемент1);
    НовыйЭлемент2.Заголовок = "НоваяНадпись";
    
КонецПроцедуры

Получить предопределенное значение справочника, перечисления или бизнесс-процесса на стороне клиента можно так:

ПредопределенноеЗначение("Справочник.ИмяСправочника.ИмяПредопределенногоЭлемента");

Для правильной работы контекстной подсказки по процедуре или функции их заголовок должен быть оформлен следующим образом:

// %

// Параметры:

// {НаименованиеПараметра} - % (тип параметра) - % (описание параметра)

// {НаименованиеПараметра} - % (описание параметра)

где: % - любой набор символов

Пример:

//
// Параметры:
// МассивОбъектов - Массив - ссылки на объекты
// КоллекцияПечатныхФорм - ТаблицаЗначений - уже сформированные документы
// ОбъектыПечати - СписокЗначений - значение это ссылка на объект, а представление это имя области в которой был введен объект
// ПараметрыВывода - произвольные параметры для печати.

Режим разделения итогов регистра

При включенном разделителе итогов немного увеличивается размер таблицы итогов регистра, т.к. добавляется новый столбец и вместо одной строки по набору измерений может появится несколько.

Данный режим следует использовать при выполнении следующих двух условий:

1. По данному регистру нет контроля остатков. При использовании регистра бухгалтерии контроль остатков как правило отсутствует. Если есть контроль остатков, то выигрыша в производительности не будет. Так же при контроле остатков необходимо использовать свойство набора записей БлокироватьДляИзменения, иначе возможна взаимоблокировка.

2. С регистром идет активная параллельная работа пользователей. Если с регистром работают только последовательно, либо с ним работает малое количество пользователей, тогда нет особого смысла включать разделитель итогов. Ведь при отсутствии конкурирующих транзакциях мы не получим никакого эффекта от включения режима разделения итогов, т.к. нет ожиданий на блокировках.


Включение отладки на сервере 1С По умолчанию отладка на сервере выключена.

Чтобы включить, нужно:

Запустить REGEDIT

Найти строчку «C:\Program Files\1cv81\bin\ragent.exe» -srvc -agent (взятую из параметров запуска службы Агент сервера 1С:Предприятия 8.3).

Дописать в конец -debug

Например.

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\1C:Enterprise 8.1 Server Agent] «ImagePath»=

было «С:\Program Files\1cv81\bin\ragent.exe» -srvc -agent -regport 1541 -port 1540 -range 1560:1591 -d «С:\Program Files\1cv81\server»

поставили «С:\Program Files\1cv81\bin\ragent.exe» -srvc -agent -regport 1541 -port 1540 -range 1560:1591 -debug -d «С:\Program Files\1cv81\server»

Остановить сервер, запустить сервер.

Запустить в режиме 1С:Предприятие . Выбрать «Сервис-Параметры». Закладка «Системные», включить «Отладка разрешена», «Устанавливать режим разрешения отладки при запуске».

Запустить конфигуратор. Меню «Отладка-Подключение». Включить необходимые флажки в «Автоматическое подключение».


Блокировки в проведении реализации по партиям

Процедура ОбработкаПроведения(Отказ, Режим)

 //1
 Движения.ОстаткиТоваров.Записывать = Истина;
 
 //2
 Движения.ОстаткиТоваров.Очистить();
 
 Для каждого Стр Из СписокТоваров Цикл
  Движение = Движения.ОстаткиТоваров.ДобавитьРасход();
  Движение.Период = Дата;
  Движение.Товар = Стр.Товар;
  Движение.Количество = Стр.Количество;
 КонецЦикла; 
 
 //7
 Движения.ОстаткиТоваров.БлокироватьДляИзменения = Истина;
 
 //3
 Движения.Записать();

 Запрос = Новый Запрос;
 
 //4
 Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
 Запрос.Текст = "ВЫБРАТЬ
 | Док.Товар КАК Товар,
 | СУММА(Док.Количество) КАК Количество
 |ПОМЕСТИТЬ ДокТЧ
 |ИЗ
 | Документ.Расходная.СписокТоваров КАК Док
 |ГДЕ
 | Док.Ссылка = &Ссылка
 |
 |СГРУППИРОВАТЬ ПО
 | Док.Товар
 |
 |ИНДЕКСИРОВАТЬ ПО
 | Товар
 |;
 |
 |////////////////////////////////////////////////////////////////////////////////
 |ВЫБРАТЬ
 | Остатки.Товар.Представление КАК ТоварПредставление,
 | Остатки.КоличествоОстаток
 |ИЗ
 | РегистрНакопления.ОстаткиТоваров.Остатки(
 | &ТочкаИтогов,
 | Товар В
 | (ВЫБРАТЬ
 | ДокТЧ.Товар
 | ИЗ
 | ДокТЧ КАК ДокТЧ)) КАК Остатки
 |ГДЕ
 | Остатки.КоличествоОстаток < 0
 |;
 |
 |////////////////////////////////////////////////////////////////////////////////
 |ВЫБРАТЬ
 | ДокТЧ.Товар
 |ИЗ
 | ДокТЧ КАК ДокТЧ";
 Запрос.УстановитьПараметр("Ссылка", Ссылка);
 
 //5
 Запрос.УстановитьПараметр("ТочкаИтогов", Новый Граница(МоментВремени(), ВидГраницы.Включая)); 
 
 ПакетРезультатов = Запрос.ВыполнитьПакет();
 РезультатЗапроса = ПакетРезультатов[1];
 
 Если НЕ РезультатЗапроса.Пустой() Тогда
  //6
  Отказ = Истина;
  
  Выборка = РезультатЗапроса.Выбрать();
  Пока Выборка.Следующий() Цикл
   Сообщение = Новый СообщениеПользователю;
   Сообщение.Текст = "Мало товара " + Выборка.ТоварПредставление + " нужно еще " + (-Выборка.КоличествоОстаток);
   Сообщение.Сообщить(); 
  КонецЦикла;  
 КонецЕсли; 
 
 Если Отказ Тогда
  Возврат;
 КонецЕсли; 
 
 //12
 Блокировка = Новый БлокировкаДанных;
 //13
 ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.СтоимостьТоваров");
 ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
 //14
 ЭлементБлокировки.ИсточникДанных = ПакетРезультатов[2] ;
 //15
 ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Товар", "Товар");
 Блокировка.Заблокировать(); 
 
 //16
 Если Режим = РежимПроведенияДокумента.Оперативный Тогда
  Движения.СтоимостьТоваров.Очистить();
  //17
  Движения.СтоимостьТоваров.БлокироватьДляИзменения = Истина;
  движения.СтоимостьТоваров.Записать();
 КонецЕсли; 
 
 //7
 Запрос.Текст = "ВЫБРАТЬ
 | ДокТЧ.Товар КАК Товар,
 | ДокТЧ.Количество КАК Количество,
 | СтоимостьТоваров.Партия,
 | СтоимостьТоваров.КоличествоОстаток,
 | СтоимостьТоваров.СтоимостьОстаток
 |ИЗ
 | ДокТЧ КАК ДокТЧ
 | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СтоимостьТоваров.Остатки(
 | &ТочкаИтоговДляСебестоимости,
 | Товар В
 | (ВЫБРАТЬ
 | ДокТЧ.Товар
 | ИЗ
 | ДокТЧ КАК ДокТЧ)) КАК СтоимостьТоваров
 | ПО ДокТЧ.Товар = СтоимостьТоваров.Товар
 |
 |УПОРЯДОЧИТЬ ПО
 | СтоимостьТоваров.Партия.МоментВремени
 |ИТОГИ
 | МИНИМУМ(Количество)
 |ПО
 | Товар";
       
 //8
 Запрос.УстановитьПараметр("ТочкаИтоговДляСебестоимости", МоментВремени());
 
 //9
 Движения.СтоимостьТоваров.Очистить();
 
 //10
 РезультатЗапроса = Запрос.Выполнить();
 ВыборкаТовар = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
 
 Пока ВыборкаТовар.Следующий() Цикл
  
  ОсталосьСписать = ВыборкаТовар.Количество;
  
  ВыборкаПартия = ВыборкаТовар.Выбрать();
  Пока ВыборкаПартия.Следующий() И ОсталосьСписать <> 0 Цикл
   
   Списать = МИН(ОсталосьСписать, ВыборкаПартия.КоличествоОстаток);
   
   Движение = Движения.СтоимостьТоваров.ДобавитьРасход();
   Движение.Период = Дата; 
   Движение.Товар = ВыборкаПартия.Товар;
   Движение.Партия = ВыборкаПартия.Партия;
   Движение.Количество = Списать;
   Движение.Стоимость = Списать / ВыборкаПартия.КоличествоОстаток * ВыборкаПартия.СтоимостьОстаток;
   
   ОсталосьСписать = ОсталосьСписать - Списать;
   
  КонецЦикла; 
  
 КонецЦикла; 
 
 //11
 Движения.СтоимостьТоваров.Записывать = Истина;
КонецПроцедуры

Сохранение и выгрузка картинки (в форме элемента справочника)

Добавлены реквизиты в справочник: «ДанныеКартинки» (Тип «ХранилищеЗначения») и «ИмяКартинки» (Тип «Строка»).

На форму добавлен реквизит «СсылкаНаКартинку» (Тип «Строка», элемент формы имеет вид «Поле картинки»).

// обработчики событий формы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	СсылкаНаКартинку = ПолучитьНавигационнуюСсылку(Объект.Ссылка, "ДанныеКартинки");
	
КонецПроцедуры

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	
	Если ЭтоАдресВременногоХранилища(СсылкаНаКартинку) Тогда
	
		ТекущийОбъект.ДанныеКартинки = Новый ХранилищеЗначения(ПолучитьИзВременногоХранилища(СсылкаНаКартинку));
	
	КонецЕсли; 
	
КонецПроцедуры

// загрузка картинки
&НаКлиенте
Процедура ЗагрузитьКартинку(Команда)
	
	ОписаниеОповещенияОЗавершении = Новый ОписаниеОповещения("ОбработатьВыборФайла", ЭтотОбъект); 
	НачатьПомещениеФайла(ОписаниеОповещенияОЗавершении, , , ИСТИНА, УникальныйИдентификатор);
	
КонецПроцедуры

&НаСервере
Процедура ОбработатьВыборФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры)

	Если НЕ Результат Тогда
		Возврат;
	КонецЕсли; 
	МассивИзВыбранногоИмениФайла = СтрРазделить(ВыбранноеИмяФайла, "\");
	Объект.ИмяКартинки = МассивИзВыбранногоИмениФайла[МассивИзВыбранногоИмениФайла.Количество() - 1];
	СсылкаНаКартинку = Адрес;

КонецПроцедуры

// сохранение картинки
&НаКлиенте
Процедура ВыгрузитьКартинку(Команда)
	
	Режим = РежимДиалогаВыбораФайла.ВыборКаталога;
	ДиалогВыбораФайла = Новый ДиалогВыбораФайла(Режим);
	
	ОписаниеОповещения = Новый ОписаниеОповещения("ОбработкаВыбораКаталогаДляВыгрузки", ЭтотОбъект);
	ДиалогВыбораФайла.Показать(ОписаниеОповещения);
	
КонецПроцедуры

&НаКлиенте
Процедура ОбработкаВыбораКаталогаДляВыгрузки(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт

	АдресКартинки = ПолучитьНавигационнуюСсылку(Объект.Ссылка, "ДанныеКартинки");
	
	ПолноеИмяФайла = "" + ВыбранныеФайлы[0] + "\" + Объект.ИмяКартинки;
	
	ПолучитьФайл(АдресКартинки, ПолноеИмяФайла, ЛОЖЬ);
	
КонецПроцедуры