При автоматизации бизнес-процессов в среде 1С:Предприятие 8 часто возникает необходимость программного создания документов на основе внешних источников данных (текстовых файлов, XML, JSON или внешних API). Одной из типовых задач является автоматическая генерация документа СчетНаОплатуПокупателю. Однако разработчики часто сталкиваются с неожиданной трудностью: на форме счета есть поле «Срок оплаты», но при попытке обратиться к нему напрямую через свойства созданного объекта (например, Счет.СрокОплаты) система выдает ошибку о том, что данный реквизит не обнаружен.
В этой статье мы подробно разберем, почему так происходит, как устроена архитектура хранения срока оплаты в современных конфигурациях 1С (таких как «Бухгалтерия предприятия 3.0»), и напишем готовый к использованию программный код с учетом клиент-серверного взаимодействия.
Выясним причину этой архитектурной особенности. В управляемых концепциях 1С разработчики фирмы «1С» стремятся оптимизировать структуру таблиц базы данных. Реквизит «Срок оплаты» используется преимущественно для оперативного контроля дебиторской задолженности, напоминаний и анализа бизнес-метрик. Его вынесли за рамки физической таблицы документа СчетНаОплатуПокупателю.
На самом деле этот показатель хранится в независимом регистре сведений СрокиОплатыДокументов. Когда пользователь интерактивно открывает форму счета, система динамически считывает данные из этого регистра и отображает их на форме. При сохранении счета измененная дата оплаты записывается обратно в регистр сведений.
Таким образом, чтобы программно установить срок оплаты для нового счета, нам необходимо сначала записать сам документ (чтобы получить уникальную ссылку Счет.Ссылка), а затем сделать соответствующую запись в регистр сведений СрокиОплатыДокументов.
Проанализируем ситуацию с клиент-серверным разделением прав и обязанностей. В коде из обсуждения автор пытается выполнять чтение текстового файла и открытие формы в одном контексте, что приводит к критическим ошибкам:
ПолучитьФорму() вызывает ошибку «Интерактивные операции не доступны».Правильный алгоритм работы должен выглядеть следующим образом:
СчетНаОплатуПокупателю, заполняем его реквизиты, записываем объект в базу данных, программно добавляем запись в регистр сведений СрокиОплатыДокументов и возвращаем ссылку на созданный документ назад на клиент.Рассмотрим, как создать документ и заполнить его базовые реквизиты на сервере. Обратите внимание, что для корректного заполнения счетов по умолчанию (таких как банковские счета организации) мы используем стандартные механизмы конфигурации.
&НаСервере
Функция СоздатьСчетНаСервере(ДанныеФайла)
// Создаем новый объект документа
НовыйСчет = Документы.СчетНаОплатуПокупателю.СоздатьДокумент();
// Заполняем дату и базовые реквизиты
НовыйСчет.Дата = ТекущаяДата();
// Получаем организацию по умолчанию
ОсновнаяОрганизация = БухгалтерскийУчетПереопределяемый.ПолучитьЗначениеПоУмолчанию("ОсновнаяОрганизация");
НовыйСчет.Организация = ОсновнаяОрганизация;
НовыйСчет.ОрганизацияПолучатель = НовыйСчет.Организация;
// Заполняем банковский счет организации
НовыйСчет.СтруктурнаяЕдиница = ОсновнаяОрганизация.ОсновнойБанковскийСчет;
// Заполняем контрагента и договор (в реальной задаче данные берутся из структуры ДанныеФайла)
НовыйСчет.Контрагент = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", ДанныеФайла.ИНН);
НовыйСчет.ДоговорКонтрагента = Справочники.ДоговорыКонтрагентов.ПолучитьОсновнойДоговор(НовыйСчет.Контрагент, НовыйСчет.Организация);
НовыйСчет.Склад = Справочники.Склады.НайтиПоНаименованию("Основной склад", Ложь);
НовыйСчет.СуммаДокумента = ДанныеФайла.Сумма;
// Записываем документ, чтобы получить ссылку
НовыйСчет.Записать(РежимЗаписиДокумента.Запись);
// Теперь, когда у нас есть ссылка, мы можем установить срок оплаты
УстановитьСрокОплатыДокумента(НовыйСчет.Ссылка, ДанныеФайла.СрокОплаты);
Возврат НовыйСчет.Ссылка;
КонецФункции
Разберем подробно, как записать срок оплаты. Существует два способа сделать это. Первый — через вызов функций стандартной библиотеки (БСП), второй — прямой записью в регистр сведений. Посмотрим на оба варианта.
Вариант А. Использование стандартного общего модуля конфигурации
В типовых конфигурациях 1С:Бухгалтерия предусмотрен специализированный общий модуль СрокиОплатыДокументов. Это наиболее простой и правильный путь:
&НаСервере
Процедура УстановитьСрокОплатыДокумента(СсылкаНаДокумент, ДатаСрокаОплаты)
// Вызываем стандартный метод записи срока оплаты
СрокиОплатыДокументов.ЗаписатьСрокОплатыДокумента(СсылкаНаДокумент, ДатаСрокаОплаты);
КонецПроцедуры
Вариант Б. Прямая запись в регистр сведений СрокиОплатыДокументов
Если по какой-то причине в вашей конфигурации отсутствует указанный общий модуль или его структура изменена, мы можем записать данные напрямую через менеджер записи регистра сведений. Это гарантирует независимость кода от обновлений конфигурации:
&НаСервере
Процедура УстановитьСрокОплатыДокументаВручную(СсылкаНаДокумент, ДатаСрокаОплаты)
// Создаем менеджер записи для работы с конкретной строкой регистра
МенеджерЗаписи = РегистрыСведений.СрокиОплатыДокументов.СоздатьМенеджерЗаписи();
// Заполняем ключевые измерения
МенеджерЗаписи.Организация = СсылкаНаДокумент.Организация;
МенеджерЗаписи.Документ = СсылкаНаДокумент;
// Указываем ресурс (непосредственно дату, до которой должна пройти оплата)
МенеджерЗаписи.СрокОплаты = ДатаСрокаОплаты;
// Записываем данные с замещением существующих записей по этому документу
МенеджерЗаписи.Записать(Истина);
КонецПроцедуры
После того как документ успешно создан и записан на сервере, а срок оплаты зафиксирован в регистре сведений, хорошей практикой является вывод формы этого счета пользователю. Для этого мы должны передать ссылку на клиент и использовать правильные методы платформы.
Посмотрим на пример клиентского метода. Чтобы открыть форму конкретного существующего документа, нам необходимо передать его ссылку в параметре с ключевым именем Ключ:
&НаКлиенте
Процедура ИмпортироватьИОткрытьСчет()
// Шаг 1: Подготовка данных (в реальном коде здесь будет чтение вашего файла)
ДанныеФайла = Новый Структура;
ДанныеФайла.Вставить("ИНН", "7701020304");
ДанныеФайла.Вставить("Сумма", 150000);
// Установим срок оплаты, например, текущая дата плюс 5 дней
ДанныеФайла.Вставить("СрокОплаты", ТекущаяДата() + 5 * 24 * 60 * 60);
// Шаг 2: Создание документа на сервере
СсылкаНаНовыйСчет = СоздатьСчетНаСервере(ДанныеФайла);
// Шаг 3: Проверяем, что документ успешно создался
Если ЗначениеЗаполнено(СсылкаНаНовыйСчет) Тогда
// Формируем параметры для открытия формы конкретного объекта
ПараметрыФормы = Новый Структура("Ключ", СсылкаНаНовыйСчет);
// Открываем форму документа
ОткрытьФорму("Документ.СчетНаОплатуПокупателю.ФормаДокумента", ПараметрыФормы);
Иначе
ПоказатьПредупреждение(, "Не удалось создать счет на оплату!");
КонецЕсли;
КонецПроцедуры
Также существует альтернативный, более лаконичный способ открыть форму любого записанного объекта на клиенте без явного указания имени его формы. Для этого мы можем использовать метод платформы ПоказатьЗначение():
&НаКлиенте
Процедура ОткрытьДокументПросто(СсылкаНаНовыйСчет)
Если ЗначениеЗаполнено(СсылкаНаНовыйСчет) Тогда
// Платформа сама определит тип ссылки и откроет основную форму объекта
ПоказатьЗначение(, СсылкаНаНовыйСчет);
КонецЕсли;
КонецПроцедуры
Этот подход делает ваш код более гибким и защищает его от возможных переименований стандартных форм документов при обновлении платформы или прикладного решения.
Используя предложенную методику работы с регистром СрокиОплатыДокументов и соблюдая правила клиент-серверной разработки 1С, вы сможете корректно автоматизировать процесс выставления счетов и избежать ошибок, связанных с интерактивным контекстом выполнения кода.