При автоматизации рабочего места кассира или менеджера по продажам часто возникает задача объединить несколько типовых шагов в одно действие. Например, при оформлении оптово-розничной продажи за наличный расчет менеджеру требуется сначала провести документ РеализацияТоваровУслуг, а затем сразу сформировать и открыть ПриходныйКассовыйОрдер (ПКО). Если оставлять эти действия раздельными, пользователи нередко забывают вводить оплату, что приводит к кассовым разрывам и зависшей дебиторской задолженности.
Разберем, как правильно реализовать проведение текущего документа и последующий ввод кассового ордера на его основании по нажатию одной пользовательской кнопки в обычном приложении (толстый клиент конфигураций уровня 1С:Управление торговлей 10.3, УПП 1.3 или Комплексная автоматизация 1.1).
Для создания подчиненного документа на основании текущего в платформе 1С предусмотрен метод Заполнить(). При его вызове у создаваемого объекта срабатывает событие ОбработкаЗаполнения, в которое передается ссылка на документ-основание. Конфигурация автоматически переносит контрагента, договор, сумму и состав взаиморасчетов.
Рассмотрим простую реализацию обработчика нажатия кнопки на форме документа:
Процедура ДействияФормыПровестиИСоздатьПКО(Кнопка)
// 1. Проводим текущий документ
Если Не ЗаписатьВФорме(РежимЗаписиДокумента.Проведение) Тогда
Возврат; // Если проведение не удалось (нехватка остатков и т.д.), прерываем выполнение
КонецЕсли;
// 2. Создаем новый Приходный кассовый ордер и заполняем его
ДокументПКО = Документы.ПриходныйКассовыйОрдер.СоздатьДокумент();
ДокументПКО.Дата = ТекущаяДата();
ДокументПКО.Заполнить(ЭтотОбъект.Ссылка);
// 3. Записываем или сразу открываем форму для проверки пользователем
ДокументПКО.Записать(РежимЗаписиДокумента.Запись);
ДокументПКО.ПолучитьФорму().Открыть();
КонецПроцедуры
Обратим внимание на ключевые особенности работы этого кода:
ЗаписатьВФорме(РежимЗаписиДокумента.Проведение) возвращает логическое значение. Если проведение завершилось с ошибкой (например, не заполнено обязательное поле, заблокирован период или нет свободного остатка на складе), функция вернет Ложь. Обязательно проверяем результат, чтобы не создавать ордер к непроведенной накладной.ДокументПКО.Заполнить(ЭтотОбъект.Ссылка) вызывает стандартные типовые механизмы заполнения ПКО по реализации.ПолучитьФорму().Открыть(), либо провести его автоматически, передав РежимЗаписиДокумента.Проведение.Иногда требуется, чтобы кассир перед сохранением ордера мог вручную скорректировать данные (например, принять частичную оплату или выбрать конкретную статью движения денежных средств). В таком случае записывать документ в базу заранее не нужно. Правильнее сразу инициализировать форму нового документа:
Процедура СоздатьИОткрытьНовыйПКО()
Если Не ЗаписатьВФорме(РежимЗаписиДокумента.Проведение) Тогда
Возврат;
КонецЕсли;
// Получаем основную форму нового документа
ФормаПКО = Документы.ПриходныйКассовыйОрдер.ПолучитьФормуДокумента(, ЭтаФорма);
// Заполняем реквизиты объекта формы на основании проведенной накладной
ФормаПКО.ДокументОбъект.Дата = ТекущаяДата();
ФормаПКО.ДокументОбъект.Заполнить(ЭтотОбъект.Ссылка);
// Открываем форму для кассира
ФормаПКО.Открыть();
КонецПроцедуры
В этом варианте документ ПриходныйКассовыйОрдер физически появится в базе данных только тогда, когда пользователь нажмет кнопку ОК или Провести в открывшейся форме.
При ручной доработке кнопок проведения часто возникает риск человеческого фактора: кассир может нажать кнопку несколько раз подряд, что приведет к созданию документов-дублей. Чтобы избежать задвоения оплат, перед созданием нового ПКО необходимо выполнить проверку на наличие уже введенных кассовых ордеров по данной реализации.
Проанализируем пример функции проверки наличия подчиненных документов через критерий отбора СвязанныеДокументы:
Функция ПКОУжеСуществует(СсылкаНаРеализацию)
// Получаем список всех связанных документов
СписокСвязанных = КритерииОтбора.СвязанныеДокументы.Найти(СсылкаНаРеализацию);
Для Каждого Ссылка Из СписокСвязанных Цикл
Если Ссылка.Метаданные().Имя = "ПриходныйКассовыйОрдер" Тогда
// Если найден проведенный или непроведенный ПКО — сообщаем об этом
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
Интегрируем проверку в итоговый обработчик проведения:
Процедура ДействияФормыПровестиИСоздатьПКО(Кнопка)
Если Не ЗаписатьВФорме(РежимЗаписиДокумента.Проведение) Тогда
Возврат;
КонецЕсли;
Если ПКОУжеСуществует(ЭтотОбъект.Ссылка) Тогда
Предупреждение("По данному документу реализации уже создан Приходный кассовый ордер!");
Возврат;
КонецЕсли;
ДокументПКО = Документы.ПриходныйКассовыйОрдер.СоздатьДокумент();
ДокументПКО.Дата = ТекущаяДата();
ДокументПКО.Заполнить(ЭтотОбъект.Ссылка);
ДокументПКО.Записать(РежимЗаписиДокумента.Запись);
ДокументПКО.ПолучитьФорму().Открыть();
КонецПроцедуры
Чтобы исключить случайные нажатия после того, как реализация уже оформлена, можно динамически изменять доступность элементов управления. В обычных формах конфигурации УТ 10.3 управление интерфейсом выполняется в процедурах формы ПриОткрытии, ПослеЗаписи и ОбновлениеОтображения.
Разберем, как отключить кнопку после успешного проведения:
Процедура ОбновитьДоступностьКнопок()
// Если документ проведен, отключаем кнопку создания ПКО
КнопкаСозданияПКО = ЭлементыФормы.ДействияФормы.Кнопки.Найти("ПровестиИСоздатьПКО");
Если КнопкаСозданияПКО <> Неопределено Тогда
КнопкаСозданияПКО.Доступность = Не ЭтотОбъект.Проведен;
КонецЕсли;
КонецПроцедуры
Вызов этой процедуры следует разместить в обработчиках событий формы ПриОткрытии и ПослеЗаписи. Это гарантирует корректное состояние кнопки как при создании нового документа, так и при повторном открытии ранее проведенной накладной.
Если специфика торговой точки предполагает исключительно розничные продажи день-в-день, вместо связки Реализация товаров и услуг + ПКО рекомендуется использовать штатный функционал конфигурации: