При интеграции 1С с внешними приложениями через COM-соединение (V83.COMConnector или V83.Application) разработчики часто сталкиваются с необъяснимым поведением системы. Одной из классических проблем является ситуация, когда запрос, идеально работающий в консоли 1С, при выполнении из VBA (Excel) возвращает некорректные значения в числовых полях, особенно в поле Количество. Вместо фактического количества товара во всех строках может дублироваться одно и то же число, равное общему количеству записей в результате запроса.
В этой статье мы подробно разберем, почему возникает эта «магия», проанализируем технические нюансы взаимодействия 1С и Excel через COM и рассмотрим несколько эффективных способов решения проблемы.
Разберем ситуацию: когда мы выполняем запрос в 1С и получаем объект ВыборкаИзРезультатаЗапроса, мы привыкли обращаться к полям через точку, например Выборка.Количество. Однако стоит помнить, что в объектной модели 1С у самой выборки есть встроенный системный метод Количество(), который возвращает общее число записей (строк) в этой выборке.
При работе внутри 1С платформа понимает контекст. Но при обращении через COM-интерфейс из Excel VBA возникает конфликт имен. Библиотека типов COM в первую очередь ищет методы и свойства самого объекта. Поскольку у объекта выборки есть метод Количество, VBA получает результат выполнения этого метода (число строк), игнорируя одноименное поле из данных запроса. Именно поэтому, если в вашем заказе 105 строк, в колонке «Количество» для каждой позиции вы увидите число 105.
Первое, что приходит на ум — переименовать поле в запросе. Мы можем задать псевдоним, который не совпадает с системными именами 1С. Однако здесь важно не только изменить текст запроса, но и изменить код в самом VBA.
Рассмотрим пример правильного переименования в тексте запроса:
ВЫБРАТЬ
ЗаказПокупателя.Номенклатура.Наименование КАК Номенклатура,
ЗаказПокупателя.Количество КАК КоличествоТовара
ИЗ
Документ.ЗаказПокупателя.Товары КАК ЗаказПокупателя
После изменения запроса в VBA коде необходимо обращаться именно к новому псевдониму. Если вы оставите Selection.Количество, вы снова получите число строк. Нужно писать так:
' Пример обращения в VBA
ActiveSheet.Cells(i, 2).Value = Selection.КоличествоТовара
Важный нюанс: иногда использование кириллических псевдонимов (например, Колво) также может давать сбои из-за особенностей маршалинга COM. В сложных случаях рекомендуется использовать латинские псевдонимы, например Quantity.
Если мы не хотим или не можем менять псевдонимы в запросе, существует более надежный способ обхода конфликта имен. Мы можем обратиться к значению поля не через прямое свойство, а через коллекцию полей по индексу или по строковому имени с помощью метода Получить() (или обращения к коллекции Параметры, в зависимости от типа объекта).
Проанализируем ситуацию: обращение по индексу гарантирует, что мы обращаемся к данным строки, а не к свойствам объекта выборки. Посмотрите, как это реализовать:
' Вместо Selection.Количество используем доступ к полю по индексу
' Предположим, поле Количество идет 14-м по счету в запросе (индекс 13)
Value = Selection.Get(13)
Этот метод полностью снимает проблему «перекрытия» имен, так как мы явно указываем COM-объекту, что нам нужно значение из колонки данных.
Часто проблема с полем Количество возникает при прямом обращении к табличным частям документов (Документ.ЗаказПокупателя.Товары). Это не самый оптимальный путь с точки зрения производительности и структуры данных.
Рассмотрим альтернативный подход — использование регистров накопления (например, ЗаказыПокупателей). В регистрах данные уже агрегированы, и структура полей зачастую прозрачнее. Посмотрим на пример изменения структуры запроса:
ВЫБРАТЬ
ЗаказыПокупателейОстаткиИОбороты.Номенклатура,
ЗаказыПокупателейОстаткиИОбороты.КоличествоПриход КАК Колво
ИЗ
РегистрНакопления.ЗаказыПокупателей.ОстаткиИОбороты(&Дата1, &Дата2, , , ) КАК ЗаказыПокупателейОстаткиИОбороты
Использование виртуальных таблиц регистров позволяет избежать вложенных запросов к табличным частям и снижает вероятность конфликтов типов данных при передаче через COM-соединение.
Иногда Excel VBA некорректно интерпретирует типы данных 1С (объекты типа StandardNumber). Чтобы гарантировать, что число передается как число, мы можем использовать функцию ВЫРАЗИТЬ непосредственно в тексте запроса.
Проанализируем пример:
ВЫБРАТЬ
ВЫРАЗИТЬ(ЗаказПокупателя.Количество КАК ЧИСЛО(15, 3)) КАК ТочноеКоличество
ИЗ
Документ.ЗаказПокупателя.Товары КАК ЗаказПокупателя
Это заставляет 1С подготовить данные в формате, который легче конвертируется в тип Double или Decimal внутри VBA, что повышает стабильность выгрузки.
Мы выяснили, что корень проблемы — не ошибка в логике запроса, а особенность взаимодействия объектных моделей двух разных систем. При работе с COM-соединением всегда следуйте этим правилам:
Количество, Сумма, Номер).Selection.Get(i).ВЫРАЗИТЬ для числовых полей и дат, чтобы избежать ошибок интерпретации в Excel.Применяя эти методы, вы сможете создавать надежные отчеты, которые будут корректно выгружать данные из 1С в Excel без «магических» ошибок и неверных цифр.