Почему пропадают суммы в Видах запасов Отчета комиссионера и как исправить логику распределения в 1С:ERP

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

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

Рассмотрим подробнее, как работает процедура ЗаполнитьДопКолонкиВидовЗапасов, почему типовой алгоритм с использованием функций Мин() может приводить к потере части выручки и как это исправить.

Механизм работы Видов запасов в 1С:ERP

Для начала проанализируем, зачем вообще нужна табличная часть ВидыЗапасов. В 1С:ERP это служебный механизм, который определяет, какой именно товар (с какой ГТД, какой собственности — собственной или комиссионной) списывается в момент продажи. В отчете комиссионера ситуация осложняется тем, что один и тот же товар может быть продан разным конечным покупателям по разным ценам в рамках одного документа.

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

Проблема использования функции Мин в распределении сумм

Разберем фрагмент кода, который вызывает наибольшее количество вопросов у разработчиков. В процедуре ЗаполнитьДопКолонкиВидовЗапасов для документа ОтчетКомиссионера встречается следующий алгоритм:


Если СтрокаЗапасов.Количество Тогда
    НоваяСтрока.СуммаСНДС = Мин(СуммаСНДСПоСтроке, СтрокаЗапасов.СуммаСНДС);
    НоваяСтрока.СуммаНДС = Мин(СуммаНДСПоСтроке, СтрокаЗапасов.СуммаНДС);
    НоваяСтрока.СуммаВознаграждения = Мин(СуммаВознагражденияПоСтроке, СтрокаЗапасов.СуммаВознаграждения);
    НоваяСтрока.СуммаНДСВознаграждения = Мин(СуммаНДСВознагражденияПоСтроке, СтрокаЗапасов.СуммаНДСВознаграждения);
Иначе
    // Логика для сторно-записей
    НоваяСтрока.СуммаСНДС = Макс(СуммаСНДСПоСтроке, СтрокаЗапасов.СуммаСНДС);
КонецЕсли;

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

  1. Система рассчитывает «среднюю» сумму на единицу товара по всем видам запасов.
  2. Если у одного покупателя цена выше этой средней, функция Мин просто «обрезает» излишек.
  3. Обрезанная разница (копейки или даже существенные суммы) не переносится в другие строки, а просто пропадает из таблицы видов запасов.

В результате в бухгалтерском учете проводки по счету 90.01 формируются на основании ТЧ Товары, а движения по регистрам себестоимости и НДС — на основании ТЧ ВидыЗапасов. Так возникает разрыв.

Анализ структуры поиска: почему данные «смешиваются»

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


// Группировка данных выполняется широко
ИменаКолонокГруппировки = "АналитикаУчетаНоменклатуры, Упаковка, ДатаСчетаФактурыКомиссионера, Покупатель, НомерСчетаФактурыКомиссионера";

// А поиск выполняется узко
СтруктураПоиска = Новый Структура("АналитикаУчетаНоменклатуры");

Здесь и кроется главная ошибка. Таблица сгруппирована с учетом покупателя и счета-фактуры, но когда код пытается найти строку СтрокаЗапасов для заполнения сумм, он берет первую попавшуюся строку с этой номенклатурой (АналитикаУчетаНоменклатуры), игнорируя покупателя. Если в документе один и тот же товар продан Иванову за 1000 руб. и Петрову за 2000 руб., поиск может найти строку Иванова для данных Петрова, и функция Мин отсечет «лишние» 1000 рублей.

Как решить проблему программно

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

Посмотрим на пример правильного формирования структуры поиска:


// Дополняем структуру поиска ключевыми полями, по которым была группировка
СтруктураПоиска = Новый Структура;
СтруктураПоиска.Вставить("АналитикаУчетаНоменклатуры", СтрокаТовары.АналитикаУчетаНоменклатуры);
СтруктураПоиска.Вставить("Покупатель", СтрокаТовары.Покупатель);
СтруктураПоиска.Вставить("НомерСчетаФактурыКомиссионера", СтрокаТовары.НомерСчетаФактурыКомиссионера);
СтруктураПоиска.Вставить("ДатаСчетаФактурыКомиссионера", СтрокаТовары.ДатаСчетаФактурыКомиссионера);

После такого изменения алгоритм Мин(СуммаСНДСПоСтроке, СтрокаЗапасов.СуммаСНДС) будет сравнивать сравнимые величины — выручку по конкретному покупателю с этой же выручкой, предварительно зафиксированной в видах запасов, и «обрезания» сумм происходить не будет.

Рекомендации по работе без изменения кода

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

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

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

← На главную