При работе с конфигурацией "1С:Бухгалтерия предприятия 8.3" (БП 3.0) пользователи часто сталкиваются с необходимостью изменения данных в документах программно или с помощью групповых обработок. Одна из таких задач — изменение вида операции в документе "Поступление на расчетный счет". Однако, при попытке изменить вид операции, например, с "Инкассация" на "Поступление по платежным картам" программно, мы можем столкнуться с проблемой: документ записывается, но при проведении не формирует бухгалтерские проводки (движения).
Давайте разберемся, почему так происходит и как правильно решить эту задачу, чтобы документы формировали корректные движения.
Когда мы пытаемся изменить вид операции в документе, например, "Поступление на расчетный счет", программно, просто присваивая новое значение реквизиту ВидОперации, мы видим, что документ сохраняет это изменение. Но при последующем проведении документа движения остаются пустыми. Это происходит потому, что система 1С работает сложнее, чем простое изменение одного реквизита.
При интерактивном изменении вида операции пользователем в форме документа срабатывает специальный обработчик события. Этот обработчик выполняет целый комплекс действий:
Когда мы меняем реквизит ВидОперации программно, эти интерактивные обработчики событий не вызываются. В результате документ оказывается в "промежуточном" состоянии: сам реквизит ВидОперации обновлен, но вся связанная аналитика (субконто), счета учета и прочие зависимые поля остаются в состоянии, соответствующем старому виду операции, или вовсе пустыми. Это несоответствие и приводит к тому, что при проведении документ не может корректно сформировать бухгалтерские проводки.
Основной вопрос автора темы заключался в том, как обойти эту проблему. Ответ на него прост в своей формулировке, но требует внимательной реализации: программно сформировать нужные субконто. Это означает, что при программном изменении вида операции, мы должны эмулировать действия, которые выполняет система при интерактивном изменении пользователем на форме.
Рассмотрим подробнее шаги, которые нам необходимо выполнить в нашем программном коде, чтобы смена вида операции с "Инкассация" на "Поступление по платежным картам" прошла успешно и документ сформировал корректные проводки:
ВидОперации.По сути, мы переносим логику, которая привязана к изменению на форме Вида операции, из клиентского модуля формы в нашу серверную процедуру или обработку. Это позволяет нам вручную заполнить всю необходимую аналитику, которую система обычно подставляет автоматически.
Представим, что у нас есть ссылка на документ "Поступление на расчетный счет", и мы хотим изменить его вид операции. Ниже представлен пример кода на встроенном языке 1С, демонстрирующий описанный выше алгоритм. Этот код может быть интегрирован в вашу собственную обработку или регламентное задание.
Важно: Перед массовым применением подобной обработки настоятельно рекомендуем тщательно протестировать ее на копии базы данных.
// Предположим, что ДокументСсылка - это ссылка на документ "Поступление на расчетный счет", который мы хотим изменить.
// Например: ДокументСсылка = Документы.ПоступлениеНаРасчетныйСчет.НайтиПоНомер("000000001 от 01.01.2024");
// 1. Получаем объект документа для изменения
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
// Проверяем, что документ не проведен, чтобы избежать блокировок и ошибок при перезаписи
// Если ДокументОбъект.Проведен Тогда
// Сообщить("Документ " + ДокументОбъект.Номер + " от " + ДокументОбъект.Дата + " уже проведен. Отмена проведения...");
// ДокументОбъект.Проведен = Ложь;
// ДокументОбъект.Записать(); // Записываем как непроведенный
// КонецЕсли;
// 2. Устанавливаем новый вид операции
// Мы меняем вид операции на "ПоступлениеОтПродажПоПлатежнымКартам", что соответствует "Получению по платежным картам"
ДокументОбъект.ВидОперации = Перечисления.ВидыОперацийПоступлениеДенежныхСредств.ПоступлениеОтПродажПоПлатежнымКартам;
// 3. Заполняем реквизиты, специфичные для поступления по платежным картам (эквайринг)
// Эти данные (банк-эквайер, договор, счета, суммы) должны быть известны или получены из других источников.
// В данном примере мы используем заглушки или поиск по наименованию.
// Устанавливаем контрагента - банк-эквайер
ДокументОбъект.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию("Мой Банк-Эквайер", Истина);
Если ДокументОбъект.Контрагент = Неопределено Тогда
Сообщить("Контрагент 'Мой Банк-Эквайер' не найден. Создайте его или укажите существующий.");
Возврат;
КонецЕсли;
// Устанавливаем договор эквайринга
// Функция НайтиДоговорЭквайринга должна быть реализована отдельно
// и возвращать договор с видом "Прочее", "С покупателем" или "С комиссионером (агентом)" для эквайринга,
// где роль контрагента - "Иная".
Функция НайтиДоговорЭквайринга(КонтрагентБанк)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ДоговорыКонтрагентов.Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
|ГДЕ
| ДоговорыКонтрагентов.Владелец = &Владелец
| И ДоговорыКонтрагентов.ВидДоговора = &ВидДоговора"; // Можно уточнить вид договора
Запрос.УстановитьПараметр("Владелец", КонтрагентБанк);
// Для эквайринга часто используются договоры с видом "Прочее" или "С комиссионером (агентом)"
Запрос.УстановитьПараметр("ВидДоговора", Перечисления.ВидыДоговоровКонтрагентов.Прочее);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
Возврат Выборка.Ссылка;
Иначе
Возврат Неопределено;
КонецЕсли;
КонецФункции;
ДокументОбъект.Договор = НайтиДоговорЭквайринга(ДокументОбъект.Контрагент);
Если ДокументОбъект.Договор = Неопределено Тогда
Сообщить("Договор эквайринга для контрагента " + ДокументОбъект.Контрагент + " не найден.");
Возврат;
КонецЕсли;
// Устанавливаем счет расчетов с эквайером - обычно 57.03 "Продажи по платежным картам"
// В БП 3.0 это обычно Счет 57.03 "Переводы в пути"
ДокументОбъект.СчетРасчетов = ПланыСчетов.Хозрасчетный.ПереводыВПути;
// Рассчитываем и устанавливаем сумму комиссии банка.
// Например, 2% от общей суммы документа.
СуммаКомиссии = ДокументОбъект.СуммаДокумента * 0.02;
ДокументОбъект.СуммаУслуг = СуммаКомиссии;
// 4. Заполняем аналитику для учета комиссии
// Комиссия банка обычно учитывается на счете 91.02 "Прочие расходы"
ДокументОбъект.СчетЗатрат = ПланыСчетов.Хозрасчетный.ПрочиеРасходы; // Счет 91.02
// Находим статью прочих доходов и расходов для комиссии банка
СтатьяРасходов = Справочники.ПрочиеДоходыИРасходы.НайтиПоНаименованию("Расходы на услуги банков", Истина);
Если СтатьяРасходов = Неопределено Тогда
Сообщить("Статья расходов 'Расходы на услуги банков' не найдена. Создайте ее.");
Возврат;
КонецЕсли;
// Заполняем субконто для счета 91.02. В БП 3.0 обычно требуется "Прочие доходы и расходы".
// Нужно проверить виды субконто, привязанные к СчетЗатрат.
Для Каждого ВидСубконто Из ДокументОбъект.СчетЗатрат.ВидыСубконто Цикл
Если ВидСубконто.ВидСубконто = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ПрочиеДоходыИРасходы Тогда
ДокументОбъект.Субконто[ВидСубконто.Имя] = СтатьяРасходов;
Прервать;
КонецЕсли;
КонецЦикла;
// 5. Очищаем данные от предыдущей операции (если они были заполнены и неактуальны)
// Например, если для инкассации был заполнен реквизит СчетИнкассации, его следует очистить.
// ДокументОбъект.СчетИнкассации = Неопределено; // Проверить наличие такого реквизита в вашей версии БП
// Также важно очистить или установить по умолчанию другие реквизиты,
// которые могли быть связаны со старым видом операции и не нужны для нового.
// Например, для инкассации мог быть заполнен реквизит "Подразделение",
// или "СчетКасса" если он перестал быть актуальным.
// ДокументОбъект.Подразделение = Неопределено;
// ДокументОбъект.СчетКасса = Неопределено;
// Перезаполняем табличную часть "РасшифровкаПлатежа", если она зависит от вида операции
// Для поступления по платежным картам обычно есть одна строка, где контрагент - покупатель,
// а счет расчетов - 76.09 (Расчеты по прочим операциям).
// Удалим старые строки, если они были специфичны для инкассации
ДокументОбъект.РасшифровкаПлатежа.Очистить();
// Добавим новую строку для поступления от покупателя через эквайринг
НоваяСтрока = ДокументОбъект.РасшифровкаПлатежа.Добавить();
НоваяСтрока.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию("Наш Покупатель", Истина); // Контрагент, от которого пришли деньги
НоваяСтрока.ДоговорКонтрагента = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию("Основной договор с покупателем", Истина); // Договор с покупателем
НоваяСтрока.СчетУчетаРасчетовСКонтрагентом = ПланыСчетов.Хозрасчетный.РасчетыПоПрочимОперациям; // Счет 76.09
НоваяСтрока.СчетУчетаАвансов = ПланыСчетов.Хозрасчетный.РасчетыПоПрочимОперациям; // Тоже 76.09
НоваяСтрока.Сумма = ДокументОбъект.СуммаДокумента - СуммаКомиссии; // Сумма за вычетом комиссии
НоваяСтрока.ВидПлатежа = Перечисления.ВидыПлатежейРасшифровкаПлатежа.ОплатаОтПокупателя; // Оплата от покупателя
// 6. Записываем и проводим документ
Попытка
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
Сообщить("Документ " + ДокументОбъект.Ссылка + " успешно изменен и проведен.");
Исключение
Сообщить("Не удалось провести документ " + ДокументОбъект.Ссылка + ". " + ОписаниеОшибки());
КонецПопытки;
При реализации подобного решения, мы должны помнить о нескольких критически важных аспектах:
Если ДокументОбъект.Контрагент = Неопределено Тогда...). Если объект не найден, возможно, его придется создать или вывести сообщение об ошибке.РежимЗаписиДокумента.Проведение для записи и автоматического проведения документа. Если документ ранее был проведен, возможно, потребуется сначала снять его с проведения, а затем записать и провести заново.Таким образом, для успешного программного изменения вида операции и формирования корректных движений, недостаточно просто изменить один реквизит. Нам необходимо программно заполнить всю аналитику, счета учета и табличные части, которые зависят от нового вида операции, эмулируя тем самым действия, которые система выполняет при ручном изменении в форме документа.