При проектировании конфигураций на платформе 1С:Предприятие 8.3 (Управляемые формы) разработчики часто сталкиваются с задачей создания специализированных рабочих мест. Яркий пример — автоматизированное рабочее место (АРМ) кассира. Логика такого интерфейса должна быть предельно простой для конечного пользователя: минимум видимых реквизитов, кнопка прихода, кнопка расхода и текущий баланс кассы. Однако за этой внешней простотой скрывается серьезная архитектурная работа. В качестве готовой альтернативы самостоятельной разработке можно использовать программу для регистрации продаж на ККМ.
В данной статье мы подробно разберем, как правильно организовать интерфейс для такой задачи, рассмотрим разницу между общими формами и обработками, научимся выводить элементы на рабочую область начальной страницы и разберем современные программные методы вызова окон.
Общие формы в 1С являются вспомогательными объектами метаданных. Они не привязаны жестко к справочникам или документам, поэтому платформа по умолчанию не знает, в каком разделе интерфейса их нужно отображать. Если мы хотим, чтобы пользователь мог открыть общую форму из панели разделов подсистемы, нам необходимо явно указать это в конфигураторе.
Выясним, какими путями можно решить эту задачу. Существует два основных подхода:
Вариант А. Использование стандартных команд формы
У каждой общей формы в палитре свойств есть механизм автоматического создания команды открытия. Разберем по шагам, как его активировать:
Истина).Вариант Б. Создание Общей команды (рекомендуемый способ)
Если нам требуется не просто открыть форму, а предварительно проверить права пользователя, передать параметры или заполнить какие-то данные по умолчанию, стандартная команда не подойдет. В этом случае мы создаем собственный инструмент вызова:
Панель действий.Сервис).
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
// Передаем параметры открытия, если это необходимо
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("ТекущийПользователь", ПараметрыВыполненияКоманды.Источник);
ОткрытьФорму(
"ОбщаяФорма.ИмяВашейОбщейФормы",
ПараметрыФормы,
ПараметрыВыполненияКоманды.Источник,
ПараметрыВыполненияКоманды.Уникальность,
ПараметрыВыполненияКоманды.Окно
);
КонецПроцедуры
Если разрабатываемая «Касса» является основным рабочим пространством пользователя, заставлять его каждый раз искать кнопку в меню подсистем — плохое решение. Форма должна открываться автоматически при запуске программы. Для этого мы интегрируем её в рабочую область начальной страницы.
Проанализируем порядок действий в конфигураторе:
На форумах часто возникает спор: есть ли принципиальная разница, где верстать интерфейс кассира — в общей форме или в форме обработки? Некоторые разработчики утверждают, что разницы нет, так как визуальный редактор одинаков. Однако с точки зрения архитектуры 1С и удобства дальнейшего сопровождения разница огромна.
Рассмотрим сравнительный анализ этих объектов в таблице логики разработки:
1. Наличие модуля объекта и реквизитов
У общей формы нет собственного модуля объекта и реквизитов объекта — существуют только реквизиты самой формы. Это сильно ограничивает нас в написании чистой бизнес-логики. Обработка же является полноценным объектом метаданных. В модуле объекта обработки мы можем объявить экспортные методы, хранить промежуточные таблицы данных и описывать алгоритмы проведения расчетов, оставляя модуль формы чистым и отвечающим исключительно за визуализацию.
2. Мобильность и тестирование (Внешние обработки)
Это ключевой аргумент в пользу обработки. В процессе эксплуатации кассы вам регулярно придется вносить изменения: добавлять новые проверки, менять логику проведения документов или дизайн кнопок. Если ваше АРМ сделано как общая форма, то для любого изменения вам придется обновлять конфигурацию базы данных монопольно, выгоняя пользователей.
Если же АРМ спроектировано на базе обработки, вы можете в любой момент сохранить её как Внешнюю обработку (.epf), внести изменения, протестировать на копии базы и загрузить в рабочую базу через механизм «Дополнительные отчеты и обработки» без остановки работы пользователей.
Иногда в старых обработках или на форумах можно встретить конструкцию вида ПолучитьОбщуюФорму("ИмяФормы").Открыть(). Важно понимать, что этот метод является устаревшим. Он использовался в толстом клиенте (обычное приложение) и выполнялся в синхронном режиме.
В современных управляемых формах (интерфейс «Такси») такой подход вызовет ошибки или предупреждения платформы. Открытие любых управляемых форм должно выполняться строго асинхронно с помощью функции ОткрытьФорму().
Посмотрим на пример правильного вызова общей формы из встроенного языка:
&НаКлиенте
Процедура ОткрытьКассуПрограммно()
// Параметры, передаваемые в открываемую форму
ПараметрыОткрытия = Новый Структура;
ПараметрыОткрытия.Вставить("РежимРаботы", "БыстрыеПродажи");
// Вызов современной асинхронной функции платформы
ОткрытьФорму("ОбщаяФорма.АРМ_Кассира", ПараметрыОткрытия);
КонецПроцедуры
Обратите внимание, что если запустить этот код в модуле управляемого приложения в процедуре ПриНачалеРаботыСистемы, форма откроется в виде модального или отдельного всплывающего окна поверх основного интерфейса, что ухудшает юзабилити. Поэтому для постоянных рабочих мест всегда используйте настройку «Рабочей области начальной страницы», описанную выше.
Разберем, как должна работать правильная логика «простого» интерфейса кассы, о котором шла речь на форуме. Пользователь видит только сумму в кассе и две кнопки: «Приход» и «Расход».
Категорически не рекомендуется менять сумму кассы «простым изменением надписи декорации» напрямую. Все движения денежных средств в системе 1С должны быть подтверждены документами. В противном случае вы потеряете сходимость учета, не сможете построить отчеты и провести аудит операций. Правильный подход — создавать документы незаметно для пользователя.
Давайте реализуем эту логику. Создадим обработку АРМ_Кассира. На форме создадим реквизит ТекущийБаланс и две команды: ОформитьПриход и ОформитьРасход. При нажатии на кнопку будет открываться упрощенное окно ввода суммы, а после ввода система автоматически создаст и проведет документ движения денег.
Рассмотрим пример серверного модуля формы обработки, который отвечает за получение баланса и создание документов:
&НаСервере
Функция ПолучитьТекущийБалансКассы()
// В реальной системе здесь должен быть запрос к регистру накопления "ДенежныеСредства"
// Для примера вернем вычисляемое значение
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(СуммаОстаток, 0) КАК Баланс
|ИЗ
| РегистрНакопления.ДенежныеСредства.Остатки КАК ДенежныеСредстваОстатки";
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующая();
Возврат Выборка.Баланс;
КонецЕсли;
Возврат 0;
КонецФункции
&НаСервереБезКонтекста
Процедура СоздатьДокументДвиженияНаСервере(ТипОперации, СуммаДокумента)
// Автомагическое заполнение документов на основе предопределенных параметров
Если ТипОперации = "ПРИХОД" Тогда
НовыйДок = Документы.ПоступлениеНаличных.СоздатьДокумент();
НовыйДок.ВидОперации = Перечисления.ВидыОперацийПоступлениеНаличных.ПрочиеПоступления;
Иначе
НовыйДок = Документы.РасходНаличных.СоздатьДокумент();
НовыйДок.ВидОперации = Перечисления.ВидыOperацийРасходНаличных.ПрочийРасход;
КонецЕсли;
НовыйДок.Дата = ТекущаяДатаСеанса();
НовыйДок.СуммаДокумента = СуммаДокумента;
// Заполняем системные реквизиты по умолчанию (невидимо для кассира)
НовыйДок.Организация = Справочники.Организации.ПредопределеннаяОрганизация();
НовыйДок.Касса = Справочники.Кассы.ПолучитьОсновнуюКассуДляПользователя();
НовыйДок.СтатьяДвиженияДенежныхСредств = Справочники.СтатьиДвиженияДенежныхСредств.ОсновнаяСтатья;
Попытка
НовыйДок.Записать(РежимЗаписиДокумента.Проведение);
Исключение
ВызватьИсключение "Не удалось провести документ по кассе: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
Таким образом, мы сохраняем простоту интерфейса для конечного пользователя (кассир видит только баланс и вводит сумму транзакции), но при этом соблюдаем жесткие требования к ведению учета в ERP-системах. Все операции мгновенно отражаются в регистрах накопления через проведение скрытых документов, а баланс кассы на форме актуализируется при помощи функции ПолучитьТекущийБалансКассы() после каждой успешной операции.