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