В процессе разработки отчетов или обработок в системе 1С:Предприятие (особенно в таких конфигурациях, как УПП или Комплексная автоматизация 1.1) программисты часто сталкиваются с необходимостью классифицировать документ поступления. Проблема заключается в том, что документ ПоступлениеТоваровУслуг является универсальным и может содержать данные о материальных ценностях, услугах, работах и даже оборудовании. Разберем подробно, как правильно и эффективно определить, что именно пришло по документу, и какие подводные камни нас ожидают.
Это самый простой и интуитивно понятный способ, который предложил автор темы. Логика заключается в проверке количества строк в различных табличных частях документа. В 1С:УПП документ поступления имеет несколько ключевых таблиц: Товары, Услуги, Оборудование, Тара.
Проанализируем ситуацию, когда нам нужно быстро понять состав документа. Мы можем использовать следующий алгоритм: если заполнена только одна таблица, мы присваиваем документу соответствующий статус. Рассмотрим пример кода:
КолТоваров = ОбъектДокумента.Товары.Количество();
КолУслуг = ОбъектДокумента.Услуги.Количество();
КолОборудования = ОбъектДокумента.Оборудование.Количество();
Если КолТоваров > 0 И КолУслуг = 0 И КолОборудования = 0 Тогда
// Это чисто товарное поступление
Результат = "Товары";
ИначеЕсли КолУслуг > 0 И КолТоваров = 0 И КолОборудования = 0 Тогда
// Чистое поступление услуг
Результат = "Услуги";
ИначеЕсли КолТоваров > 0 И КолУслуг > 0 Тогда
// Смешанный тип документа
Результат = "Смешанный";
Иначе
// Обработка исключений (например, только тара или оборудование)
Результат = "Прочее";
КонецЕсли;
Важно: этот метод имеет существенный недостаток. Пользователь может по ошибке внести услугу (например, "Доставка") в табличную часть Товары, выбрав соответствующий элемент справочника Номенклатура. В этом случае проверка табличных частей выдаст неверный результат.
Более надежный способ — проанализировать содержимое строк. У каждого элемента справочника Номенклатура есть реквизит ТипНоменклатуры (или ВидНоменклатуры, в зависимости от версии и настроек конфигурации), который представляет собой перечисление: Товар, Услуга, Работа или Набор.
Рассмотрим, как реализовать проверку по типам номенклатуры, обходя все строки документа. Проанализируем пример функции, которая определяет «товарную сущность» документа:
Функция ОпределитьТипСоставаДокумента(СсылкаНаДокумент)
ЕстьТовары = Ложь;
ЕстьУслуги = Ложь;
// Проверяем ТЧ "Товары"
Для Каждого СтрокаТЧ Из СсылкаНаДокумент.Товары Цикл
Если СтрокаТЧ.Номенклатура.Услуга Тогда // В УПП часто используется булево "Услуга"
ЕстьУслуги = Истина;
Иначе
ЕстьТовары = Истина;
КонецЕсли;
КонецЦикла;
// Проверяем ТЧ "Услуги"
Если СсылкаНаДокумент.Услуги.Количество() > 0 Тогда
ЕстьУслуги = Истина;
КонецЕсли;
Если ЕстьТовары И ЕстьУслуги Тогда
Возврат "Смешанный";
ИначеЕсли ЕстьТовары Тогда
Возврат "Товары";
КонецЕсли;
Возврат "Услуги";
КонецФункции
В этом примере мы учитываем, что в табличной части Товары технически может оказаться номенклатура с признаком Услуга = Истина. Это позволяет избежать ошибок классификации при некорректном вводе данных пользователем.
Если нам нужно обработать список документов (как в случае автора темы), использование объектной модели (получение каждого документа и перебор строк) крайне неэффективно с точки зрения производительности. Выясним, как решить задачу одним запросом.
Посмотрим на пример запроса, который определяет наличие товаров и услуг в документе, используя объединение таблиц:
ВЫБРАТЬ
Док.Ссылка КАК Ссылка,
МАКСИМУМ(ЕСТЬNULL(Типы.ЭтоТовар, ЛОЖЬ)) КАК СодержитТовары,
МАКСИМУМ(ЕСТЬNULL(Типы.ЭтоУслуга, ЛОЖЬ)) КАК СодержитУслуги
ИЗ
Документ.ПоступлениеТоваровУслуг КАК Док
ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ
Товары.Ссылка КАК Ссылка,
ИСТИНА КАК ЭтоТовар,
ЛОЖЬ КАК ЭтоУслуга
ИЗ
Документ.ПоступлениеТоваровУслуг.Товары КАК Товары
ГДЕ
НЕ Товары.Номенклатура.Услуга
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Услуги.Ссылка,
ЛОЖЬ,
ИСТИНА
ИЗ
Документ.ПоступлениеТоваровУслуг.Услуги КАК Услуги
) КАК Типы ПО Док.Ссылка = Типы.Ссылка
ГДЕ
Док.Ссылка В (&МассивСсылок)
СГРУППИРОВАТЬ ПО
Док.Ссылка
Данный подход позволяет за один вызов к базе данных получить флаги содержимого для всех документов в списке. Это значительно ускоряет работу обработки.
Иногда самым точным способом является анализ движений, которые сделал документ. Если документ ПоступлениеТоваровУслуг сделал движения по регистру ПартииТоваровНаСкладах (в УПП) или ТоварыНаСкладах, значит, в нем точно были материальные ценности. Если же движения есть только в регистре Затраты или Закупки (по номенклатуре с типом "Услуга"), то это услуга.
Преимущества этого метода:
Как было верно замечено в обсуждении, реквизит ВидОперации может дать подсказку. Например:
ПоступлениеУслугПрочихАктивов.Проанализируем различие между услугами и работами. С точки зрения 1С, услуга не имеет себестоимости в классическом понимании и не хранится на складе. Работа же может иметь производственную себестоимость. При написании кода важно помнить, что работы часто попадают в ту же табличную часть, что и услуги, но требуют иного отражения в регистрах. Если ваша задача связана с распределением затрат, обязательно проверяйте ТипНоменклатуры на значение Работа.
Для создания надежной обработки мы рекомендуем комбинированный подход:
Услуга (или ТипНоменклатуры) у каждой позиции.Иначе для случаев, когда документ заполнен некорректно (например, пустые обе ТЧ) или содержит смешанный состав, чтобы вывести предупреждение пользователю.Следуя этим шагам, вы создадите устойчивый к ошибкам алгоритм, который будет корректно работать даже при нестандартном заполнении документов пользователями.