В процессе работы с программными продуктами семейства 1С:Предприятие (в частности, с конфигурацией 1С:Бухгалтерия КОРП/ПРОФ 3.0) пользователи и администраторы нередко сталкиваются с досадной системной ошибкой при массовом формировании платежных документов на выплату заработной платы. Программа прерывает операцию и выводит на экран лаконичное, но малоинформативное сообщение: «Не удалось записать платежное поручение».
Особую сложность добавляет то, что в файловом режиме базы данных процедура может проходить абсолютно штатно, в то время как в клиент-серверном варианте (при работе под управлением СУБД MS SQL или PostgreSQL) система стабильно выдает ошибку. В этой статье мы подробно разберем, почему возникает данная проблема, проанализируем неочевидные серверные механизмы и рассмотрим пошаговые инструкции по ее устранению.
Для того чтобы эффективно решить проблему, выясним причину ее возникновения. В современных конфигурациях 1С формирование документов по выплате зарплаты часто вынесено в фоновые задачи для обеспечения отзывчивости интерфейса. Этот механизм реализован через стандартный программный интерфейс ДлительныеОперации. Когда фоновое задание на сервере пытается записать сформированный документ ПлатежноеПоручение, СУБД отвергает транзакцию, а платформа перехватывает исключение и возвращает общую ошибку.
Проанализируем основные технические факторы, которые приводят к сбою транзакции записи на сервере:
ASCII 9). Файловая СУБД 1С лояльно относится к таким символам, однако серверные СУБД при строгой проверке типов данных могут заблокировать запись транзакции, возвращая ошибку ОшибкаХранимыхДанных.usr1cv8). Если алгоритмы проведения или записи обращаются к внешним компонентам криптографии (для подписи), каталогам временных файлов или внешним веб-сервисам проверки контрагентов, отсутствие прав у серверного пользователя ОС вызовет аварийное завершение процесса.Рассмотрим подробнее практические методы локализации и исправления каждого из этих сценариев.
Если в системе нарушилась последовательность номеров документов, автонумератор платформы начинает давать сбои. Чтобы быстро восстановить корректный порядок распределения номеров без ручного перебора документов, воспользуемся встроенным методом платформы ОбновитьНумерациюОбъектов().
Разберем по шагам, как выполнить это действие:
ВыборкаМетаданных = Метаданные.Документы.ПлатежноеПоручение;
ОбновитьНумерациюОбъектов(ВыборкаМетаданных);
Сообщить("Автонумерация платежных поручений успешно обновлена на сервере!");
Этот метод сбрасывает закэшированные сервером СУБД будущие номера и заставляет систему заново проанализировать существующие в базе документы для определения следующего свободного индекса. Если после этого ошибка повторяется, необходимо вручную найти документ с наибольшим номером в текущем периоде (году). Скорее всего, кто-то из пользователей случайно отредактировал номер вручную (например, заменил префикс или добавил лишний символ в конец), из-за чего автонумерация "уткнулась" в этот некорректный предел. Найдите его, верните стандартный формат номера и повторно запустите обновление нумерации.
Если обновление нумерации не принесло желаемого результата, нам потребуется выяснить точный текст системного исключения, которое прячется за общей формулировкой. Поскольку ошибка генерируется внутри фонового процесса, обычная интерактивная отладка не покажет нам проблемный участок кода.
Проанализируем ситуацию и выполним настройку отладки фоновых заданий на сервере:
-debug (или -tcp в зависимости от архитектуры вашей сети).ДлительныеОперации и перейдите к строке 389 (или найдите вызов исключения в вашей версии платформы):
// Примерный код в общем модуле ДлительныеОперации
Если Задание ВыполненоСОшибкой Тогда
ВызватьИсключение(ТекстОшибки); // Установите точку останова на этой строке!
КонецЕсли;
Установите точку останова на вызове исключения. Запустите процесс формирования платежных поручений из пользовательского интерфейса. При возникновении ошибки выполнение кода прервется в конфигураторе. Наведите курсор на переменную ТекстОшибки или добавьте ее в табло вычислений. Там будет содержаться детальное техническое описание сбоя (например, «Поле "Договор контрагента" не заполнено» или «Нарушение уникальности ключа в таблице СУБД»). Получив эту информацию, вы легко поймете, какой именно реквизит документа мешает его успешной записи.
Часто в процессе интеграции зарплатных программ (например, 1С:ЗУП) с бухгалтерскими базами при переносе ведомостей на выплату в текстовых реквизитах «Назначение платежа» или «Получатель» могут содержаться спецсимволы табуляции или некорректные переносы строк, которые отторгаются сервером СУБД SQL.
Посмотрим на пример функции, которую можно внедрить в код формирования платежных документов для превентивной очистки строковых данных перед вызовом метода Записать():
Функция ОчиститьТекстДляЗаписиНаСервере(ВходящийТекст) Экспорт
РезультатСтрока = ВходящийТекст;
// Заменяем символы табуляции на обычные пробелы
РезультатСтрока = СтрЗаменить(РезультатСтрока, Символы.Таб, " ");
// Избавляемся от жестких возвратов каретки, заменяя их на стандартный перевод строки
РезультатСтрока = СтрЗаменить(РезультатСтрока, Символы.ВК, "");
Возврат СократитьЛП(РезультатСтрока);
КонецФункции
Применяйте подобную фильтрацию ко всем текстовым полям, которые заполняются автоматически на основе данных из внешних источников данных или файлов обмена. Это гарантирует беспрепятственную запись документов в любой СУБД.
Если база данных работает в нагруженном клиент-серверном режиме и ошибка записи возникает спорадически (то есть платежки то проводятся, то нет), велика вероятность взаимных блокировок в СУБД. В этот момент таблицы базы данных могут блокироваться регламентными процессами.
Рекомендуется выполнить следующие действия:
EXCP для детального анализа транзакционных ошибок блокировок на уровне СУБД.Регулярное проведение регламентных процедур обслуживания базы данных (дефрагментация индексов и обновление статистики СУБД) также существенно снижает вероятность возникновения ошибок записи из-за таймаутов транзакций.