Как найти и подобрать документы по идентичному содержанию их табличных частей в 1С

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

В практике сопровождения систем на базе 1С часто возникает ситуация, когда между документами (например, приходом и списанием) не были установлены явные связи (через реквизит ДокументОснование или ведущие регистры). Если таких документов накопилось много за несколько лет, ручной поиск превращается в кошмар. Рассмотрим, как автоматизировать процесс подбора пар документов, основываясь на идентичности их табличных частей Товары.

Постановка задачи и основные сложности

Представим ситуацию: нам нужно найти документ оприходования, который соответствует конкретному документу списания. Единственный критерий — в обоих документах должен быть одинаковый набор товаров и их количеств. Основные проблемы, с которыми мы сталкиваемся:

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

Способ 1: Прямое сопоставление через временные таблицы и группировки

Первым делом проанализируем подход с использованием запроса. Чтобы избежать проблем с дублированием строк, мы должны сначала «свернуть» табличные части обоих документов по номенклатуре (и, если есть, по характеристикам). Рассмотрим пример запроса, который собирает данные из документов СписаниеНедостачТоваров и ВводОстатков.

Сначала подготовим данные по списаниям во временной таблице:


ВЫБРАТЬ
    СписаниеТовары.Ссылка КАК Ссылка,
    СписаниеТовары.Номенклатура КАК Номенклатура,
    СУММА(СписаниеТовары.Количество) КАК Количество
ПОМЕСТИТЬ втСписано
ИЗ
    Документ.СписаниеНедостачТоваров.Товары КАК СписаниеТовары
ГДЕ
    СписаниеТовары.Ссылка.Проведен
    И СписаниеТовары.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
СГРУППИРОВАТЬ ПО
    СписаниеТовары.Ссылка,
    СписаниеТовары.Номенклатура;

Затем аналогичным образом подготовим данные по документам прихода (например, ВводОстатков или ПрочееОприходованиеТоваров):


ВЫБРАТЬ
    ПриходТовары.Ссылка КАК Ссылка,
    ПриходТовары.Номенклатура КАК Номенклатура,
    СУММА(ПриходТовары.Количество) КАК Количество
ПОМЕСТИТЬ втПриход
ИЗ
    Документ.ВводОстатков.Товары КАК ПриходТовары
ГДЕ
    ПриходТовары.Ссылка.Проведен
СГРУППИРОВАТЬ ПО
    ПриходТовары.Ссылка,
    ПриходТовары.Номенклатура;

Способ 2: Использование «цифровых отпечатков» (сигнатур) табличных частей

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

Рассмотрим логику: если в Документе №1 сумма количеств равна 12 и в нем 3 уникальных товара, а в Документе №2 те же показатели, то с высокой долей вероятности это наши кандидаты на соответствие. Проанализируем, как это выглядит в коде:


ВЫБРАТЬ
    втСписано.Ссылка КАК ДокСписания,
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ втСписано.Номенклатура) КАК ВсегоСтрок,
    СУММА(втСписано.Количество) КАК ОбщееКоличество
ПОМЕСТИТЬ втСигнатурыСписания
ИЗ
    втСписано КАК втСписано
СГРУППИРОВАТЬ ПО
    втСписано.Ссылка;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    втПриход.Ссылка КАК ДокПрихода,
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ втПриход.Номенклатура) КАК ВсегоСтрок,
    СУММА(втПриход.Количество) КАК ОбщееКоличество
ПОМЕСТИТЬ втСигнатурыПрихода
ИЗ
    втПриход КАК втПриход
СГРУППИРОВАТЬ ПО
    втПриход.Ссылка;

Теперь мы можем быстро соединить эти две таблицы по ВсегоСтрок и ОбщееКоличество. Это мгновенно отсеет 99% неподходящих документов.

Учет временного фактора: фильтрация по датам

Как отмечалось в обсуждении, поиск по всей базе за 5 лет выдаст множество ложных совпадений (одни и те же наборы товаров могут списываться ежемесячно). Выясним, как правильно наложить ограничение по времени. Проанализируем два варианта условия в блоке ГДЕ:

  1. Использование РАЗНОСТЬДАТ: Позволяет найти документы, созданные в пределах 5 дней друг от друга.
    
    ГДЕ
        РАЗНОСТЬДАТ(ДокСписания.Дата, ДокПрихода.Дата, ДЕНЬ) МЕЖДУ -5 И 5
    
  2. Использование периодов: С точки зрения производительности SQL, лучше заранее рассчитать границы дат и использовать МЕЖДУ, чтобы система могла использовать индексы.

Важно: Специалисты рекомендуют использовать именно РАЗНОСТЬДАТ для гибкости, но при очень больших объемах данных лучше заранее подготовить выборку по периоду.

Метод полной проверки (Хеширование)

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

1. Выгружаем ТЧ документа в таблицу значений.
2. Сортируем таблицу по номенклатуре (и характеристикам).
3. Формируем строку вида "IDНоменклатуры_Количество;IDНоменклатуры_Количество;".
4. От этой строки вычисляем MD5 или другой хеш-код.

Хранение такого хеша в дополнительном реквизите позволит находить точные копии документов за доли секунды. В типовых конфигурациях 1С для этого можно использовать функции платформы или БСП.

Итоговый алгоритм решения

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

  1. Группировка: Сворачиваем табличные части по номенклатуре во временных таблицах.
  2. Первичный отбор: Соединяем документы по «сигнатурам» (количество строк и общая сумма) и по складу.
  3. Временной фильтр: Ограничиваем поиск интервалом +/- 5 рабочих дней.
  4. Проверка на уникальность: Если для одного документа списания нашелся только один документ прихода — помечаем их как связанные автоматически.
  5. Ручной разбор: Если система нашла несколько подходящих документов («неоднозначность»), выводим их пользователю для принятия окончательного решения.

Рассмотрим пример финального соединения, который объединяет логику сопоставления:


ВЫБРАТЬ
    Списания.ДокСписания,
    Приходы.ДокПрихода
ИЗ
    втСигнатурыСписания КАК Списания
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ втСигнатурыПрихода КАК Приходы
    ПО Списания.ВсегоСтрок = Приходы.ВсегоСтрок
    И Списания.ОбщееКоличество = Приходы.ОбщееКоличество
ГДЕ
    РАЗНОСТЬДАТ(Списания.ДокСписания.Дата, Приходы.ДокПрихода.Дата, ДЕНЬ) МЕЖДУ -5 И 5
    И Списания.ДокСписания.Склад = Приходы.ДокПрихода.Склад

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

← На главную