Как подобрать комбинации документов для закрытия суммы эквайринга?

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

Часто в работе бухгалтерии или отдела продаж возникает задача: банк присылает общую сумму поступления по эквайрингу, а в системе числится множество документов ОплатаОтПокупателяПлатежнойКартой с разными суммами. Задача состоит в том, чтобы подобрать документы, сумма которых точно (или максимально близко) соответствует приходу от банка. Давайте разберемся, как подходить к этому вопросу профессионально.

Анализ проблемы и критика метода перебора

Многие разработчики, столкнувшись с этой задачей впервые, пытаются решить её «в лоб» — с помощью кросс-соединений (CROSS JOIN) нескольких таблиц в одном запросе 1С. Рассмотрим, почему это не лучший путь:

  1. Ресурсоемкость: Если количество документов для анализа превышает 10-15 штук, количество комбинаций растет экспоненциально. Запрос начинает выполняться минуты, а то и вовсе вешает сервер.
  2. NP-полная задача: В информатике это классическая «Задача о сумме подмножества». Попытка решить её средствами СУБД — это попытка заставить базу данных выполнять математические вычисления, для которых она не предназначена.
  3. Логика учета: Как справедливо заметили наши коллеги в обсуждении, автоматический подбор «идеальной комбинации» может быть избыточным. Банк платит за совокупность операций, и привязка конкретных оплат — это скорее вопрос хронологии, чем математического пазла.

Метод первый: «Жадный алгоритм» (ФИФО)

Прежде чем приступать к написанию сложных алгоритмов, зададимся вопросом: действительно ли нам нужно «подбирать» суммы? Чаще всего в управленческом учете используется принцип ФИФО (первым пришел — первым ушел). Вместо поиска комбинации, которая дает сумму 100 рублей, мы просто закрываем самые старые неоплаченные документы, пока сумма поступления не будет исчерпана.

Почему это лучше:

Метод второй: Рекурсивный поиск в оперативной памяти

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


// Пример упрощенной логики подбора через рекурсию в памяти
Функция НайтиКомбинацию(Суммы, ЦелеваяСумма, Индекс = 0, ТекущаяСумма = 0)
    // Базовые условия выхода из рекурсии...
    // Итерация по списку сумм документов
КонецФункции

Разберем, почему перенос вычислений в код 1С эффективнее:

  1. Вы работаете с объектом Массив или СписокЗначений в оперативной памяти сервера.
  2. Вы полностью контролируете глубину стека и условия остановки алгоритма.
  3. Вы избегаете лишних обращений к SQL-серверу, которые являются «узким местом» любого решения.

Как не стоит делать: пример неоптимального запроса

Для понимания того, чего стоит избегать, проанализируем структуру, которую часто предлагают в попытках решить задачу через ВТ (Временные таблицы):


ВЫБРАТЬ
    ВТ_Множества_1.ОплатаКартой КАК Оплата1,
    ВТ_Множества_2.ОплатаКартой КАК Оплата2,
    ВТ_Множества_1.Сумма + ВТ_Множества_2.Сумма КАК Итого
ИЗ
    ВТ_Множества КАК ВТ_Множества_1,
    ВТ_Множества КАК ВТ_Множества_2
ГДЕ
    ВТ_Множества_1.ОплатаКартой <> ВТ_Множества_2.ОплатаКартой

Этот код создает декартово произведение. Если у вас 100 документов, запрос попытается создать таблицу из 10 000 строк. Если добавить 3-й уровень (3 документа в связке), это будет уже 1 000 000 строк. Никогда не используйте подобные конструкции для больших объемов данных — это приведет к блокировкам таблиц и падению производительности всей конфигурации.

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

В завершение, подведем итог, как вам лучше поступить:

  1. Оцените необходимость: Поговорите с бухгалтерией. Если нет жесткого требования подбирать документы под сумму, внедряйте ФИФО. Это сэкономит недели разработки и отладки.
  2. Используйте память: Если подбор необходим — выгружайте список сумм в Массив и используйте алгоритмы динамического программирования или классический поиск в глубину на встроенном языке.
  3. Ограничивайте выборку: Если документов много, делите задачу на части. Используйте метод «встречного поиска» (разбиение множества пополам), чтобы сократить пространство перебора.

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

← На главную