Как программно получить данные из Актов и Счетов-фактур для переноса между базами 1С

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

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

Разберем детально, как устроено хранение данных в 1С, как функционируют связанные печатные формы и как спроектировать надежный обмен информацией по веб-сервису.

Развеиваем мифы: где на самом деле хранятся данные печатных форм

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

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

Проанализируем структуру хранения на примере стандартного документа РеализацияТоваровУслуг:

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

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


// Пример прямого обхода табличной части документа по ссылке
Для Каждого СтрокаУслуг Из СсылкаНаДокумент.Услуги Цикл
    НаименованиеУслуги = СтрокаУслуг.Номенклатура.Наименование;
    СодержаниеУслуги = СтрокаУслуг.Содержание;
    СуммаБезНДС = СтрокаУслуг.Сумма;
    СуммаНДС = СтрокаУслуг.СуммаНДС;
    // Данные готовы к передаче в веб-сервис
КонецЦикла;

Как технически устроены ссылки на Акт и Счет-фактуру внизу формы

В типовых решениях на обычных формах в нижней части документа часто выводятся интерактивные надписи (гиперссылки), сообщающие о наличии связанных документов — например, «Акт об оказании услуг №...» или «Счет-фактура №...».

Выясним причину их появления. Это результат работы динамического кода формы документа. При открытии или записи объекта система выполняет специализированные запросы для поиска подчиненных документов.

В случае со Счетом-фактурой связь организуется по реквизиту ДокументОснование, который присутствует в документе СчетФактураВыданный. Программа выполняет запрос к базе данных, передавая ссылку на текущую «Реализацию» в качестве параметра:


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

Запрос.УстановитьПараметр("ДокументОснование", СсылкаНаРТиУ);
РезультатЗапроса = Запрос.Выполнить();

Если запрос возвращает запись, форма программно делает видимой надпись-гиперссылку и заполняет ее текст строковым представлением найденного Счета-фактуры.

В случае с Актом выполненных работ ситуация несколько отличается. Часто в отечественных конфигурациях Акт не является самостоятельным документом, а представляет собой лишь одну из печатных форм документа РеализацияТоваровУслуг. Название гиперссылки внизу может генерироваться на основе реквизитов самой «Реализации» (номер и дата), либо ссылаться на сохраненный во внешнем хранилище файл (если внедрен функционал присоединенных файлов библиотеки стандартных подсистем).

Как определить, какой макет использовался для формирования Акта

В одном документе может присутствовать несколько макетов печатных форм (например, устаревшие бланки за прошлые годы и актуальные новые). Выбор конкретного макета закладывается разработчиками в Модуле объекта документа.

Рассмотрим по шагам, как найти эту логику в Конфигураторе:

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

Именно внутри этой процедуры реализован выбор макета в зависимости от различных условий (даты документа, настроек учетной политики или параметров учетной записи организации). Пример такой логики:


Функция Печать(ИмяМакета, КоличествоЭкземпляров = 1, НаПринтер = Ложь) Экспорт
    
    // Выясним, какой макет затребован пользователем
    Если ИмяМакета = "Акт" Тогда
        // Проверяем дату документа для выбора нужной версии макета
        Если ЭтотОбъект.Дата < '20150101' Тогда
            Макет = ПолучитьМакет("Акт_Старый");
        Иначе
            Макет = ПолучитьМакет("Акт_Новый");
        КонецЕсли;
        
        // Далее следует код заполнения областей макета данными из реквизитов документа
        ...
    КонецЕсли;
    
КонецФункции

Важное примечание: Обратите внимание, что печать может осуществляться через механизм Внешних печатных форм. Если в модуле объекта вы не нашли нужный алгоритм, проверьте состав дополнительных обработок в режиме «1С:Предприятие» (обычно хранятся в справочнике ДополнительныеОтчетыИОбработки или ВнешниеОбработки). При их использовании код заполнения и сам макет хранятся внутри внешней обработки .epf.

Проектирование веб-сервиса для переноса данных в другую базу

Поскольку во второй (приемной) базе у нас спроектировано кастомное решение, где Акты и Счета-фактуры должны создаваться как отдельные физические документы, передавать готовые макеты или файлы не имеет практического смысла. Правильный подход — передавать чистые структурированные данные через веб-сервис в формате JSON или XML, а сами макеты и логику печати реализовать локально в базе-приемнике.

Посмотрим на пример реализации веб-сервиса на стороне базы-источника (Обычные формы):


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

Теперь проанализируем, как должен выглядеть обработчик на стороне базы-приемника (Управляемые формы), получающий эту JSON-строку:


Процедура ИмпортироватьДокумент(СтрокаJSON) Экспорт
    
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
    Данные = ПрочитатьJSON(ЧтениеJSON);
    ЧтениеJSON.Закрыть();
    
    // Важно: Сопоставление контрагентов производим по уникальному бизнес-ключу (ИНН), а не по внутреннему ID!
    КонтрагентСсылка = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", Данные.КонтрагентИНН);
    Если КонтрагентСсылка.Пустая() Тогда
        // Опционально: создаем нового контрагента или пишем в лог ошибок
        ВызватьИсключение "Контрагент с ИНН " + Данные.КонтрагентИНН + " не обнаружен в базе-приемнике!";
    КонецЕсли;
    
    // Создаем документ Акт выполненных работ в нашей системе
    НовыйАкт = Документы.АктВыполненныхРабот.СоздатьДокумент();
    НовыйАкт.Дата = Данные.Дата;
    НовыйАкт.Номер = Данные.Номер;
    НовыйАкт.Контрагент = КонтрагентСсылка;
    
    Для Каждого СтрокаУслуги Из Данные.Услуги Цикл
        НоваяСтрока = НовыйАкт.Услуги.Добавить();
        
        // Ищем или создаем номенклатуру по наименованию
        НоменклатураСсылка = Справочники.Номенклатура.НайтиПоНаименованию(СтрокаУслуги.Номенклатура);
        Если НоменклатураСсылка.Пустая() Тогда
            НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();
            НовыйЭлемент.Наименование = СтрокаУслуги.Номенклатура;
            НовыйЭлемент.Записать();
            НоменклатураСсылка = НовыйЭлемент.Ссылка;
        КонецЕсли;
        
        НоваяСтрока.Номенклатура = НоменклатураСсылка;
        НоваяСтрока.Количество = СтрокаУслуги.Количество;
        НоваяСтрока.Цена = СтрокаУслуги.Цена;
        НоваяСтрока.Сумма = СтрокаУслуги.Сумма;
    КонецЦикла;
    
    НовыйАкт.Записать(РежимЗаписиДокумента.Проведение);
    
    // Если в источнике был Счет-фактура, создаем его в связке с Актом
    Если Данные.ЕстьСчетФактура Тогда
        НовыйСФ = Документы.СчетФактураВыданный.СоздатьДокумент();
        НовыйСФ.Дата = Данные.СФДата;
        НовыйСФ.Номер = Данные.СФНомер;
        НовыйСФ.ДокументОснование = НовыйАкт.Ссылка;
        // Заполняем остальные реквизиты СФ...
        НовыйСФ.Записать(РежимЗаписиДокумента.Проведение);
    КонецЕсли;
    
КонецПроцедуры

Рекомендации по реализации печатных форм в новой базе

Для того чтобы клиенты могли просматривать и распечатывать Акты и Счета-фактуры непосредственно в самописной базе на управляемых формах, создайте в ней собственные макеты печатных форм:

← На главную