Почему непроведенные документы попадают в запрос к регистру остатков в 1С 7.7 и как это исправить?

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

Иногда при работе с базой данных 1С:Предприятие 7.7 можно столкнуться с аномальным и, на первый взгляд, нелогичным поведением системы. Одна из таких ситуаций — когда запрос к регистру остатков возвращает данные по документам, которые не проведены. Это нарушает основную логику учета, ведь только проведенные документы должны формировать движения. Подобное поведение обычно свидетельствует о нарушении целостности данных в базе.

Рассмотрим на примере реальной ситуации, как диагностировать и исправить эту проблему.

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


Процедура Сформировать()
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = "
    |Период с ДатаС по ДатаПо;
    |
    |Товар = Регистр.Остатки.Товар;
    |ТекДок = Регистр.Остатки.ТекущийДокумент;
    |Кво = Регистр.Остатки.Кво;
    |
    |Функция КвоНач = НачОст(Кво);
    |Функция КвоПрих = Приход(Кво);
    |Функция КвоРасх = Расход(Кво);
    |Функция КвоКон = КонОст(Кво);
    |
    |Группировка ТекДок;
    |
    |Условие(Товар = выбТовар);
    |";
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда   
        Возврат;
    КонецЕсли;
    
    Запрос.Выгрузить(тз, 0, 0);
КонецПроцедуры

Стандартные процедуры, такие как переиндексация и "Тестирование и исправление" (ТиИ), в данном случае не помогают. Разберемся, в чем причина и как действовать.

Шаг 1: Диагностика проблемы — проверка наличия движений

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

Для этого можно использовать метод ВыбратьДвиженияДокумента() объекта Регистр. Этот код позволяет перебрать все движения, связанные с конкретным документом.


// Предполагается, что в переменной "Док" находится ссылка 
// на "проблемный" непроведенный документ
Рег = СоздатьОбъект("Регистр.Остатки");
Рег.ВыбратьДвиженияДокумента(Док);
Пока Рег.ПолучитьДвижение() = 1 Цикл
    Сообщить("Обнаружено движение: " + Рег.Товар + ", Кво " + Рег.Кво);
КонецЦикла;

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

Шаг 2: Анализ возможных причин

Откуда могли появиться такие "осиротевшие" движения? Причин может быть несколько:

  1. Сбой транзакции. Самая частая причина. Если во время отмены проведения документа произошел сбой (зависание компьютера, отключение питания), система могла не успеть завершить операцию удаления записей из регистра, хотя сам документ уже помечен как непроведенный.
  2. Прямое редактирование базы. Кто-то мог с помощью внешних утилит или прямых запросов снять флаг проведения в журнале документов (таблица 1SJOURN.DBF), оставив при этом связанные движения в таблицах регистров (RA*.DBF, RG*.DBF) нетронутыми.
  3. Некорректная "свертка" базы. Некоторые старые или самописные обработки свертки могли создавать движения в регистрах напрямую, нарушая стандартный механизм привязки к документу-регистратору.
  4. Ошибки в коде конфигурации. В редких случаях сложный код проведения, использующий ручное управление транзакциями, может содержать ошибки, приводящие к подобной рассинхронизации.

Шаг 3: Способы решения

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

Решение 1: Программный обходной путь (провести и отменить)

Стандартный способ "вылечить" такой документ — это провести его и сразу же отменить проведение. При отмене проведения штатный механизм 1С должен корректно удалить все связанные с ним движения.

Проблема: Часто такой документ невозможно провести, так как он сам же и списал остатки, которых теперь не хватает для его проведения. Система выдаст ошибку "Недостаточно товара".

Обходной путь:

  1. Откройте конфигуратор и найдите процедуру ОбработкаПроведения() в модуле "проблемного" документа.
  2. Временно закомментируйте или удалите весь код внутри процедуры, оставив только пустой каркас или команду Возврат;. Это отключит все проверки, включая контроль остатков.
    
    Процедура ОбработкаПроведения()
        // Весь старый код закомментирован
        // ...
        Возврат;
    КонецПроцедуры
    
  3. Сохраните конфигурацию и зайдите в режим "Предприятие".
  4. Теперь вы сможете без проблем провести "проблемный" документ, так как все проверки отключены.
  5. Сразу после проведения выполните отмену проведения этого же документа. Система должна корректно удалить все его движения.
  6. Вернитесь в конфигуратор и восстановите исходный код в процедуре ОбработкаПроведения().

Важно: Этот способ может не сработать, если в конфигурации (например, в типовой "Торговля и Склад") отключено автоматическое удаление движений при отмене проведения. В таком случае переходим к следующему решению.

Решение 2: Прямое удаление "фантомных" движений из DBF-файлов

Этот метод является наиболее надежным, но требует повышенной осторожности и понимания структуры данных 1С. Он заключается в ручном удалении записей из файлов базы данных.

ШАГ 0. ОБЯЗАТЕЛЬНО СДЕЛАЙТЕ РЕЗЕРВНУЮ КОПИЮ БАЗЫ ДАННЫХ!

  1. Определить внутренний ID документа (IDDoc).
    Чтобы найти нужные записи в файлах регистра, нам нужен уникальный идентификатор документа. Получить его можно несколькими способами:
    • С помощью компоненты 1C++ или MetaDataWork. Это самый простой способ, если у вас установлены эти компоненты.
      
      // Требуется компонента MetaDataWork
      Метадата = СоздатьОбъект("MetaDataWork");
      // В переменной ТвойДок - ссылка на нужный документ
      Сообщить(Метадата.ЗначениеВСтрокуБД(ТвойДок));
      
      Результатом будет короткая строка, например, ' 44DL ', которая и является искомым ID.
    • С помощью встроенной функции ЗначениеВСтрокуВнутр(). Этот способ не требует внешних компонент, но сложнее, так как результат нужно парсить.
      
      // В переменной ТвойДок - ссылка на нужный документ
      ВнутрПредставление = ЗначениеВСтрокуВнутр(ТвойДок); 
      // Результат будет вида: {"O", ... ,"     5136   192297  "}
      // Из этой строки нужно извлечь и преобразовать ID.
      
  2. Найти и удалить записи в DBF-файле регистра.
    • Закройте 1С:Предприятие.
    • Откройте каталог с вашей базой данных. Движения регистров хранятся в файлах с именами RA[НомерРегистра].DBF (для регистров остатков) и RG[НомерРегистра].DBF (для регистров оборотов). В обсуждаемом примере это был файл RA45.DBF.
    • Откройте нужный DBF-файл с помощью любого редактора DBF, например, WinDBFView.exe, DBF Navigator или плагина в Total Commander.
    • В таблице будет колонка (поле), содержащая ID документа-регистратора. Отфильтруйте или найдите записи, у которых значение в этом поле совпадает с ID, полученным на предыдущем шаге.
    • Удалите найденные строки. Это и есть "фантомные" движения.
    • Сохраните изменения в DBF-файле и закройте редактор.
  3. Запустить пересчет итогов.
    После прямого вмешательства в файлы данных необходимо заставить 1С пересчитать свои внутренние таблицы итогов. Зайдите в 1С:Предприятие в монопольном режиме и запустите полный пересчет итогов (Операции -> Управление оперативными итогами).

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

Дополнительное замечание по коду запроса

В ходе обсуждения также был затронут вопрос о разнице между двумя вариантами группировки в запросе:

Вариант 1 (как в исходном коде):


|ТекДок = Регистр.Остатки.ТекущийДокумент;
|Группировка ТекДок;

Вариант 2 (предопределенная группировка):

|Группировка Документ;

Хотя результат в большинстве случаев будет идентичным, использование предопределенной группировки Документ считается более правильным и потенциально более быстрым, так как система использует для этого оптимизированный механизм.

← На главную