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