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