Базовый курс. Домашнее задание №5
Второе задание по 1-му блоку базового курса.
Для выполнения рекомендуется изучить следующие главы 1-го блока.
Глава 4. Синтакс-помощник
Глава 5. Свойства конфигурации
Глава 6. Подсистемы
Глава 7. Константы
Глава 8. Справочники
К сожалению, у Вас недостаточно прав для просмотра этой записи. Если Вы еще не залогинены на сайте — залогиньтесь. Если Вы оплачивали курс, у Вас активирован токен доступа, Вы залогинены, но Вы видите эту запись — напишите нам на e-mail поддержки.
Задание сделал. Проверку и создание пользователя, получение списка вариантов обеда и запись выбора поместил в общий модуль “Сервер + Вызов сервера”.
Были сложности с передачей значений ссылочных типов между клиентом и сервером (в итоге передача сделана на уровне примитивных типов и универсальных коллекций).
Сейчас буду смотреть решение.
Задание выполнил. Буду смотреть недочеты.
Домашнее задание №5 выполнено.
В модуле управляемого приложения в методе ПередНачаломРаботыСистемы проверяем (с помощью функции серверного общего модуля) есть/нет текущий пользователь в справочнике Пользователи. Если нет такого пользователя, то с помощью функции серверного общего модуля добавляем данного пользователя. Если пользователь с флагом Администратор, то график работы для него не проверяем, в противном случае проверяем и отказываем во входе, если необходимо.
В методе ПриНачалеРаботыСистемы предлагаем выбор вариантов обеда с помощью списка значений с пометка. Сам список формируем в функции серверного общего модуля, где в качестве значений записаны элементы справочника ВариантыОбедов.
После выбора пользователем значений вариантов обеда, сохраняем выбор (с помощью сервреной процедуры общего модуля) в справочнике ОбедыПользователей.
При выходе, если пользователь не администратор, проверяем окончание графика работы, и если необходимо предлагаем отказаться от выхода из системы.
Задание выполнила, особых затруднений не было. Из модуля управляемого приложения происходит вызов процедур общего модуля с назначенными свойствами Сервер и Вызов сервера.
<code>
Процедура ПроверимНаличиеПользователя(ПризнакАдмина) Экспорт
// если пользователя нет в справочнике, создадим его
// вернем значение примитивного типа для сравнения
Польз= ПользователиИнформационнойБазы.ТекущийПользователь();
ЭлСпр= Справочники.Пользователи.НайтиПоНаименованию(Польз.Имя);
Если ЭлСпр = Справочники.Пользователи.ПустаяСсылка() тогда
ЭлСпр=Справочники.Пользователи.СоздатьЭлемент();
ЭлСпр.Наименование= Польз.Имя;
ЭлСпр.Записать();
КонецЕсли;
ПризнакАдмина=ЭлСпр.Администратор;
КонецПроцедуры // ПроверимНаличиеПользователя()
Процедура ПолучитьВремя(ИмяКонстанты,Время) Экспорт
Время= Константы[ИмяКонстанты].Получить();
КонецПроцедуры
Процедура ВариантыОбедовОткрытьНаСервере(СписокЗначенийОбед) Экспорт
//заполняем список значений для выбора
Выборка=Справочники.ВариантыОбедов.Выбрать();
Пока Выборка.Следующий() Цикл
Если Не Выборка.ПометкаУдаления Тогда
СписокЗначенийОбед.Добавить(Выборка.Наименование);
КонецЕсли;
КонецЦикла;
КонецПроцедуры // ()
Функция ПолучитьПользователя()
//возвращает ссылку на справочник Пользователи
Польз= ПользователиИнформационнойБазы.ТекущийПользователь();
ЭлПольз= Справочники.Пользователи.НайтиПоНаименованию(Польз.Имя);
Возврат(ЭлПольз);
КонецФункции // ПолучитьИмяПользователя()
Функция СегодняВыбирали() Экспорт
// Повторно обед выбирать не надо
ЭлПольз= ПолучитьПользователя();
ТекДата=НачалоДня(ТекущаяДата());
Отбор = Новый Структура(“Дата”, ТекДата);
Обеды=Справочники.ОбедыПользователей.Выбрать(,ЭлПольз,Отбор);
Если Обеды.Следующий() Тогда
Возврат(Истина);
Иначе
Возврат (Ложь);
КонецЕсли;
КонецФункции // СегодняВыбирали()
Процедура ОбедыПользователяЗаписатьНаСервере(ГлОбед) Экспорт
ТекДата=НачалоДня(ТекущаяДата());
ЭлПольз= ПолучитьПользователя();
Для каждого вар Из ГлОбед Цикл
ЭлОбед=Справочники.ОбедыПользователей.СоздатьЭлемент();
ЭлОбед.Дата=ТекущаяДата();
ЭлОбед.ВариантОбеда= Справочники.ВариантыОбедов.НайтиПоНаименованию(вар);
ЭлОбед.Владелец=ЭлПольз;
ЭлОбед.Записать();
КонецЦикла;
КонецПроцедуры
</code>
Задание выполнил.
Делал долго , посмотрев решение все переделал.
Задание выполнил. Спасибо синтаксис-помощнику.
Задание выполнила. Особых проблем не возникло.
Возник вопрос как лучше определить для текущего пользователя является ли он администратором?
Но самой большой проблемой является то что 8.2 постоянно закрывается с ошибкой связи с чем отладка почти невозможна.
По проверке администратора – посмотрите решение ДЗ.
Какой у вас используется антивирус (нужна его версия)?
KIS 2011 версия 11.0.1.400
См. новую запись “Осторожно, 1С”.
Задание выполнил. Синхранизацию справочника Пользовтаели и пользовтелей ИБ реализовал по анлогии как сделано УТ 11. Единственно непонятно почему в конфигурациях на 8.1 инициализация парамтеров сеанса происходила при запуске системы, а сейчас это реализовно – инициализация параметра сеанса происходит при первом обращении к нему.
В 8.2 также инициализация параметров сеанса происходит при старте в модуле сеанса.
Однако, если параметр неинициализирован, то система дает еще один шанс – повторно обращается к методу УстановкаПараметровСеанса(). И если и сейчас параметр не установлен, то выдается ошибка.
ДЗ№5 Выполнил. Для реализации алгоритма использовал модуль управляемого приложения и общий модуль. Все обращения к справочникам реализованы в экспортных процедурах и функциях общего модуля. Для общего модуля установлены флаги: Сервер и Вызов сервера. Описывать процедуры и функции не буду, они во многом похожи на представленные другими участниками. “Эталонное” решение посмотрю завтра и сравню со своим. Есть некоторые сложности с разделением кода на сервере и клиенте, но главная проблема – это свободное время, вернее его отсутствие.
Задание сделал. Долго разбирался почему в общий управляемый модуль не передается СписокЗначений. Потом сделал его содержимое ссылками и все заработало. Больше сложностей не было.
Задание выполнил. Возникли некоторые затруднения с добавление роли для пользователя. Видел уроки помогли.
Возник вопрос: при множественном выборе вариантов обеда я создаю каждый раз новый элемент в цикле. А можно как-то разом создать несколько новых элементов в справочнике. Что-то типа “пакетного” создания.
И еще почему в коде
Набор = Константы.СоздатьНабор(ИменаКонстант);
Набор.Прочитать();
Набор = Константы.СоздатьНабор(“НачалоРабочегоДня”); Набор.Прочитать();
В набор заносятся все константы, а не одна?
> А можно как-то разом создать несколько новых элементов в справочнике.
Нет, нельзя
Хотя эта возможность была бы актуальной, иногда в базу приходится грузить миллионы записей.
Давно уже просим об этом разработчиков, возможно когда-нибудь появится возможность.
>В набор заносятся все константы, а не одна?
Набор – это все константы.
А вот читаться значения будут только указанных. В вашем случае только “НачалоРабочегоДня”.
> Набор – это все константы.
А вот читаться значения будут только указанных. В вашем случае только «НачалоРабочегоДня».
Да, точно. Не заметил, что в свойство Набора попадают все возможные константы, а вот читаются, только переданные
Здравствуйте. С заданием справился затруднений не возникло. Но хотелось бы уточнить. В ДЗ4 было сказано, что пользователь может выбрать несколько вариантов обедов, а в ДЗ5 говорится о о создании реквизитов Дата и ВариантОбед. если это Реквизиты объекта тогда получается только по одному значению. правильно понял, сделав справочник ОбедыПользователей такой структурой: реквизит справочника – Дата и таб. часть, добавив туда реквизит ВариантОбеда?
Нет, не совсем так.
Структура справочника “Обеды пользователей” это реквизиты Дата и Вариант обеда.
Если пользователь делает множественный выбор создается несколько элементов этого справочника.
Можете скачать обновленную формулировку ДЗ №5, там этот момент учтен.
Спасибо Евгений. Скачал, доделал как надо. Готово мастер:)
Отлично :)
Отлично! :)
Появившиеся решения ДЗ 5 ещё не читал.
1. Перед началом работы системы вызывается функция ПолучитьУстановитьПараметрыНачалаРаботы(ДатаВремяРазрешить) общего модуля ОбщийМодуль1 (флаги “Сервер”, “Вызов сервера”), которая должна возвращать ссылку на текущего пользователя и разрешение на начало работы.
В функции ПолучитьУстановитьПараметрыНачалаРаботы() первоначально вызывается функция ПолучитьТекущегоПользователяИБ() общего модуля ПолныеПрава(флаги “Сервер”, “Привилегированный”), которая возвращает имя текущего пользователя информационной базы. Привилегированный режим необходим, т.к. имя доступно только для пользователя с полными правами.
Далее ищем по наименованию пользователя в справочнике, при необходимости создаём нового, затем определяем разрешение на начало работы. Структура из ссылки на пользователя и разрешения на вход возвращается в модуль приложения. Если есть разрешение на вход, ссылка на пользователя записывается в переменную глТекущийПользователь.
Определение разрешения на начало работы с использованием флагом “Администратор” имеет следующую трудность: при первом запуске нет пользователей с установленным флагом, а константы начала и окончания рабочего дня также не установлены – в базу никто войти не сможет. Поэтому пришлось принять допущение, что кроме пользователей с флагом “Администратор” возможность входить в базу имеет также и пользователь с полными правами.
Получается такая схема работы при первом запуске: первым входим пользователь с полными правами, устанавливает нормальное рабочее время, затем в позволенное время входят прочие пользователи. При входе происходит автоматическое создание элементов справочника “Пользователи”, в которых пользователь с полными правами устанавливает (кому следует) флаг “Администратор”).
2. Для выбора обедов пользователем в конфигурацию добавлена общая форма “ФормаПодбораОбедов”. У формы снят флаг “Использовать стандартные команды”. В форме добавлен реквизит “СписокОбедов” в качестве основного, тип “Динамический список”, основная таблица – “Справочник.ВариантыОбедов”.
Реквизит отображается в форме в виде таблицы. У таблицы установлены флаги “Режим выбора”, “Множественный выбор”, режим выделения: “Множественный”.
При начале работы форма подбора обедов открывается модально:
МассивВыборОбеда = ОткрытьФормуМодально(“ОбщаяФорма.ФормаПодбораОбедов”);
Я показываю в форме все элементы, в т.ч. помеченные на удаление (ведь не сказано, что пользователь не должен их видеть). Пользователь может добавить в форме новые варианты и даже сразу их выбрать.
При закрытии форма возвращает массив выбранных ссылок на вырианты обедов. Для обработки массива вызывается серверная процедура. Т.к. массив не удётся передать, он был переписан в стуктуру. Также в качестве параметров передаются глТекущийПользователь и начало текущего дня.
На сервере выполняется проверка на пометку удаления и запись элементов в подчиненный справочник.
Из вариантов обедов, для которых была осуществлена запись, формируется список подтвержденных заказов; из непрошедших – список неподтвержденных заказов. Списки помещаются в структуру и возвращаются на Клиент, где выдаётся соответствующее Предупреждение.
3. Реализация обедов пользователей в виде подчиненного справочника мне кажется не вполне подходящим решением. Для начала, возникает неудобство в наименованием элементов, т.к., по сути, оно должно дублировать информацию, которая содержится в реквизитах Дата и ВариантОбеда. Это уже настораживает. Кроме того, пользователь может несколько раз за день проходить эту процедуру, и в другой раз выбрать другой набор вариантов – в таком случае, придётся анализировать имеющиеся элементы подчинённого справочника и невыбранные помечать на удаление. Наконец, трудно представить, чтобы эти элементы могла быть выбраны где-либо в качестве реквизитов. Таким образом, правильнее было бы реализовать в виде регистра сведений. Измерения – Пользователь, ВариантОбеда и Дата, без ресурсов.
Проверки на дублирование элементов в подчинённом справочнике реализовывать не стал, т.к. хотелось бы всё же переделать на регистр сведений. Пока что времени на реализцию через регистр не было, но если будет такое продолжение в следующем ДЗ, то это было бы интересно
// Комментарий про регистр сведений заметил позже.
4. Не удалось выполнить проверку на пометку удаления в форме подбора обедов. Понятно, что на клиенте нет доступа к реквизиту ПометкаУдаления справочника. Однако пометка удаления отображается на форме, стало быть должен быть доступ к ней через динамический список. Но этого мне реализовать не удалось, видимо где-то что-то пропустил.
Сделал сложностей не возникло. Только один вопрос. Я создал общий модуль. С флагом Сервер. я так понимаю что все что написано в этом модуле будет выполнятся на сервере. но я попробовал написать в модуле процедуру с препроцессором НаСервереБезКонтекста , после чего на данную функцию ругалось при выполнении кода. Это правильное поведения ?
Да, это правильное поведение.
Во-первых, директива НаСервереБезКонтекста имеет смысл только для модулей форм. И это логично, ведь только в формах может быть контекст.
Во-вторых, в таком общем модуле нет смысла использовать директивы, в нем все процедуры будут серверными.
Я так и думал. Спасибо за ответ.
Спасибо. Я и забыл что у меня наименование попало в поиск по строке. Как только удалил все заработало. С выборкой тоже понятно. Буду ждать работу с Запросом.
А зачем ее ждать :)
Нужно применять в 6-ом ДЗ, для этого есть заключительные главы 1-го блока.
Задание сделано.
Весь код сосредоточен в двух модулях:
1. Модуль управляемого приложения.
2. Общий модуль со свойствами Сервер и Вызов сервера.
Созданы все объекты метаданных необходимые для выполнения задания.
В общем модуле описаны функции проверки пользователя, проверки рабочего времени для входа в систему, формирования списка меню обедов из справочника, создание элементов подчинённого сравочника.
Также были использованы обработчики событий глобального контекста в модуле управляемого приложения:
ПередНачаломРаботыСистемы() ;
ПриНачалеРаботыСистемы() ;
ПередЗавершениемРаботыСистемы() ,
в которых вызываются соответствующие процедуры и фукции, определённые в общем модуле.
ДЗ выполнил.
Много времени пришлось потратить с разбором взаимных вызовов различных модулей. Пришлось развернуть конфигурацию бухгалтерии и по ней понять что из чего вызывается и в какой последовательности. К сожалению все равно идеального понимания пока этого вопроса нет. Буду надеяться что в разборе этого домашнего задания окончательно все проясниться.
Добрый день, наконец-то добрался до выполнения домашнего задания. Надеюсь ничего страшного, что так поздно? Итак особенности выполнения:
1. Создал все необходимые справочники. При создании справочника “ОбедыПользователей” сделал длину наименования равной нулю, т.е. не использовал наименование, а у поля “Дата” свойтву “Индексировать” поставил заначение “индекстировать”. Также для справочника “ВариантыОбедов” определил форму выбора, где у основного реквизита формы, который соответствует списку вариантов обеда с помощью настройки списка сделал, чтобы не показывались помеченные на удаление элементы. Также для этого списка определил множественный выбор.
2. С пользователями и их синхронизацией проблем не возникло.
3. При проверке возможности работы, если пользователь “Администратор”, тогда вообще не проверяем время, а даем работать. Если же это простой пользователь, т.е. в ключе задачи “Менеджер”, то проверяем время. Тоже самое равносильно для выхода из системы.
4. С обедами. Вначале проверяю делал ли пользователь уже сегодня выбор обеда. Для этого использовал
Справочники.ОбедыПользователей.Выбрать(, Пользователь, Новый Структура(“Дата”, НачалоДня(ТекущаяДата())), вот здесь и пригодилась установка свойства “Индексировать” у реквизита “Дата”, иначе метод “Выбрать” не работает, выдает ошибку на третий параметр. Далее, если обеда не было, то показываем пользователю форму выбора справочника “ВариантыОбедов”, где он может выбрать вариант(ы) и при необходимости добавить.
Здесь возникла сложность с пониманием самой задачи. Евгений, поясните пожалуйста. Написано: “Результат выбора пользователя записывайте в подчиненный справочник”, а ранее: “Вариант обеда (ссылка на соответствующий справочник).
Так где всетаки правда? Реквизит “ВариантОбеда” справочника “ОбедыПользователей” должен быть типа “СправочникСсылка.ВариантыОбедов”?, но тогда нельзя записать несколько вариантов. Или же этот реквизит должен быть типа “Строка”, или же вообще у справочника “ОбедыПользователей” должна быть табличная часть, в которую можно записать сразу несколько вариантов с типом “СправочникСсылка.ВариантыОбедов”. Я сделал через строку, но могу переделать в любой.
Вот собственно и все.
Уточнение формулировки.
“• Результат выбора пользователя записывайте в справочник «ОбедыПользователей».”
Теперь все однозначно?
Не совсем, Евгений. Это было понятно и так. Не понятно в каком виде записывать результат выбора. Меня смутило то, что у справочника “ОбедыПользователей” есть реквизит “ВариантОбеда”, тип которого, как я понял, ссылка на справочник “ВариантыОбедов”. Тогда не понятно как записать в этот реквизит несколько вариантов, например пользователь выбрал рыбу и мясо, или же этот реквизит имеет тип строка? Или нужно вообще создать у справочника “ОбедыПользователей” табличную часть?
В случае множественного выбора в справочник “Обеды пользователей” пишем несколько записей.
Теперь все понятно, спасибо. Переделаю, это будет не сложно, хоть и не оптимально на мой взгляд. Лучше сделать табличную часть у элемента справочника и писать туда.
Лучше сделать регистр сведений, но мы его еще не проходили :)
Евгений, а можно немножко поподробнее про “… показываем пользователю форму выбора справочника «ВариантыОбедов»…”. Откуда вызываете форму выбора и как. У меня при попытке это организовать возникла какая-то путаница. Если пробовала вызвать из клиентского контекста, то выдавалась ошибка про недоступность метода для тонкого клиента, если из серверного тоже что-то не получалось.
В результате так и отложила до момента, когда понимание контекстов получше в голове уляжется :)
Рекомендую ознакомиться с решением 5-го домашнего задания.
Задание выполнил. При повторном выполнении того же задания в базе данных изменил порядок выполнения модулей. Наконец начал понимать что такое контекст. Во время выполнения предыдущего домашнего задания создал экспортный массив глОбед и не мог обратиться к нему из общего модуля. Теперь понял что пытался вызвать эту переменную созданную в контексте клиента в контексте сервера, из общего модуля созданного в контексте клиента данная переменная прекрасно вызывается.
&НаКлиенте
Процедура СписокВариантовОбедов() Экспорт
СписокВыбора = Новый СписокЗначений;
СписокВыбора = ОбщийМодуль1.СоздатьСписокОбедаИзСправочника();
если СписокВыбора.ОтметитьЭлементы(“Выбрать обеды”) тогда
Для Каждого Эл из СписокВыбора цикл
если Эл.Пометка Тогда
глОбед.Добавить(Эл.Значение);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры // СписокВариантовОбедов()
вынес в общий клиентский модуль и все прекрасно работает (раньше создавал промежуточное значение МассивОбеды и его присваивал глОбед).
Имя текущего пользователя определяю с помощью функции ИмяПользователя(). Если в сисетме нет такого пользователя ( ищу с помощью метода Справочники.Пользователи.НайтиПоНаименованию(ИмяПользователя,Истина), т.е по точному совпадению наименования), создаю новый элемент с наименованием равным строке возвращаемой функцией ИмяПользователя(). Время занес в константу типа Дата и составом Время. Проверки входа реализовал так
ВремяНачала = ОбщийМодуль1.ПолучитьЗначениеИзКонстанты(“ВремяНачалаРабочегоДня”);
ЧислоВремяНачала = Час(ВремяНачала)*3600 + Минута(ВремяНачала)*60 + Секунда(ВремяНачала);
ДатаВремяНачала = НачалоДня(ТекущаяДата())+ЧислоВремяНачала;
если ДатаВремяНачала>ТекущаяДата() тогда
Предупреждение(“Вход в систему запрещен”,10,”Вход в систему”);
отказ = Истина;
КонецЕсли;
где ОбщийМодуль1 – выполняется в контексте сервера. Точно так же реализовал и функцию проверки окончания работы системы.
Работа со справочниками тоже практически не вызвало затруднений после того как разобрался с контекстом выполнения. Правда закралась такая ошибка. Создал справочник ОбедыПользователей подчиненный справочнику Пользователигде хранятся результаты выбранных пользователем обедов пользователей. Создал у него 2 реквизита (индексированный Дата,для проверки наличия заказанных пользователем блюд, и ВариантОбеда, ссылка на соответствующий справочник). Сформировал , посмотрел что все работает и понял, что зря оставил поле Наименование. С помощью внешней обработки очистил все поля данного справочника. Открыл конфигуратор и сделал длину наименования равной 0. И при повторной попытке зайти в режим предприятия он сообщает мне что у меня ошибка “Справочник.ОбедыПользователей: Указано неверное поле для ввода по строке: Наименование”. Форму я для данного справочника не создавал, они все формируются динамически, проверка заполнения стоит “Не проверять”, Полнотекстовый поиск стоит “Не использовать”, элементов данный справочник не имеет. Где мне надо еще подчистить? Использую движок 8.2.12.80, надо может на 8.2.12.96 попробовать конечно но нет под рукой.
И еще один вопрос. Делаю стандартный обход выборки из 10 элементов допустим
Выборка = Справочники.Контрагенты.Выбрать();
пока Выборка.Следующий() цикл
и вдруг на 5 элементе я должен перейти в начало выборки. Как это делается? Я вынужден буду создавать новую выборку
Выборка1 = Справочники.Контрагенты.Выбрать();
пока Выборка1.Следующий() цикл
или как мне надо поступить?
> Где мне надо еще подчистить?
Нужно убрать из полей ввода по строке “Наименование”. Например, в окне редактирования объекта на закладке “Формы” (внизу).
>и вдруг на 5 элементе я должен перейти в начало выборки. Как это делается?
Желательно реализовывать однопроходные алгоритмы.
Однако, если требуется перейти в начало выборки, то при использовании приведенного кода нужно будет заново вызывать метод “Выбрать”.
Но это очень плохо с точки зрения производительности, так как по сути это новый запрос к базе данных.
Гораздо правильнее в этом случае использовать запрос и выборку его результатов. У типа данных “ВыборкаИзРезультатаЗапроса” есть метод Сбросить(), который позволяет спозиционироваться на первом элементе выборки. В этом случае повторного обращения к БД не будет происходить.
Наконец-то осилила ДЗ№5! :) С налету решить не получилось, заминка – не могла найти как обратиться к текущему пользователю системы (даже Синтаксис-Помощник не смог помочь, все же еще плохо ориентируюсь в нем), пришлось подсмотреть у уже отписавшихся, оказалось все просто ИмяПользователя() :) При решении пришлось еще разок пересмотреть уроки посвященные модулю приложения, модуля сеанса и общим модулям. После их просмотра утвердилась в мысли, что буду использовать только модуль приложения и общий модулю (с признаком “Вызов сервера”).
Алгоритм получился таким:
1. В общем модуле “ОбщийМодульСервер” прописала такие функции и процедуры:
функция ПолучитьЗначениеКонстанты(ВыбКонстанта), ВыбКонстанта – признак (1 – нач.дня, 2 – кон.для), обращаюсь через метод Получить() к константам и сравниваю с текущим временем ТекВремя = Формат(ТекущаяДата(),”ДЛФ=В”) , тут же прописала проверку пользователя на признак “Администратор” , пользователя определяю через функцию “ПроверкаПользователя()”, возвращаю ИСТИНА если время подходящие и не админ, иначе ЛОЖЬ
функция ПроверкаПользователя() , через ИмяПользователя() нахожу имя тек.пользователя , далее через НайтиПоНаименованию делаю проверку в справочнике “Пользователи”, если нет такого происходит запись. Функция возвращает Пользователя – тип Спр-к.Объект
функция ПолучитьСписокБлюд() , из спр-ка “Варианты обедов” формирует список значений, не включая помеченные на удаление, и возвращает его .
функция ПроверкаОбедаПользователя(), проверяет в справочнике “Обеды пользователей” ,через использование метода Выбрать к подчиненным спр-кам Справочники.ОбедыПользователей.Выбрать(,Пользователь.ссылка) наличие за текущую дату записей у текущего пользователя (пользователя нахожу через функцию ПроверкаПользователя() ), возвращает ИСТИНА если найдена хоть одна запись иначе ЛОЖЬ.
Процедура ЗаписьВыбранныхБлюд(МассивБлюд), проверяю если у пользователя в спр-ке “Обеды пользователе” уже есть записи (через функцию ПроверкаОбедаПользователя()), тогда их удаляю и записываю новые, иначе просто записываю новые элементы.
2. В модуле приложений прописала такие процедуры и определила переменные:
Перем глОбед Экспорт;
Перем глРежим Экспорт;
Процедура ПередНачаломРаботыСистемы(Отказ)
Ответ=ОбщийМодульСервер.ПолучитьЗначениеКонстанты(1);
Если Ответ=Истина Тогда
Предупреждение(“ЕЩЕ РАНО ОЧЕНЬ!!!”);
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Процедура ПередЗавершениемРаботыСистемы(Отказ)
Ответ=ОбщийМодульСервер.ПолучитьЗначениеКонстанты(2);
Если Ответ=Истина Тогда
ОтветНаВопрос = Вопрос(“Еще не закончился рабочий день!ЖЕлаете выйти?”,глРежим,0);
Если ОтветНаВопрос = КодВозвратаДиалога.Нет Тогда
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ПриНачалеРаботыСистемы()
Если ОбщийМодульСервер.ПроверкаОбедаПользователя() = Ложь Тогда
ВыводимМеню();
Иначе
ОтветНаВопрос = Вопрос(“Вы уже заказывали обед! Желаете перевыбрать?”,глРежим,0);
Если ОтветНаВопрос = КодВозвратаДиалога.Да Тогда
ВыводимМеню();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ВыводимМеню()
СписокБлюд = Новый СписокЗначений;
СписокБлюд = ОбщийМодульСервер.ПолучитьСписокБлюд();
Если СписокБлюд.ОтметитьЭлементы(“Что будете на обед?”) Тогда
Для каждого Элемент Из СписокБлюд Цикл
Если Элемент.Пометка Тогда
глОбед.Добавить(Элемент.Значение);
КонецЕсли;
КонецЦикла;
глОбед = Новый Массив;
глРежим = РежимДиалогаВопрос.ДаНет;
Не до конца, вставилась последняя процедура, вот :
Процедура ВыводимМеню()
СписокБлюд = Новый СписокЗначений;
СписокБлюд = ОбщийМодульСервер.ПолучитьСписокБлюд();
Если СписокБлюд.ОтметитьЭлементы(“Что будете на обед?”) Тогда
Для каждого Элемент Из СписокБлюд Цикл
Если Элемент.Пометка Тогда
глОбед.Добавить(Элемент.Значение);
КонецЕсли;
КонецЦикла;
ОбщийМодульСервер.ЗаписьВыбранныхБлюд(глОбед);
КонецЕсли;
КонецПроцедуры
Задание выполнил.
Особенности
1. Большинство кода оформил в общем модуле (сервер, вызов сервера)
2.Пользователя создавал, если не найден
Функция ТекПользователь() Экспорт
ИмяПользователя = ИмяПользователя();
Пользователь = Справочники.Пользователи.НайтиПоНаименованию(ИмяПользователя,Истина);
Если Пользователь = Справочники.Пользователи.ПустаяСсылка() Тогда
НовыйПользователь = Справочники.Пользователи.СоздатьЭлемент();
НовыйПользователь.Наименование = ИмяПользователя;
НовыйПользователь.Записать();
ИмяПользователя = НовыйПользователь.Ссылка
КонецЕсли;
Структура = Новый Структура(“Пользователь,Администратор”,Пользователь,Пользователь.Администратор ) ;
Возврат Структура
КонецФункции
3. Для сравнения дат использовал серверную неЭкспортную функцию
Функция ДобавимНуль(ВремяСтрокой)
нач = Найти(ВремяСтрокой,”:”);
Если нач = 2 Тогда
ВремяСтрокой = “0”+ВремяСтрокой
КонецЕсли;
Возврат ВремяСтрокой
КонецФункции
Она вызывалась
…
ВремяСтрокой = Формат (Константы.НачалоРаботы.Получить(), “ДЛФ=T”);
НачалоРаботы = ДобавимНуль(ВремяСтрокой);
4.Варианты обеда через список
Функция ЗаполнимМассив() Экспорт
Список = Новый СписокЗначений;
Выборка =Справочники.ВариантыОбедов.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.ПометкаУдаления Тогда
Продолжить
КонецЕсли;
Список.Добавить(Выборка.Ссылка);
КонецЦикла;
Возврат Список
КонецФункции
…
Список = ОМнаСервере.ЗаполнимМассив();
//далее выбор из списка в модуле Упр.приложения
…
Если Список.ОтметитьЭлементы(“Выберите вариант(-ты) обеда”)
5.Запись выбранных обедов произвожу в случае отсутствия их у пользователя на эту дату:
Процедура ЗаполнимОбедыПользователя(ТекущийПользователь,ГлОбед) Экспорт
Отбор = Новый Структура(“Дата”,НачалоДня(ТекущаяДата()));
Выборка =Справочники.ОбедыПользователей.Выбрать(,ТекущийПользователь,Отбор);
Если Выборка.Следующий() ТОгда
Сообщить(“На сегодня Вам обед заказан!”);
Иначе
Для сч=0 По ГлОбед.Вграница() Цикл
НовыйЭлСпр = Справочники.ОбедыПользователей.СоздатьЭлемент();
НовыйЭлСпр.Наименование =””+ТекущийПользователь+” “+Формат(ТекущаяДата(), “ДФ=dd/MM/yy”) ;
НовыйЭлСпр.Владелец =ТекущийПользователь ;
НовыйЭлСпр.Дата = НачалоДня(ТекущаяДата());
НовыйЭлСпр.ВариантыОбеда = ГлОбед[сч];
НовыйЭлСпр.Записать();
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Задание сделала.
Не использовала ни модуль сеанса, ни параметры сеанса. Только модуль управляемого приложения и общий модуль с галками «Сервер», «Вызов сервера», «Привилегированный». Оказалось не так просто разделять клиентскую и серверную часть: одно не работает там, другое – здесь. Пришлось писать в общем модуле кучу маленьких функций и процедур, потому что для любого общения с пользователем надо вернуться в модуль приложения, а потом вызывать уже проще новую серверную процедуру.
*********************************
Процедура ПередНачаломРаботыСистемы(Отказ)
ОбщийМодульДляСерверных.УстановитьТекущегоПользователя(глТекПользователь);
Если (Не ОбщийМодульДляСерверных.РабочееВремя())и(Не ОбщийМодульДляСерверных.ЭтотПользовательАдминистратор(глТекПользователь) ) тогда
Предупреждение(“Нельзя работать в нерабочее время!”, 10);
Отказ=Истина;
КонецЕсли;
КонецПроцедуры
*********************************
Процедура ПриНачалеРаботыСистемы()
СЗ=Новый СписокЗначений;
Если ОбщийМодульДляСерверных.ПроверкаОбедов(глТекПользователь) тогда // есть ли заказы у текущего пользователя на текущую дату
Режим = РежимДиалогаВопрос.ДаНет;
Текст = “Уже существуют варианты обеда на текущую дату. Заменить?”;
Ответ = Вопрос(Текст, Режим, 0);
Если Ответ = КодВозвратаДиалога.Да Тогда
ОбщийМодульДляСерверных.УдалитьТекОбеды(глТекПользователь);
Иначе
Возврат;
КонецЕсли;
КонецЕсли;
ОбщийМодульДляСерверных.ВариантыОбедов(глТекПользователь,СЗ); // из справочника в список значений
Зн = СЗ.ОтметитьЭлементы (“Что Вы хотите на обед?”);
ОбщийМодульДляСерверных.ЗанестиОбеды(глТекПользователь,СЗ); ); // из списка значений в справочник
КонецПроцедуры
*********************************
С константами хранящими границы рабочего дня немного соригинальничала: они у меня строковые с маской «99:99:99» и проверкой чтоб часы от 0 до 24, а остальное до 60. Я легко извлекаю из них отдельно часы, минуты и секунды и с ними работаю, как в 4-ом ДЗ, собирая дату из частей функцией Дата(Г,М,Д,Ч,Мин,Сек).
С работой с пользователями немного помучалась и полазила по типовой конфигурации, разобралась, там сделано через параметры сеанса, но я решила в эти дебри не лезть.
*********************************
Процедура УстановитьТекущегоПользователя(ТекущийПользователь) Экспорт
ИмяПользователя = ИмяПользователя();
Если ПустаяСтрока(ИмяПользователя) Тогда // пользователь не авторизовался
ИмяПользователя = “НеАвторизован”;
КонецЕсли;
ТекущийПользователь = Справочники.Пользователи.ПустаяСсылка();
Если НЕ ПустаяСтрока(ИмяПользователя) Тогда
ТекущийПользователь = Справочники.Пользователи.НайтиПоКоду(ИмяПользователя);
КонецЕсли;
Если ТекущийПользователь = Справочники.Пользователи.ПустаяСсылка() Тогда
Спр=Справочники.Пользователи.СоздатьЭлемент();
Спр.Код=ИмяПользователя;
Спр.Наименование=ИмяПользователя;
Спр.Записать();
ТекущийПользователь = Спр.Ссылка;
КонецЕсли;
КонецПроцедуры
Задание выполнено. Созданы все необходимые справочники и константы.
Далее, создан общий модуль с признаками “Сервер” и “Вызов сервера”. В нем определены все процедуры и функции, необходимые для выполнения данного ДЗ, а именно: получение констант; определение текущего пользователя (использовалось свойство глобального контекста ПользователиИнформационнойБазы); определение активности признака “Администратор” для текущего пользователя; создание новых пользователей в соответствующем справочнике (с проверкой на наличие); получение из справочника вариантов обеда для выбора пользователя; создание выбранных обедов для текущего пользователя (с проверкой на наличие).
Для меня задание оказалось не простым, с наскока не удалось забороть. Но повторный просмотр определенных видео-уроков и вдумчивая работа с синтакс-помощником помогли получить ответы на все возникшие вопросы.
Хех, не доработал с синтакс-помощником =)
Выяснил, что есть функция глобального контекста ИмяПользователя()
Задание выполнила.
Создала общий серверный модуль со свойством “вызов сервера” для работы с объектами БД. В нем создала функции по получению констант, определению у пользователя признака Администратор, получению списка вариантов доступных обедов а также добавлению выбранных вариантов в справочник ОбедыПользователей.
В параметры сеанса добавила ТекущийПользователь.
В модуле сеанса в справочнике Пользователи ищу элемент с наименованием ИмяПользователя(). Если нет такого элемента, добавляю. Определяю параметр сеанса ТекущийПользователь.
В модуле управляемого приложения в процедуре ПередНачаломРаботыСистемы для не администраторов проверяю вхождение текущего времени в интервал разрешенного времени работы.
В процедуре ПриНачалеРаботыСистемы вызываю процедуру общего модуля для формирования списка значений с доступными вариантами обедов, затем вызываю процедуру общего модуля добавления в справочник ОбедыПользователей элементов, соответствующих выбранным значениям списка.
ПередЗавершениемРаботыСистемы для не администраторов проверяю, закончился ли рабочий день.
Начало и конец рабочего дня определяю таким образом:
НачалоДня = Дата(Строка(Формат(ТекущаяДата(),”ДФ=dd.MM.yyyy”))+” “+Формат(Вспомогательный.ПолучитьКонстанту(“ВремяНачалаРаботы”),”ДЛФ=T”));
Это как-то совсем “в лоб”. Может, есть какой-то более правильный способ формирования даты из непосредственно Даты и Времени не через конкатенацию строк?
“Может, есть какой-то более правильный способ формирования даты из непосредственно Даты и Времени не через конкатенацию строк”
Безусловно есть.. если Вы сделаете
ТекущееВремя = ТекущаяДата() – НачалоДня(ТекущаяДата())
То ТекущееВремя можно уже сравнивать со временем НачалоРаботыПредприятия (только его тоже нужно сохранить в таком же формате (время как количество секунд с начала суток)
Код в “модул управляемого приложения”:
&НаКлиенте
Процедура ПередНачаломРаботыСистемы(Отказ)
Перем НачРаб, КонРаб;
старт=НачалоДня(ТекущаяДата());
тт=ОбщийМодуль4.Начало();
НачРаб=старт+Минута(тт)*60+3600*Час(тт);
тт=ОбщийМодуль4.Конец();
КонРаб=старт+Минута(тт)*60+3600*Час(тт);
Если Не ОбщийМодуль4.ПроверитьПользователя() Тогда
Если ((ТекущаяДата()<НачРаб) Или (ТекущаяДата()>КонРаб)) Тогда
ПоказатьОповещениеПользователя(“Приходите вовремя”);
Отказ=Истина;
Иначе
глОбед=ОбщийМодуль4.Выбрать();
глОбед.ОтметитьЭлементы(“Выберите что кушать”);
Если глОбед.НайтиПоЗначению(“НовыйВариант”).Пометка Тогда
НовоеБлюдо=””;
ВвестиСтроку(НовоеБлюдо, “Введите наименование нового блюда”, 25,);
Если СтрДлина(СтрЗаменить(НовоеБлюдо,” “,””))>0 Тогда
ОбщийМодуль4.СохранитьОбед(Истина,НовоеБлюдо);
КонецЕсли;
Иначе
и1=0; ИмяОбеда=””;
Для Каждого Эл из глОбед Цикл
Если Эл.Пометка Тогда
и1=и1+1;
ИмяОбеда=Эл.Значение;
КонецЕсли;
КонецЦикла;
Если и1=1 Тогда
ОбщийМодуль4.СохранитьОбед(Ложь,ИмяОбеда);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ПередЗавершениемРаботыСистемы(Отказ)
Перем КонРаб;
тт=ОбщийМодуль4.Конец();
КонРаб=НачалоДня(ТекущаяДата())+Минута(тт)*60+3600*Час(тт);
Если Не ОбщийМодуль4.ПроверитьПользователя() Тогда
Если (ТекущаяДата()>КонРаб) Тогда
Если Вопрос(“Рабочее время ещё в разгаре, вы уверены, что хотите свалить?”,РежимДиалогаВопрос.ДаНет,,,,)<>КодВозвратаДиалога.Да Тогда
Сообщить(“Отменено”);
Отказ=Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
код в “ОбщиеМодули.ОбщийМодуль4″ (с флагом серверный вызов):
Функция Начало() Экспорт
Возврат Константы.НачалоДня.Получить();
КонецФункции
Функция Конец() экспорт
Возврат Константы.КонецДня.Получить();
КонецФункции
Функция ПроверитьПользователя() экспорт
Юзер=ИмяПользователя();
Ссылка=Справочники.Пользователи.НайтиПоНаименованию(Юзер);
Если Не Ссылка=Справочники.Пользователи.ПустаяСсылка() Тогда
Возврат Ссылка.ПолучитьОбъект().Администратор;
Иначе
Права=?(Юзер=”Администратор”,Истина,Ложь);
НовыйЮзер=Справочники.Пользователи.СоздатьЭлемент();
НовыйЮзер.Наименование=Юзер;
НовыйЮзер.Администратор=Права;
НовыйЮзер.Записать();
Возврат Права;
КонецЕсли;
КонецФункции
Функция Выбрать() Экспорт
Вар = Справочники.ВариантыОбедов;
глОбед = Новый СписокЗначений;
Выборка = Вар.Выбрать(,,,);
Пока Выборка.Следующий() Цикл
Если Выборка.ПолучитьОбъект().ПометкаУдаления Тогда
Продолжить;
КонецЕсли;
Обед = Выборка.ПолучитьОбъект().Наименование;
глОбед.Добавить(СтрЗаменить(Обед,” “,””),Обед,Ложь,);
КонецЦикла;
глОбед.Добавить(“НовыйВариант”,”Нечто особенное”,Ложь,);
Возврат глОбед;
КонецФункции
Процедура СохранитьОбед(флаг, НаименованиеОбеда) Экспорт
Если флаг Тогда
НовыйЭлемент = Справочники.ВариантыОбедов.СоздатьЭлемент();
НовыйЭлемент.Наименование = НаименованиеОбеда;
НовыйЭлемент.Записать();
КонецЕсли;
Обед1=Справочники.ВариантыОбедов.НайтиПоНаименованию(НаименованиеОбеда);
Владелец=Справочники.Пользователи.НайтиПоНаименованию(ИмяПользователя());
ОбедПользователя=Справочники.ОбедыПользователей.СоздатьЭлемент();
ОбедПользователя.Владелец=Владелец;
ОбедПользователя.ВариантОбеда=Обед1;
ОбедПользователя.Дата=ТекущаяДата();
ОбедПользователя.Записать();
КонецПроцедуры
Есть конечно пара несделанных моментов (управление сохранением при повторных входах в течении раб.дня и т.п.) но это уже дело техники…
Задание Выполнил
Все действия выполняю в модуле Управляемого приложения и общем модуле с пометкой «Вызов наСервере»
В модуле Управляемого приложения в обработке «ПередНачаломРаботыСистемы»
Проверяю время запуска системы. Для этого вызываю экспортную функцию из общего модуля «ПроверкаРежима» в ней начало и конец рабочего дня берутся из констант.
В процедуре обработке «ПриНачалеРаботыСистемы()» Проверяю есть ли текущей пользователь в Справочнике.Пользователи. Для этого использую экспортную функцию из общего модуля. Значение текущего пользователя узнаю из св-ва глобального контекста «ПользователиИнформационнойБазы.ТекущийПользователь()».
Далее вызываю еще одну экспортную функцию «СформироватьСписок()» из общего модуля в которой создаю «СписокЗначений» из данных Справочника.ВариатыОбедов. Сам список потом Передаю назад в процедуру вызова . Далее вызываю Список.ОтметитьЭлементы и потом от вызываю еще одну экспортную процедуру «ЗаписатьОбедПользователя» из общего модуля, а от редактированный список передаю как параметр. Процедура «ЗаписатьОбедПользователя» создает новые элементы Справочника. ОбедыПользователей.
Для работы с объектами, не доступными в режиме тонкого клиента, создан общий модуль ОбщийМодульСервер с установленными свойствами Сервер и Вызов сервера. В модуле реализованы следующие процедуры и функции:
<code>
//================= работа с пользователями ===============
Процедура ИнициализироватьПользователя() Экспорт
ИмяПользователя = ИмяПользователя();
Если (Справочники.Пользователи.НайтиПоНаименованию(ИмяПользователя, Истина) = Справочники.Пользователи.ПустаяСсылка()) Тогда
НовыйПользователь = Справочники.Пользователи.СоздатьЭлемент();
НовыйПользователь.Наименование = ИмяПользователя;
НовыйПользователь.Записать();
Сообщить(“Создан пользователь ” + ИмяПользователя);
КонецЕсли;
КонецПроцедуры
Функция ЭтоАдминистратор() Экспорт
ТекущийПользователь = Справочники.Пользователи.НайтиПоНаименованию(ИмяПользователя(), Истина);
Если ЗначениеЗаполнено(ТекущийПользователь) Тогда
Возврат ТекущийПользователь.Администратор;
Иначе
Возврат Ложь;
КонецЕсли;
КонецФункции // ЭтоАдминистратор()
Функция ПолучитьПользователя(ИмяПользователя) Экспорт
Возврат Справочники.Пользователи.НайтиПоНаименованию(ИмяПользователя, Истина);
КонецФункции // ПолучитьПользователя()
// ======================= Обеды ==========================
Функция ПолучитьСписокВариантовОбедов() Экспорт
Меню = Новый СписокЗначений;
Выборка = Справочники.ВариантыОбедов.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.ПометкаУдаления Тогда
Продолжить;
КонецЕсли;
Меню.Добавить(Выборка.Ссылка);
КонецЦикла;
Возврат Меню;
КонецФункции // ПолучитьСписокВариантовОбедов()
Процедура ДобавитьВариантОбедаПользователю(ВариантОбеда, Пользователь) Экспорт
НужноДобавлять = Истина;
СтруктураОтбора = Новый Структура(“Дата”, НачалоДня(ТекущаяДата()));
Выборка = Справочники.ОбедыПользователей.Выбрать(, Пользователь, СтруктураОтбора);
Пока Выборка.Следующий() Цикл
Если Выборка.ВариантОбеда = ВариантОбеда Тогда
НужноДобавлять = Ложь;
Прервать;
КонецЕсли;
КонецЦикла;
Если НужноДобавлять Тогда
НовыйОбъект = Справочники.ОбедыПользователей.СоздатьЭлемент();
НовыйОбъект.ВариантОбеда = ВариантОбеда;
НовыйОбъект.Владелец = Пользователь;
НовыйОбъект.Дата = НачалоДня(ТекущаяДата());
НовыйОбъект.Записать();
КонецЕсли;
КонецПроцедуры
// =========== константы ====================
Функция ПолучитьЗначениеКонстанты(ИмяКонстанты) Экспорт
Возврат Константы[ИмяКонстанты].Получить();
КонецФункции // ПолучитьЗначениеКонстанты()</code>
В модуле управляемого приложения:
для проверки времени входа пользователя в программу использован обработчик события ПередНачаломРаботыСистемы:
<code>Процедура ПередНачаломРаботыСистемы(Отказ)
Если (НЕ ОбщийМодульСервер.ЭтоАдминистратор()) Тогда
ВремяНачала = ОбщийМодульСервер.ПолучитьЗначениеКонстанты(“НачалоРабочегоДня”);
ВремяОкончания = ОбщийМодульСервер.ПолучитьЗначениеКонстанты(“ОкончаниеРабочегоДня”);
Если (Формат(ТекущаяДата(), “ДЛФ=В; ДФ=ЧЧммсс”) < Формат(ВремяНачала, “ДЛФ=В; ДФ=ЧЧммсс”)) ИЛИ
(Формат(ТекущаяДата(), “ДЛФ=В; ДФ=ЧЧммсс”) > Формат(ВремяОкончания, “ДЛФ=В; ДФ=ЧЧммсс”)) Тогда
Предупреждение(“Сейчас нельзя заходить в систему!”);
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры</code>
для проверки времени выхода пользователя из программы использован обработчик события ПередЗавершениемРаботыСистемы:
<code>Процедура ПередЗавершениемРаботыСистемы(Отказ)
Если (НЕ ОбщийМодульСервер.ЭтоАдминистратор()) Тогда
ВремяОкончания = ОбщийМодульСервер.ПолучитьЗначениеКонстанты(“ОкончаниеРабочегоДня”);
Если (Формат(ТекущаяДата(), “ДЛФ=В; ДФ=ЧЧммсс”) < Формат(ВремяОкончания, “ДЛФ=В; ДФ=ЧЧммсс”)) Тогда
Ответ = Вопрос(“Рабочий день еще не закончен! Продолжить работу?”, РежимДиалогаВопрос.ДаНет, 10);
Если (Ответ = КодВозвратаДиалога.Да) Тогда
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры</code>
выбор варианта обеда реализован в обработчике события ПриНачалеРаботыСистемы():
<code>Процедура ПриНачалеРаботыСистемы()
ОбщийМодульСервер.ИнициализироватьПользователя();
Меню = ОбщийМодульСервер.ПолучитьСписокВариантовОбедов();
Если Меню.ОтметитьЭлементы(“Выберите вариант обеда”) Тогда
Для Каждого Элемент Из Меню Цикл
Если Элемент.Пометка Тогда
ОбщийМодульСервер.ДобавитьВариантОбедаПользователю(Элемент.Значение,
ОбщийМодульСервер.ПолучитьПользователя(ИмяПользователя()));
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры</code>
Задание сделал.
Созданные процедуры и функции в общем модуле (флаги сервер и вызов сервера):
– ЗаполнениеКонстант
– СинхронизацияСпПользователей, там же проверка флага «Администратор»
– Функция ЗаполнениеВыборкиОбедов, почему то при отработке Список.ВыбратьЭлемент() в общем модуле вызывает ошибку – «Ошибка при вызове метода контекста (ВыбратьЭлемент): Неудачная попытка создания окна»; пришлось из процедуры делать функцию и вызывать окно выбора элемента из модуля управляемого приложения.
– ЗаписьВариантаОбеда, проверяю если обед на текущий день у пользователя заполнен то заменяю ВариантОбеда, если нет то создаю новый элемент в ОбедыПользователей
После описанной выше ошибки был вариант с модальным выводом формы выбора справочника ВариантыОбедов. Только пока что не смог сделать в ней отбор не помеченных на удаление. А так способ гораздо проще.
Помеченные на удаление, смог отобрать помощью ЭлементОтбораКомпоновкиДанных. Разбирался долго и теперь уже такой способ не кажется особо простым :)
Основные моменты выполнения задания:
– все экспортные процедуры и функции где идет обращение к константам и справочникам описаны в общем модуле с флагами “сервер” и “вызов сервера” (ОбщийМодульНаСервере)
– синхронизацию списка пользователей и одноименного справочника провожу в проц. ПередНачаломРаботыСистемы и сохраняю текущего пользователя в параметре сеанса(тип СправочникСсылка.Пользователи), тут же идет проверка <а надо ли проверять раб время>
Функция ПроверятьВремя() Экспорт
Возврат НЕ ПараметрыСеанса.ТекущийПользователь.Администратор;
КонецФункции
– рабочее время проверяется с использованием констант
Функция РабочееВремя() Экспорт
текДата = Дата(“00010101″+Формат(ТекущаяДата(), “ДФ=ЧЧммсс”));
Возврат текДата >= Константы.ВремяНачалаРаботы.Получить() И текДата <= Константы.ВремяОкончанияРаботы.Получить();
КонецФункции
– обеды запрашиваются в ПриНачалеРаботыСистемы.
спОбедов = ОбщийМодульНаСервере.ЗапроситьОбеды();
Если спОбедов.ОтметитьЭлементы(“Выберите вид обеда”) Тогда
ОбщийМодульНаСервере.ЗаписатьОбеды(спОбедов);
КонецЕсли;
Сделала через список значений, который заполняется из справочника. Запрос обедов происходит если для текущего пользователя за текущую дату нет выбранных блюд:
Если Справочники.ОбедыПользователей.НайтиПоРеквизиту(“Дата”, Дата(Формат(ТекущаяДата(), “ДЛФ=Д”)+” 00:00:00″),,ПараметрыСеанса.ТекущийПользователь) = Справочники.ОбедыПользователей.ПустаяСсылка() Тогда
…
Основные моменты выполнения задания:
– все экспортные процедуры и функции где идет обращение к константам и справочникам описаны в общем модуле с флагами “сервер” и “вызов сервера” (ОбщийМодульНаСервере)
– синхронизацию списка пользователей и одноименного справочника провожу в проц. ПередНачаломРаботыСистемы и сохраняю текущего пользователя в параметре сеанса(тип СправочникСсылка.Пользователи), тут же идет проверка <а надо ли проверять раб время>
Функция ПроверятьВремя() Экспорт
Возврат НЕ ПараметрыСеанса.ТекущийПользователь.Администратор;КонецФункции
– рабочее время проверяется с использованием констант
Функция РабочееВремя() Экспорт
текДата = Дата(“00010101″+Формат(ТекущаяДата(), “ДФ=ЧЧммсс”)); Возврат текДата >= Константы.ВремяНачалаРаботы.Получить() И текДата <= Константы.ВремяОкончанияРаботы.Получить();
КонецФункции
– обеды запрашиваются в ПриНачалеРаботыСистемы.
спОбедов = ОбщийМодульНаСервере.ЗапроситьОбеды(); Если спОбедов.ОтметитьЭлементы(“Выберите вид обеда”) Тогда ОбщийМодульНаСервере.ЗаписатьОбеды(спОбедов); КонецЕсли;
Сделала через список значений, который заполняется из справочника. Запрос обедов происходит если для текущего пользователя за текущую дату нет выбранных блюд:
Если Справочники.ОбедыПользователей.НайтиПоРеквизиту(“Дата”, Дата(Формат(ТекущаяДата(), “ДЛФ=Д”)+” 00:00:00″),,ПараметрыСеанса.ТекущийПользователь) = Справочники.ОбедыПользователей.ПустаяСсылка() Тогда
…
Задание сделал.
1.В обработчике модуля сеанса инициализируется параметр ТекПользователь типа СправочникСсылка.Пользователи значением
Справочники.Пользователи.НайтиПоНаименованию(ПараметрыИБ.ТекущийПользователь).Здесь же добавляется новый пользователь в справочник.
2. В обработчиках модуля управляемого приложения
ПередНачаломРаботыСистемы(Отказ) –
Если НЕ ОбщийМодуль.ЭтоАдминистратор() тогда Отказ = Не ОбщийМодуль.РабочееВремя()
ПередЗавершениемРаботыСистемы(Отказ) –
Если НЕ ОбщийМодуль.ЭтоАдминистратор() тогда Отказ = ОбщийМодуль.РабочееВремя()
ПриНачалеРаботыСистемы()
СписокБлюд = ОбщийМодуль.ВыборБлюд();
Если СписокБлюд.ОтметитьЭлементы тогда ОбщийМодуль.СделатьЗаказ(СписокБлюд);
3.В Общем модуле сервера (с флажком вызова):
РабочееВремя() – проверка ТекущаяДата() на входимость в интервал Константы.НачалоРаботы..Константы.КонецРаботы
ЭтоАдминистратор() – возврат ПараметрыСеанса.ТекПользователь.Администратор
ВыборБлюд() – возврат списка значений из справочника ВариантыОбедов без пометки на удаление.
Меню = Новый СписокЗначений;
Выборка = Справочники.ВариантыОбедов.Выбрать();
Пока Выборка.Следующий() Цикл
Если Не Выборка.ПометкаУдаления Тогда
Меню.Добавить(Выборка.Ссылка);
КонецЕсли;
КонецЦикла;
возврат Меню;
СделатьЗаказ(СписокБлюд) – наполнение справочника ОбедыПользователей данными из списка значений.
Для каждого Блюдо из СписокБлюд Цикл
Если Блюдо.Пометка тогда
Эл = Справочники.ОбедыПользователей.СоздатьЭлемент();
Эл.ВариантОбеда = Блюдо.Значение;
Эл.Владелец=ПараметрыСеанса.ТекПользователь;
Эл.Дата=ТекущаяДата();
Эл.Записать();
КонецЕсли;
КонецЦикла;
ДЗ №5 выполнила.
По ходу решения наступила на двое граблей-)))
Сначала пользователь не записывался потому что не было доступных ролей, хотя роль уже была создана. Здесь помогли уроки по темам Роли и Пользователи.
Затем, чтобы организовать множественный выбор из справочника Варианты Обедов, в общем модуле формировала список значений, отсеивая помеченные на удаление элементы справочника. И вот здесь лежали вторые грабли: метод ОтметитьЭлементы() не работал на сервере, хотя в синтакс-помощнике было написано обратное-))) Почему?.. Пробовала и так и эдак, в результате обошла кривой дорогой – в список значений заносила наименования элементов справочника Варианты обеда, передавала в модуль управляемого приложения, пользователь делает выбор и список передается обратно в модуль. В общем модуле поиск по наименованию и запись в справочник Обеды пользователей. Криво. Работает-)).
Остальное сложностей не вызвало.
> метод ОтметитьЭлементы() не работал на сервере, хотя в синтакс-помощнике было написано обратное-))) Почему?.
Доверяй, но проверяй :)
Интерактивные методы не могут работать на сервере, только на клиенте.
Задание выполнила.
По ходу выполнения столкнулась с несколькими затруднениями.
1. Не знала, где лучше запомнить пользователя – как Параметр сеанса или как глобальную переменную в модуле управляемого приложения. Использовала Параметр сеанса. Почитав комментарии уже нашла ответ, что гл.переменная правильнее.
2. Не знала как показать пользователю список элементов справочника Варианты обеда не только для выбора, но и с возможностью добавить свои варианты. В результате сделала через общую форму. Получаю общую форму в ПриНачалеРаботыСистемы и открываю ее модально. При открытии формы заполняю на ней список значений непомеченными на удаление вариантами обеда из справочника, используя серверную процедуру общего модуля (с вызовом сервера). При закрытии – копирую список вместе с возможно добавленными пользователем вариантами и пометками в гл.переменную, объявленную в модуле упр.приложения. Дальше все еще из процедуры ПриНачалеРаботыСистемы, снова через процедуру общего модуля записываю помеченные пользователем варианты обеда в подчиненный справочник.
Так и не смогла найти как задать тип значения для списка значений на форме. То есть как не дать пользователю добавив новый элемент списка добраться до ненужного справочника и ввести туда новый элемент, вместо ввода нового варианта обеда.
3. При проверке не был ли уже осуществлен выбор обеда за текущую дату столкнулась ровно с такими же затруднениями, что и ulan. Отбор по дате, где Дата=ТекущаяДата(), всегда получался пустым из-за присутствия в дате времени. Боролась также – использовала в отборе НачалоДня(ТекущаяДата())
Почитала комментарии внимательнее. Удивилась, что большинство только выдавало пользователю список вариантов обеда для проставления пометок выбора. Перечитала условие домашнего задания и поняла, что перемудрила :)
Сложную дорого выбрали, но зато много интересного узнали ;)
>То есть как не дать пользователю добавив новый элемент списка добраться до ненужного справочника
Свойства элемента формы, куда выведен ваш список (это таблица формы). Категория Использование, свойство “Список команд”. Убираете все команды.
Задание выполнил.
Соригинальничать увы не получится. ТекущийПользователь в параметрах сеанса. Инициализация в Модуле сеанса (вызов процедуры общего модуля УправлениеПользователями, галки Сервер, Вызов сервера). Там же процедура проверки возможности входа, вызываемая из модуля приложения ПередНачаломРаботыСистемы().
Приведу листинг (в этот раз копипаст в FF)
Процедура ПроверитьВозможностьРаботыПользователя(Отказ) Экспорт ТекущийПользователь = ПараметрыСеанса.ТекущийПользователь;
Если НЕ ТекущийПользователь.Администратор Тогда ВремяНачалаРабочегоДняСтрокой = Формат(Константы.ВремяНачалаРабочегоДня.Получить(), “ДФ=hhmmss”); ВремяОкончанияРабочегоДняСтрокой = Формат(Константы.ВремяОкончанияРабочегоДня.Получить(), “ДФ=hhmmss”); НачалоРабочегоДня = Дата(Формат(ТекущаяДата(), “ДФ=yyyyMMdd”) + ВремяНачалаРабочегоДняСтрокой); КонецРабочегоДня = Дата(Формат(ТекущаяДата(), “ДФ=yyyyMMdd”) + ВремяОкончанияРабочегоДняСтрокой); ВремяВходаПользователяВПрограмму = ТекущаяДата(); Если ВремяВходаПользователяВПрограмму < НачалоРабочегоДня ИЛИ ВремяВходаПользователяВПрограмму > КонецРабочегоДня Тогда
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
А вот дальше наткнулся на грабли. По привычке работы в толстом клиенте (обычном приложении) весь процесс обработки вариантов обеда был размещен в одной процедуре общего модуля (все того же УправлениеПользователями)ОбработатьВариантыОбеда(), которая вызывается из ПриНачалеРаботыСистемы(). Но потом все же понял что, к чему и процедура разбилась на 3. 1) НаСервере. Получение доступных вариантов обеда (запросом из справочника, исключая помеченные на удаление). 2) НаКлиенте. Взаимодействие с пользователем (вызов метода списка значений ОтметитьЭлементы()). 3) НаСервере. Запись выбраных элементов в подчиненный справочник). В плане удобства разработки прям скажем неприятный момент, но более правильный с точки зрения клиент-серверного взаимодействия. Чтож, бум привыкать :)
Задание выполнено.
1. Модуль управляемого приложения.
Определены следующие обработчики событий:
ПередНачаломРаботыСистемы(Отказ)
– проверка возможности входа в программу
ПриНачалеРаботыСистемы()
– выбор и сохранение вариантов обеда пользователя,
диалог выбора реализован с помощью метода ОтметитьЭлементы()
ПередЗавершениемРаботыСистемы(Отказ)
– проверка целесообразности закрытия программы
2. Модуль сеанса.
Хранение текущего пользователя:
параметр сеанса “ТекущийПользователь”,
(тип “СправочникСсылка.Пользователи”).
Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
– инициализация параметра сеанса ТекущийПользователь,
создание элемента справочника “Пользователи”,
в случае его отсутствия
3. Общий серверный модуль “Сервер” с возможность вызова. Реализация процедур, необходимых для описания
обработчиков событий модуля управляемого приложения.
Функция ПользовательЯвляетсяАдминистратором() Экспорт
– параметр ПараметрыСеанса.ТекущийПользователь.Администратор
Функция РабочееВремя() Экспорт
– проверка текущего времени с константами начала
и окончания рабочего дня
Функция ПолучитьСписокВариантовОбеда() Экспорт
– занесение не помеченных на удаление элементов
справочника «ВариантыОбедов» в СписокЗначений
Процедура ЗаписатьСписокВариантовОбеда(СписокЗначений) Экспорт
– создание новых элементов справочника “ОбедыПользователей”
для помеченных элементов параметра процедуры СписокЗначений
В качестве примера привожу код, реализующий выбор пользователем
вариантов обеда:
Процедура ПриНачалеРаботыСистемы()
СписокЗначений = Сервер.ПолучитьСписокВариантовОбеда();
Если СписокЗначений.ОтметитьЭлементы(“Выберете обед:”) Тогда
Сервер.ЗаписатьСписокВариантовОбеда(СписокЗначений)
Иначе
Предупреждение(“Останетесь без обеда!”)
КонецЕсли;
КонецПроцедуры
Поскольку очевидно, что в модуле управляемого приложения нужно работать с данными ИБ. Создал общий модуль с флагом компиляции на Сервере и для доступа к процедурам этого модуля из модуля приложения установил флаг «Вызов сервера». Для определения текущего пользователя в модуле приложения объявил глобальную переменную глТекущийПользователь. Которую передавал в качестве параметра в процедуру определения пользователя в созданном общем модуле. При создании справочника «Пользователи» для организации удобного поиска пользователя в нем, отключил контроль уникальности кодов и в код записывал Имя пользователя, при добавлении пользователя в справочник. В этом случае поиск пользователя можно осуществлять с помощью метода НайтиПоКоду. В модуле приложения попыталась обратиться к реквизиту Администратор переменной глТекущийПользователь и получил ошибку времени выполнения. Вспомнил, что клиенте недоступно обращение к БД, пришлось получать значение этого реквизита, через дополнительный параметр процедуры общего модуля ОпределениеТекущегоПользователя(ТекПользователь, ПризнакАдминистратора) . Это кажется не удобным (учитывая навыки программирования в предыдущих версиях), но понятно, что разделение на клиентский и серверный контекст фирма 1С придумала не для того, чтобы доставить неудобство разработчикам.
Для чтения значений констант также пришлось использовать функцию общего модуля которая возвращала значение константы по ее имени и состояла из всего одной строки:
Возврат Константы[ИмяКонстанты].Получить();
Хотя, кажется, я видел в каком-то из уроков, как можно получить значение константы на клиенте без обращения к процедурам сервера, но так и не нашел нужной функции.
Для создания списка возможных вариантов обеда пользователя соответствующая процедура общего модуля переберала элементы справочника ВариантыОбедов и формировала список значений который возвращался в параметре в модуль приложения, а там уже осуществлялся выбор значений из списка в интерактивном режиме. Таким образом обращение к ИБ осуществлялось из серверного общего модуля, а взаимодействие с пользователем из модуля приложения, т.е. все в соответсвии с новой идеологией. Здесь столкнулся с еще одной интересной особенностью.
В процедуре общего модуля перед формированием списка значений с вариантами обеда сначала проверялось нет ли данных в справочнике ОбедыПользователей и если есть то в список элементы не добавлялись и выбор пользователь не производил. При этом для реквизита Дата справочника ОбедыПользователей, для ускорения поиска было установлено свойство индексировать, а сам поиск осуществлялся с помощью метода НайтиПоРеквизиту. При этом даже с учетом того, что состав даты для реквизита «Дата» был установлен «Дата» (т.е. без учета времени) если в качестве значения поиска передавать возвращаемое функцией ТекущаяДата() значение то поиск всегда осуществлялся неудачно. Это яркий пример того, что, не смотря на свойство состав даты, в поле хранится полная дата с учетом времени, а свойство влияет только на отображение даты. Поэтому для решения этой задачи при записи элемента и последующем поиске необходимо приводит дату к единому виду, для этого я использовал функцию НачалоДня.
>Хотя, кажется, я видел в каком-то из уроков, как можно получить значение константы на клиенте без обращения к процедурам сервера, но так и не нашел нужной функции.
Есть функция ПредопределенноеЗначение(), которая позволяет обращаться к предопределенным элементам справочников, значениям перечислений, пустым ссылкам.
Но вот значение константы с помощью нее не получить..
> Это яркий пример того, что, не смотря на свойство состав даты, в поле хранится полная дата с учетом времени, а свойство влияет только на отображение даты.
Все верно Вы описали.
Спасибо за содержательный комментарий.
Задание выполнил, серьезных затруднений не возникло.
Создал все объекты метаданных, которые требовались по условию. Модифицировал код предыдущего задания. Добавил немножко “отсебятины” – создал параметр сеанса ТекущийПользователь.
В ПередНачаломРаботыСистемы() в процедуре ОпределитьСтатусПользователя() общего модуля РаботаПриложенияСервер (галочки Сервер, СерверныйВызов) провожу синхронизацию справочника Пользователи (если это новый пользователь, то создается новый элемент) и определяю статус пользователя (администратор ли он и сохраняю значение в глобальную переменную ЭтоАдминистратор. А также сохраняю в параметры сеанса текущего пользователя (для удобства). Если прав администратора нет, то выполняется проверка на время входа в программу.
Затем, если вход разрешен, в ПриНачалеРаботыСистемы() функцией РаботаПриложенияСервер.ЗаполнитьОбедыПользователей() заполняю список значений ВидыОбедов (путем перебора элементов справочника ВариантыОбедов, исключая помеченные на удаление). Используя метод ОтметитьЭлементы, предлагаю пользователю составить свое обеденное меню. После этого отмеченные элементы сохраняю в справочник ОбедыПользователей, который подчинен справочнику Пользователи. Владельца беру из параметра сеанса. Кстати, в условии ничего не сказано о том, что ОбедыПользователей нужно очищать при каждом сеансе. Добавил очистку, иначе там накопится масса блюд для каждого пользователя :)
Ну и, наконец, в ПередЗавершениемРаботыСистемы() вновь проверяется значение глобальной переменной ЭтоАдминистратор, и если у пользователя нет административных прав, выполняется процедура проверки права на выход из программы раньше времени окончания рабочего дня (которое указано в константе).
Задание выполнил…
Пользователя инициализировал(создавал) в модуле сеанса и писал в параметр сеанса. Функции проверки времени, формирования списка меню из справочника, создание элементов подчиненного справочника расположил в серверном модуле. Вызывал их из модуля упр.приложения (из соответствующих обработчиков)…
Все просто, даже слишком просто :(
Из пройденного материала более 95% знал и до этого, терзают меня смутные сомнения: наверное надо было идти на продвинутый …
Дальше будут более сложные задания.
Но, разумеется, в рамках тем базового курса..
Текущего пользователя определял ПараметрахСеанса и синхронизировал в модуле сеанса. Для проверки возможности входа, составления списка блюд и создания подчиненных элементов справочника был создан глобальный модуль с серверной компиляцией и возможностью вызова сервера из клиента. Все остальное осталось почти без изменений в модуле приложения. Вот текст общего модуля:
Функция ВходВозможен() Экспорт
Администратор=ПараметрыСеанса.ТекПользователь.Администратор;
ТекДата=ТекущаяДата();
НачДня=Константы.НачалоРабочегоДня.Получить();
КонДня=Константы.КонецРабочегоДня.Получить();
РабочийДень = (ТекДата > Дата(Год(ТекДата),Месяц(ТекДата),День(ТекДата),Час(НачДня),Минута(НачДня),Секунда(НачДня)))
И (ТекДата < Дата(Год(ТекДата),Месяц(ТекДата),День(ТекДата),Час(КонДня),Минута(КонДня),Секунда(КонДня)));
Возврат Администратор Или РабочийДень;
КонецФункции
Процедура ЗаполнитьМеню(Меню) Экспорт
ВыборкаВариантов = Справочники.ВариантыОбедов.Выбрать();
Пока ВыборкаВариантов.Следующий() И (Не ВыборкаВариантов.ПометкаУдаления) Цикл
Меню.Добавить(ВыборкаВариантов.Ссылка,ВыборкаВариантов.Наименование);
КонецЦикла;
КонецПроцедуры
Процедура СоставитьМеню(Меню) Экспорт
Для каждого Блюдо Из Меню Цикл
Если Блюдо.Пометка Тогда
НовоеБлюдо=Справочники.ОбедыПользователей.СоздатьЭлемент();
НовоеБлюдо.Владелец=ПараметрыСеанса.ТекПользователь;
НовоеБлюдо.Наименование=Блюдо.Значение.Наименование;
НовоеБлюдо.Дата=ТекущаяДата();
НовоеБлюдо.ВариантОбеда = Блюдо.Значение;
НовоеБлюдо.Записать();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
>Текущего пользователя определял ПараметрахСеанса и синхронизировал в модуле сеанса
Все-таки лучше не использовать параметры сеанса, как серверные глобальные переменные.
Параметры сеанса предназначены для обращения к ним в запросах RLS.
В типовой торговле сделано именно так:
Есть параметр сеанса ТекущийПользователь, и он инициализируется в модуле сеанса:
Пользователи.ОпределитьТекущегоПользователя(ИмяПараметра, УстановленныеПараметры);
А затем везде применятся для идентификации текущего пользователя, в том числе и для RLS
Здесь важно понимать, что в типовых параметр сеанса был создан из-за необходимости использования в RLS.
И поскольку он уже создан к нему обращаются из различных модулей.
У Вас ошибка в коде:
Пока ВыборкаВариантов.Следующий() И (Не ВыборкаВариантов.ПометкаУдаления) Цикл
как только попадется первый помеченный на удаление элемент, цикл прервется. А это не верно, потому что после него в выборке могут идти не помеченные на удаление элементы и в Ваш список они не попадут.
Сделано. В модуле сеанса (поскольку он запускается до модуля управляемого приложения) инициализируется параметр сеанса Пользователь (синхронизация по имени пользователя). В модуле управляемого приложения в процедурах ПередНачаломРаботыСистемы и ПередЗавершениемРаботыСистемы производим проверку с обращением к константам через
НаборКонстант = Константы.СоздатьНабор(“ВремяНачалаРД,ВремяОкончанияРД”);
НаборКонстант.Прочитать();
При этом, поскольку доступ к этим константам ролями мы не ограничили, ограничим их изменение в модуле менеджера значений в процедуре ПередЗаписью, оставив такую возможность только пользователям с реквизитом “Администратор”=Истина. Аналогично и для справочника “Пользователи”, чтобы обычные пользователи не смогли поставить себе признак Администратора (а администратору можно запретить снимать себе галочку, или лучше в модуле сеанса если текущий пользователь = “Администратор”, проверять и, при необходимости, устанавливать админские права).
С выбором обедов и фиксацией их в подчиненном справочнике тоже проблем не возникло.
Пометки:
1) Одна роль “полные права” для всех пользователей не сможет защитить от запуска базы в режиме конфигуратора и отключить установленные программно ограничения;
2) Было открытием способ хранения констант в таблице _Consts. И правда все значения хранятся в одной строке, что естественно препятствует их одновременному изменению разными пользователями. Интересно, блокировка устанавливается только на время исполнения методов Установить/Записать?
>Интересно, блокировка устанавливается только на время исполнения методов Установить/Записать?
Смотря где выполняется программный код.
Если в рамках транзакции (явной или неявной), например, при проведении документа, то блокировка будет длиться до окончания транзакции.
Если можно, комментарии не по собственно ДЗ, а по рекомендованному материалу.
1. Очень порадовала работа со ссылками незаписанных объектов! Раньше (тем более в 7.7) не приходилось с этим сталкиваться, и этот материал оказался для меня совершенно новым.
2. По поводу примера с записью КЛ при записи контрагента интересен такой вопрос: а не запишется ли в реквизит ссылка без объекта. Предположим, в процедуре ПередЗаписью() в модуле справочника КЛ генерируется Отказ, например если не заполнен телефон КЛ, а мы, редактируя модуль формы Контрагента, об этом не знаем. – Оказывается, запись КЛ происходит в той же транзакции, и Контрагент в этом случае не запишется.
Правда, сообщение, которое при этом возникает, выглядит, как ошибка – стало быть, мы должны предусмотреть такую ситуацию. Попробуем записать КЛ в Попытке, а в случае Исключения – не предпринимать никаких действий. Тогда, действительно, Контрагент запишется, а в реквизите ОсновнойКЛ появится “<Объект не найден> (59:8c22aff1fdd4b0e5402136bcc3370b1e)”. Но это уже точно тот случай, когда надо все-таки обработать Исключение должным образом.
3. Ещё один вопрос связан с материалом “13 ошибок”, именно с последней 14-й ошибкой. После записи элемента КЛ у нас в памяти одновременно находятся объект Контрагент и объект КЛ, которые ссылаются друг на друга. Не есть ли это тот случай, когда после выхода из процедуры ПриЗаписиНаСервере ссылка на объект КЛ не будет очищена, а для 1С уже будет недоступна. Если это так, правильно ли будет:
КЛ.Записать();
КЛ = “”;
4. На всякий случай, последний вопрос: уместны ли здесь подобные комментарии?
2. Несуществующую ссылку можно легко записать таким кодом (справочник Номенклатура):
УИД = Новый УникальныйИдентификатор;
Поставщик = Справочники.Контрагенты.ПолучитьСсылку(УИД);
КонецПроцедуры
Разумеется нужно следить за правильностью кода.
3. Циклическая ссылка действительно налицо.
Но пока не уверен будут ли образовываться утечки в памяти. Отвечу чуть позже.
4. Эти вопросы уместнее было бы задавать в тему, где представлен первый блок.
3. Да в этом случае правильным будет очищать значение переменной КЛ.