Как наиболее быстро получить себестоимость товара в документе реализации для 1С 7.7?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

В практике разработчика на платформе 1С:Предприятие 7.7 часто возникает задача получения себестоимости товаров непосредственно из документа «Реализация». Типичная ситуация: в табличной части документа множество позиций, а в настройках списания партий указан «Автоподбор». Если пытаться рассчитать себестоимость «на лету» путем прямого перебора справочников и регистров остатков, это может привести к катастрофическому падению производительности, особенно в крупных информационных базах.

В этой статье мы подробно разберем, почему стандартные методы расчета могут работать медленно, и рассмотрим самый оптимальный способ получения данных, который уже заложен в архитектуру платформы.

Анализ проблемы: почему ручной расчет — это долго?

Давайте проанализируем ситуацию. Когда мы открываем проведенный документ реализации и пытаемся программно вычислить себестоимость каждой строки, обращаясь к регистру остатков на момент времени документа, мы фактически заставляем систему выполнять ту же тяжелую работу, которую она уже проделала при проведении этого документа. Алгоритм «Автоподбора» должен найти свободные остатки по методу FIFO или LIFO, распределить их по партиям и учесть специфику конкретного склада. Повторное выполнение этих действий для каждой строки табличной части в цикле — это избыточная нагрузка на сервер и дисковую подсистему.

Оптимальное решение: использование движений регистра

Самый быстрый и правильный способ получить себестоимость для уже проведенного документа — это **чтение его собственных движений по регистру**. Выясним причину, почему это эффективно: в момент проведения документа система записывает итоговые суммы списания (себестоимость) в физические таблицы движений регистров (например, ПартииНаличие или ПартииТоваров). Эти данные уже рассчитаны, распределены по партиям и «привязаны» к уникальному идентификатору документа IDDOC.

Рассмотрим по шагам, как реализовать этот алгоритм программно:

  1. Создадим объект типа Регистр, соответствующий вашему регистру партий.
  2. Используем метод ВыбратьДвиженияДокумента(), чтобы ограничить выборку записями только этого конкретного документа.
  3. В цикле переберем движения, суммируя показатели себестоимости (обычно это ресурс Стоимость).
  4. Для удобства сгруппируем (свернем) полученные данные по номенклатуре.

Посмотрим на пример реализации этого метода:


// Создаем объект регистра
РегПартии = СоздатьОбъект("Регистр.ПартииНаличие");

// Выбираем движения конкретного документа (ТекущийДокумент)
РегПартии.ВыбратьДвиженияДокумента(Контекст.ТекущийДокумент());

Пока РегПартии.ПолучитьДвижение() = 1 Цикл
    // Нас интересуют только расходные движения (списание товара)
    Если РегПартии.Расход = 1 Тогда
        Товар = РегПартии.Номенклатура;
        СуммаСебестоимости = РегПартии.Стоимость;
        Количество = РегПартии.Количество;
        
        // Здесь можно накапливать данные в Таблицу Значений
        // или сопоставлять их со строками ТЧ документа
    КонецЕсли;
КонецЦикла;

Точное сопоставление со строками (НомерСтрокиДокумента)

Часто возникает вопрос: как быть, если один и тот же товар встречается в документе несколько раз в разных строках? Если мы просто выберем движения по номенклатуре, мы получим общую сумму, которую будет сложно распределить обратно. Проанализируем ситуацию глубже: в типовых конфигурациях (например, «Торговля и Склад» 7.7) при проведении используется метод ПривязыватьСтроку().

Если в модуле проведения вашего документа была команда Регистр.ИмяРегистра.ПривязыватьСтроку(НомерСтроки), то при чтении движений вы можете обратиться к методу НомерСтроки() объекта Регистр. Это позволяет получить себестоимость с точностью до конкретной позиции в табличной части, что исключает любые ошибки округления или распределения.

Работа с непроведенными документами: Временный расчет

Рассмотрим случай, когда документ еще не проведен (например, менеджер хочет увидеть предполагаемую прибыль в форме нового документа), и движений в регистре еще нет. В этом случае чтение движений не сработает. Нам поможет механизм временного расчета.

Вместо полного перебора партий вручную, мы можем заставить систему рассчитать итоги на нужную точку времени. Разберем этот механизм:


Рег = СоздатьОбъект("Регистр.ПартииНаличие");
// Устанавливаем фильтр по нужной номенклатуре
Рег.УстановитьФильтр(ВыбТовар);
// Включаем режим временного расчета
Рег.ВременныйРасчет(1);
// Рассчитываем остатки на момент времени перед документом
РассчитатьРегистрыНа(ТекущийДокумент());
// Теперь можем получать остатки и стоимость стандартными методами
ОстатокСтоимости = Рег.СводныйОстаток(ВыбТовар, , "Стоимость");

Важно: Метод ВременныйРасчет гораздо быстрее, чем ручной перебор справочников, так как платформа оптимизирует запросы к базе данных на уровне ядра.

Альтернатива: Регистр «Продажи»

В некоторых редакциях конфигураций на базе 1С 7.7 (например, модификации «Торговля и Склад») себестоимость при проведении дублируется в регистр Продажи. Проанализируем этот вариант. Регистр Продажи обычно является «оборотистым», в нем меньше измерений (нет разреза по партиям и складам), чем в регистре ПартииНаличие. Если ваша цель — просто получить итоговую цифру себестоимости для отчета, выборка из регистра Продажи может отработать еще быстрее за счет меньшего объема данных в таблице.

Оптимизация для SQL-версий (1С++)

Если вы работаете в среде SQL и используете внешние компоненты, такие как 1С++, самым эффективным способом будет выполнение прямого SQL-запроса к таблице движений регистра. Идентификатор таблицы движений обычно имеет вид RAxxxx (где xxxx — внутренний ID регистра). Прямой запрос к SQL-серверу с фильтром по полю IDDOC выполняется практически мгновенно, так как база данных использует заранее построенные индексы по документам.

Резюме и рекомендации

Подводя итог, можно выделить следующие правила для получения оптимальной производительности в 1С 7.7:

Соблюдение этих принципов позволит вам создавать быстрые и надежные механизмы анализа себестоимости даже в очень нагруженных системах на базе 1С 7.7.

← На главную