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