Почему при загрузке таблицы значений в регистр накопления не создаются движения расхода и как правильно реализовать контроль остатков?

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

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

Причина ошибки: системные типы против пользовательских перечислений

Разберем ситуацию, когда в запросе для формирования движений используется конструкция ЗНАЧЕНИЕ(Перечисление.ВидыДвиженийПриходРасход.Расход). На первый взгляд это кажется логичным, если в конфигурации создано подобное перечисление. Однако для регистра накопления поле ВидДвижения имеет строго определенный системный тип — ВидДвиженияНакопления.

Если подставить значение из обычного (пользовательского) перечисления, платформа не сможет сопоставить его с системным типом «Приход/Расход» регистра накопления. В результате при вызове метода движения.ИмяРегистра.Загрузить(ТаблицаДанных) колонка ВидДвижения заполнится некорректно, и все записи могут по умолчанию стать приходными или не записаться вовсе.

Проанализируем правильный подход. В тексте запроса необходимо обращаться к системному перечислению следующим образом:


"ВЫБРАТЬ
|   ...
|   ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход) КАК ВидДвижения,
|   ...
|ОБЪЕДИНИТЬ ВСЕ
|ВЫБРАТЬ
|   ...
|   ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход),
|   ..."

Именно использование ВидДвиженияНакопления гарантирует, что метод Загрузить() правильно распознает тип операции для каждой строки таблицы значений.

Реализация контроля остатков: «Новая методика»

После того как движения сформированы и записаны, необходимо проверить, не ушел ли остаток в минус. Рассмотрим современный стандарт реализации этой задачи. Согласно «новой методике», мы сначала записываем движения документа в базу данных (внутри транзакции), а затем выполняем запрос к остаткам, чтобы найти отрицательные значения.

Выясним, как должен выглядеть алгоритм в модуле проведения:

  1. Запись движений: Устанавливаем свойство Записывать = Истина для нужных регистров и вызываем Движения.Записать(). Важно: если документ перепроводится, старые движения должны быть предварительно удалены.
  2. Подготовка данных: Формируем временную таблицу с товарами из документа. Это необходимо для того, чтобы проверять остатки только по тем позициям, которые затронуты документом.
  3. Запрос к остаткам: Получаем остатки из виртуальной таблицы Остатки на МоментВремени документа.

Посмотрим на пример эффективного запроса для контроля:


// 1. Помещаем товары документа во временную таблицу
Запрос.Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ
               |	Товары.Номенклатура КАК Номенклатура,
               |	Товары.Характеристика КАК Характеристика,
               |	Товары.Склад КАК Склад
               |ПОМЕСТИТЬ ВТ_Товары
               |ИЗ
               |	&ТаблицаТоваров КАК Товары
               |ИНДЕКСИРОВАТЬ ПО
               |	Номенклатура, Характеристика, Склад";

// 2. Проверяем наличие отрицательных остатков после записи
Запрос.Текст = Запрос.Текст + ";
               |ВЫБРАТЬ
               |	Остатки.Номенклатура.Представление КАК НоменклатураПредставление,
               |	Остатки.Склад.Представление КАК СкладПредставление,
               |	Остатки.ВНаличииОстаток КАК Остаток
               |ИЗ
               |	РегистрНакопления.СвободныеОстатки.Остатки(&МоментВремени, 
               |		(Номенклатура, Характеристика, Склад) В (ВЫБРАТЬ Номенклатура, Характеристика, Склад ИЗ ВТ_Товары)) КАК Остатки
               |ГДЕ
               |	Остатки.ВНаличииОстаток < 0";

Оптимизация производительности и блокировки

Рассмотрим важные нюансы, которые влияют на скорость работы системы и отсутствие ошибок в многопользовательской среде.

Индексация временных таблиц: Всегда используйте ИНДЕКСИРОВАТЬ ПО для полей, по которым будет происходить соединение или фильтрация (Номенклатура, Склад). Без индекса на больших документах запрос к остаткам будет работать крайне медленно, нагружая СУБД.

Управляемые блокировки: Использование свойства БлокироватьДляИзменения = Истина является устаревшим для режима управляемых блокировок. Вместо этого перед выполнением запроса к остаткам следует явно устанавливать блокировку данных.

Проанализируем пример использования объекта БлокировкаДанных:


Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.СвободныеОстатки");
ЭлементБлокировки.УстановитьПараметр("Склад", СкладОтправитель);
ЭлементБлокировки.ИсточникДанных = ТаблицаТоваров;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
Блокировка.Заблокировать();

Это гарантирует, что в момент между чтением остатков и завершением вашей транзакции другой пользователь не сможет изменить остатки по этим же позициям, что предотвращает появление «фантомных» излишков.

Развернутое сальдо и аналитика

Посмотрим на ситуацию со стороны учета по сериям и характеристикам. Если в вашем регистре включена соответствующая аналитика, контроль остатков должен выполняться строго в ее разрезе. Распространенная ошибка — проверять остаток «вообще» по номенклатуре, не учитывая, что по одной характеристике может быть «+10», а по другой «-10».

В блоке ИМЕЮЩИЕ или ГДЕ запроса обязательно проверяйте отрицательные остатки по каждой комбинации измерений. Если вы используете группировку в запросе, убедитесь, что она включает все ключевые измерения регистра (Склад, Номенклатура, Характеристика, Серия).

Резюме:

  1. Всегда используйте системный тип ВидДвиженияНакопления для формирования записей регистра.
  2. Применяйте «новую методику» проведения: запись движений -> контроль отрицательных остатков.
  3. Индексируйте временные таблицы и используйте управляемые блокировки для обеспечения целостности данных и высокой производительности.
  4. Проверяйте остатки с учетом всей аналитики (характеристики, серии), чтобы избежать ошибок развернутого сальдо.

Эти правила позволят вам создавать стабильные и быстрые механизмы проведения документов в 1С:Предприятии 8.3.

← На главную