Ошибка проведения документа 1С: «Не удалось провести»

Дата: 06.10.2026 16:54:16
Ошибки 1С
Проведение документов
Отладка
Подписки на события
Расширение конфигурации
БСП
Комментарий:
0
Платформа:
8.3
Конфигурация:
Любая
Формы:
Любые

Ошибка проведения документа 1С выглядит одинаково при любой причине: окно «Не удалось провести…», иногда — «Операция не выполнена» без пояснений. А причин с десяток: не хватает остатков, документ попал в закрытый период, у пользователя нет прав, не заполнен реквизит, упала доработка или подписка на событие. Ниже — как по тексту понять класс ошибки, где прочитать её полностью и как кодом найти модуль, на котором проведение сорвалось.

Встречается это везде, где документ записывается в режиме проведения: кнопка «Провести», групповое перепроведение, загрузка из обмена, регламентные задания. Любой обработчик — модуль объекта, подписка, расширение — может выставить Отказ = Истина или вызвать исключение, и платформа откатит транзакцию целиком: в регистрах не останется ни одной записи.

Ошибка проведения документа 1С: что означает текст

Окно «Не удалось провести» говорит лишь, что 1С не удалось провести документ. Причину пишет обработчик, который отказал, — в окно сообщений под формой документа. Если сообщений нет, а появилось окно ошибки, смотрите исключение: кнопка «Подробно» показывает его полный текст.

Текст сообщенияЧто случилосьЧто делать
«Недостаточно товара в наличии на складе …», «Превышен доступный остаток товара на складе …» (УТ 11.4)Контроль остатков после записи движений: товара на момент документа меньше, чем в документе, или он в резервеОстатки на дату и время документа, резервы, проведено ли поступление; флажок склада «Контролировать обеспечение» (в 11.5 — «Контролировать свободные остатки»)
«Превышен оперативный складской остаток на складе …» (УТ 11.4)Не хватает товара по оперативному складскому учётуРасходные ордера, серии; флажок склада «Контролировать оперативные остатки»
«Запрещено изменять данные с датой ранее … (включительно)»Дата запрета изменения БСП: период закрытДату — общую или для пользователя — настраивает администратор, путь ниже
«Недостаточно прав для проведения», «Нарушение прав доступа!», «У пользователя недостаточно прав на исполнение операции над базой данных»Нет права на документ или регистр либо сработало ограничение на уровне записейПрофиль пользователя; разбор — в статье про нарушение прав доступа
«Поле "…" не заполнено», «Не заполнена колонка "…" в строке N списка "…"»Проверка заполнения перед проведениемЗаполнить поле; если оно обязательно не всегда — править ОбработкаПроверкиЗаполнения
«Помеченный на удаление документ не может быть проведен!»На документе пометка удаленияСнять пометку
«Дата оперативно проводимого документа больше текущей…» или «…меньше текущей»Документ проводится оперативно, а его дата не текущаяПровести неоперативно (платформа предложит) или поправить дату
«Операция не может быть выполнена из-за несоответствия версии или отсутствия записи базы данных…»Документ изменили в другом сеансе или кодом, пока была открыта формаЗакрыть форму без сохранения, открыть и провести заново
«Конфликт блокировок при выполнении транзакции:», «Превышено максимальное время ожидания предоставления блокировки»Те же данные одновременно пишет другой сеансПовторить; если часто — разбирать блокировки
«{ОбщийМодуль.Имя.Модуль(245)}: …», «Поле объекта не обнаружено (…)», «Значение не является значением объектного типа (…)», «Деление на 0»Ошибка в коде: доработка, подписка, расширениеМодуль и строка — в подробном тексте, разбор ниже
«В данной транзакции уже происходили ошибки!»Раньше в той же транзакции перехватили исключение и продолжили работуИскать первую ошибку цепочки, а не эту
«Операция не выполнена!» без сообщенийОбработчик выставил Отказ = Истина и ничего не сообщилНайти обработчик по списку участников проведения (листинг 3)

Где прочитать полный текст ошибки

  1. Окно сообщений формы. Сюда пишут типовые проверки: остатки, даты запрета, заполнение. Сообщение, привязанное к полю, показывает, что исправить.
  2. Кнопка «Подробно» в окне ошибки. Подробный текст состоит из строк вида {Документ.Имя.МодульОбъекта(120)}: исходная строка кода, а после «по причине:» идёт вложенная ошибка. Читайте снизу: последняя причина — место, где исключение возникло, верхние строки — путь к нему.
  3. Отладчик. В конфигураторе «Отладка → Остановка по ошибке…», флажок «Останавливаться по ошибке»: выполнение встанет на строке исключения со всеми переменными. Как подключиться к серверу и к сеансу пользователя — в статье про отладку 1С.

Если ошибка плавает или окно уже закрыли, воспроизведите проведение кодом. Функция ниже проводит документ так же, как форма, но в транзакции с откатом: база не меняется, а на выходе — сообщения обработчиков, подробный текст и цепочка модулей. Код рассчитан на модуль объекта внешней обработки (как её создать), подойдёт и серверный общий модуль.

// Модуль объекта внешней обработки «ДиагностикаПроведения» (подойдёт и общий
// модуль с флагом «Сервер»). Проводит документ так же, как форма: сначала
// проверка заполнения, потом запись в режиме проведения. Возвращает то, чего
// не видно в окне «Не удалось провести»: сообщения обработчиков, подробный
// текст исключения и цепочку модулей со строками.
// ТолькоПроверить = Истина: проведение в транзакции с откатом, база не меняется.
// Внешние действия обработчиков (HTTP-запросы, письма, файлы) откат не отменяет.
Функция ПровестиСДиагностикой(ДокументСсылка, ТолькоПроверить = Истина) Экспорт

	Если ТранзакцияАктивна() Тогда
		ВызватьИсключение "Диагностику проведения запускают вне транзакции.";
	КонецЕсли;

	ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
	Если ДокументОбъект = Неопределено Тогда
		ВызватьИсключение "Документ не найден в базе: " + Строка(ДокументСсылка);
	КонецЕсли;

	Результат = Новый Структура;
	Результат.Вставить("Успешно", Ложь);
	Результат.Вставить("Этап", "Проверка заполнения");
	Результат.Вставить("Сообщения", Новый Массив);
	Результат.Вставить("ТекстОшибки", "");
	Результат.Вставить("Цепочка", Новый Массив);

	// Сбросить сообщения, накопленные сеансом раньше: соберём только свои
	ПолучитьСообщенияПользователю(Истина);

	НачатьТранзакцию();
	Попытка
		// Форма проверяет заполнение перед проведением, программная запись - нет.
		// Проверка внутри Попытка: ошибка в ОбработкаПроверкиЗаполнения тоже попадёт в отчёт.
		Если ДокументОбъект.ПроверитьЗаполнение() Тогда
			Результат.Этап = "Проведение";
			ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
			Результат.Успешно = Истина;
		КонецЕсли;
		Если ТолькоПроверить Или Не Результат.Успешно Тогда
			ОтменитьТранзакцию();
		Иначе
			ЗафиксироватьТранзакцию();
		КонецЕсли;
	Исключение
		ОтменитьТранзакцию();
		Результат.Успешно = Ложь;
		Инфо = ИнформацияОбОшибке();
		// ОбработкаОшибок - с 8.3.17; на старых платформах ПодробноеПредставлениеОшибки(Инфо)
		Результат.ТекстОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(Инфо);
		Результат.Цепочка = ЦепочкаОшибки(Инфо);
	КонецПопытки;

	// Причины отказа обработчики пишут сообщениями: остатки, даты запрета, поля
	Для Каждого Сообщение Из ПолучитьСообщенияПользователю(Истина) Цикл
		Текст = СокрЛП(Сообщение.Текст);
		Если ЗначениеЗаполнено(Сообщение.Поле) Тогда
			Текст = Текст + " [поле: " + Сообщение.Поле + "]";
		КонецЕсли;
		Результат.Сообщения.Добавить(Текст);
	КонецЦикла;

	Если Не Результат.Успешно Тогда
		ЗаписьЖурналаРегистрации("Диагностика проведения", УровеньЖурналаРегистрации.Ошибка,
			ДокументСсылка.Метаданные(), ДокументСсылка,
			СтрСоединить(Результат.Сообщения, Символы.ПС) + Символы.ПС + Результат.ТекстОшибки);
	КонецЕсли;

	Возврат Результат;

КонецФункции

// Разворачивает цепочку «по причине:» от внешнего вызова (Записать) до места,
// где исключение возникло. Последний уровень с модулем - обычно виновник.
Функция ЦепочкаОшибки(Знач Инфо) Экспорт

	Цепочка = Новый Массив;
	Пока Инфо <> Неопределено Цикл
		Уровень = Новый Структура("Модуль, НомерСтроки, ИсходнаяСтрока, Описание",
			Инфо.ИмяМодуля, Инфо.НомерСтроки, СокрЛП(Инфо.ИсходнаяСтрока), Инфо.Описание);
		Цепочка.Добавить(Уровень);
		Инфо = Инфо.Причина;
	КонецЦикла;
	Возврат Цепочка;

КонецФункции

Разбор ключевых строк

  • ПроверитьЗаполнение(). Форма перед проведением сама вызывает проверку заполнения, программная запись — нет. Без этого шага диагностика не увидит «Поле … не заполнено».
  • НачатьТранзакцию() и ОтменитьТранзакцию(). При ТолькоПроверить = Истина проведение проходит целиком — движения, контроль остатков, подписки — и откатывается. Внешние действия обработчиков (отправку заказа на сайт, письмо) откат не вернёт.
  • ПолучитьСообщенияПользователю(Истина). На сервере забирает сообщения обработчиков, в том числе отправленные через ОбщегоНазначения.СообщитьПользователю. Первый вызов чистит старые сообщения сеанса, второй собирает свои.
  • ОбработкаОшибок.ПодробноеПредставлениеОшибки. Тот же текст, что по кнопке «Подробно»; глобальная функция с таким именем с 8.3.17 не рекомендуется.
  • ЦепочкаОшибки. Проходит по Причина до конца: первый уровень — вызов Записать, последний с модулем — строка, где ошибка возникла.
  • ЗаписьЖурналаРегистрации. Неудачная попытка остаётся в журнале регистрации событием «Диагностика проведения» с документом в колонке «Данные».

Права, пометка удаления, дата запрета: проверка без проведения

Часть причин видна без попытки провести. Функция проверяет их для текущего пользователя или для сотрудника, у которого документ не проводится: под администратором ошибки прав не воспроизводятся.

// Модуль объекта обработки (продолжение). Причины, которые видны без проведения.
// Пользователь - ПользовательИнформационнойБазы, у которого документ
// не проводится; Неопределено - текущий. Чужие права проверяет администратор.
Функция ПричиныДоПроведения(ДокументСсылка, Пользователь = Неопределено) Экспорт

	Причины = Новый Массив;
	МетаданныеДокумента = ДокументСсылка.Метаданные();

	Если МетаданныеДокумента.Проведение <> Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда
		Причины.Добавить("Проведение документов этого вида запрещено в конфигурации.");
		Возврат Причины;
	КонецЕсли;

	ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
	Если ДокументОбъект = Неопределено Тогда
		Причины.Добавить("Документа нет в базе: ссылка битая.");
		Возврат Причины;
	КонецЕсли;

	Если ДокументОбъект.ПометкаУдаления Тогда
		Причины.Добавить("Документ помечен на удаление: платформа его не проведёт.");
	КонецЕсли;

	// Права на документ. Без «ИнтерактивноеИзменениеПроведенных» проведённый
	// документ открывается только для просмотра - перепровести его из формы нельзя.
	ИменаПрав = СтрРазделить("Проведение,ИнтерактивноеПроведение", ",");
	Если ДокументОбъект.Проведен Тогда
		ИменаПрав.Добавить("ИнтерактивноеИзменениеПроведенных");
	КонецЕсли;
	Для Каждого ИмяПрава Из ИменаПрав Цикл
		Если Не ЕстьПраво(ИмяПрава, МетаданныеДокумента, Пользователь) Тогда
			Причины.Добавить(СтрШаблон("Нет права «%1» на документ «%2».",
				ИмяПрава, МетаданныеДокумента.Представление()));
		КонецЕсли;
	КонецЦикла;

	// Права на регистры движений. Если код пишет регистр в привилегированном
	// режиме, право не нужно: строка - повод проверить, а не приговор.
	Для Каждого Регистр Из МетаданныеДокумента.Движения Цикл
		Если Не ЕстьПраво("Изменение", Регистр, Пользователь) Тогда
			Причины.Добавить(СтрШаблон("Нет права «Изменение» на %1: возможна ошибка «Нарушение прав доступа!».",
				Регистр.ПолноеИмя()));
		КонецЕсли;
	КонецЦикла;

	// Дата запрета изменения БСП (сверено по УТ 11.4 и КА 2.5). Проверяется
	// по данным самого документа и для текущего сеанса; движения регистров
	// проверит подписка при проведении.
	Если Метаданные.ОбщиеМодули.Найти("ДатыЗапретаИзменения") <> Неопределено Тогда
		// Так же делает подписка БСП перед записью документа
		ДокументОбъект.ДополнительныеСвойства.Вставить("РежимЗаписи", РежимЗаписиДокумента.Проведение);
		ОписаниеЗапрета = "";
		МодульДатЗапрета = ОбщегоНазначения.ОбщийМодуль("ДатыЗапретаИзменения");
		Если МодульДатЗапрета.ИзменениеЗапрещено(ДокументОбъект, , ОписаниеЗапрета) Тогда
			Причины.Добавить(ОписаниеЗапрета);
		КонецЕсли;
	КонецЕсли;

	Возврат Причины;

КонецФункции

// ПравоДоступа для текущего пользователя или для указанного.
Функция ЕстьПраво(ИмяПрава, ОбъектМетаданных, Пользователь)

	Если Пользователь = Неопределено Тогда
		Возврат ПравоДоступа(ИмяПрава, ОбъектМетаданных);
	КонецЕсли;
	Возврат ПравоДоступа(ИмяПрава, ОбъектМетаданных, Пользователь);

КонецФункции

Дата запрета в БСП бывает общей, по разделу или объекту, а также для отдельного пользователя или группы — поэтому у бухгалтера документ проводится, а у менеджера нет. Настраивает даты администратор: в УТ 11.4 — «НСИ и администрирование → Настройки пользователей и прав», группа «Даты запрета изменения», ссылка «Настроить». Отключать проверку кодом (ДатыЗапретаИзменения.ОтключитьПроверкуДатЗапрета) ради одного документа не стоит: отключение действует на весь сеанс и требует полных прав или привилегированного режима.

Как найти модуль-виновник

Имя модуля в подробном тексте говорит, где код: Документ.Имя.МодульОбъекта — модуль документа, ОбщийМодуль.Имя.Модуль — общий модуль, часто обработчик подписки. Но модуль документа — не единственный участник: при записи вызываются подписки на сам документ и на наборы записей каждого регистра из его движений, а расширения перехватывают типовые методы аннотациями &Перед, &После, &Вместо, &ИзменениеИКонтроль. Функции ниже определяют владельца модуля и перечисляют участников проведения.

// Модуль объекта обработки (продолжение). Чей модуль из цепочки ошибки:
// «ОбщийМодуль.Имя.Модуль», «Документ.Имя.МодульОбъекта» и т. п.
Функция ЧейМодуль(ИмяМодуля) Экспорт

	Части = СтрРазделить(ИмяМодуля, ".");
	Если Части.Количество() < 3 Тогда
		Возврат "не модуль конфигурации";
	КонецЕсли;

	ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(Части[0] + "." + Части[1]);
	Если ОбъектМетаданных = Неопределено Тогда
		Возврат "нет в метаданных: внешняя обработка или отчёт";
	КонецЕсли;

	Расширение = ОбъектМетаданных.РасширениеКонфигурации();
	Если Расширение <> Неопределено Тогда
		Возврат "объект расширения «" + Расширение.Имя + "»";
	ИначеЕсли ОбъектМетаданных.ЕстьИзмененияРасширениямиКонфигурации() Тогда
		Возврат "конфигурация, объект изменён расширением: смотрите модуль и в расширении";
	КонецЕсли;
	Возврат "основная конфигурация";

КонецФункции

// Всё, что работает при проведении помимо модуля объекта документа:
// подписки на документ и на наборы записей его регистров, расширения сеанса.
Функция УчастникиПроведения(МетаданныеДокумента) Экспорт

	Строки = Новый Массив;
	Если МетаданныеДокумента.ЕстьИзмененияРасширениямиКонфигурации() Тогда
		Строки.Добавить("Документ изменён расширением: его модули есть и в расширении.");
	КонецЕсли;

	// Источники подписок: объект документа и наборы записей регистров движений
	Источники = Новый Соответствие;
	Источники.Вставить(Тип("ДокументОбъект." + МетаданныеДокумента.Имя), "документ");
	Для Каждого Регистр Из МетаданныеДокумента.Движения Цикл
		// «РегистрНакопления.Имя» -> тип «РегистрНакопленияНаборЗаписей.Имя»
		ИмяТипаНабора = СтрЗаменить(Регистр.ПолноеИмя(), ".", "НаборЗаписей.");
		Источники.Вставить(Тип(ИмяТипаНабора), Регистр.ПолноеИмя());
		Если Регистр.ЕстьИзмененияРасширениямиКонфигурации() Тогда
			Строки.Добавить(Регистр.ПолноеИмя() + " изменён расширением.");
		КонецЕсли;
	КонецЦикла;

	Для Каждого Подписка Из Метаданные.ПодпискиНаСобытия Цикл
		Для Каждого Элемент Из Источники Цикл
			Если Подписка.Источник.СодержитТип(Элемент.Ключ) Тогда
				Расширение = Подписка.РасширениеКонфигурации();
				Строки.Добавить(СтрШаблон("Подписка %1 (%2): %3%4", Подписка.Имя, Подписка.Синоним,
					Элемент.Значение, ?(Расширение = Неопределено, "", ", расширение " + Расширение.Имя)));
				Прервать; // подписку и на документ, и на регистры показываем один раз
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;

	// Расширения, подключённые в этом сеансе. Без административных прав
	// список может быть недоступен - тогда в отчёте будет строка с причиной.
	Попытка
		Расширения = РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансАктивные);
	Исключение
		Расширения = Новый Массив;
		Строки.Добавить("Список расширений недоступен: "
			+ ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;
	Для Каждого Расширение Из Расширения Цикл
		Строки.Добавить(СтрШаблон("Расширение %1 «%2», версия %3",
			Расширение.Имя, Расширение.Синоним, Расширение.Версия));
	КонецЦикла;

	Возврат Строки;

КонецФункции

У отказа без исключения цепочки нет, и список участников становится планом поиска: точки останова — на строки Отказ = Истина в найденных модулях. В УТ 11.4 дату запрета проверяют подписки БСП ПроверитьДатуЗапретаИзмененияПередЗаписьюДокумента и ПроверитьДатуЗапретаИзмененияПередЗаписьюНабораЗаписей, а остатки — ПроведениеСерверУТ.ВыполнитьКонтрольРезультатовПроведения в конце ОбработкаПроведения документа. Как устроены подписки — в статье про подписки на события.

Обработка «Диагностика проведения» целиком

Форма собирает три функции в один отчёт. Создайте реквизиты в редакторе формы, поле «Результат» сделайте многострочным, функции листингов 1–3 положите в модуль объекта обработки. Запускайте под администратором: права другого пользователя без административных прав не проверить, а список расширений может быть недоступен.

// Модуль управляемой формы внешней обработки «ДиагностикаПроведения».
// Реквизиты формы: Документ (ДокументСсылка - любой документ), ТолькоПроверить
// (Булево), ИмяПользователя (Строка), Результат (Строка, многострочное поле).
// Команда формы Проверить. Функции листингов 1-3 - в модуле объекта обработки.

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	ТолькоПроверить = Истина;

КонецПроцедуры

&НаКлиенте
Процедура Проверить(Команда)

	Если Не ЗначениеЗаполнено(Документ) Тогда
		ПоказатьПредупреждение(, "Выберите документ.");
		Возврат;
	КонецЕсли;
	Результат = ПроверитьНаСервере();

КонецПроцедуры

&НаСервере
Функция ПроверитьНаСервере()

	Обработка = РеквизитФормыВЗначение("Объект");
	Строки = Новый Массив;

	// Сотрудник, у которого документ не проводится (нужны права администратора)
	Пользователь = Неопределено;
	Если ЗначениеЗаполнено(ИмяПользователя) Тогда
		Пользователь = ПользователиИнформационнойБазы.НайтиПоИмени(ИмяПользователя);
		Если Пользователь = Неопределено Тогда
			Возврат "Пользователь не найден: " + ИмяПользователя;
		КонецЕсли;
	КонецЕсли;

	Строки.Добавить("1. Без проведения");
	Для Каждого Причина Из Обработка.ПричиныДоПроведения(Документ, Пользователь) Цикл
		Строки.Добавить("   " + Причина);
	КонецЦикла;

	// Проведение выполняется от текущего пользователя
	Итог = Обработка.ПровестиСДиагностикой(Документ, ТолькоПроверить);
	Если Итог.Успешно Тогда
		ТекстИтога = ?(ТолькоПроверить, "прошло, изменения отменены", "документ проведён");
	Иначе
		ТекстИтога = "ошибка";
	КонецЕсли;
	Строки.Добавить(СтрШаблон("2. %1: %2", Итог.Этап, ТекстИтога));
	Для Каждого Текст Из Итог.Сообщения Цикл
		Строки.Добавить("   Сообщение: " + Текст);
	КонецЦикла;
	Для Каждого Уровень Из Итог.Цепочка Цикл
		Если ЗначениеЗаполнено(Уровень.Модуль) Тогда
			Строки.Добавить(СтрШаблон("   %1, строка %2 (%3): %4", Уровень.Модуль,
				XMLСтрока(Уровень.НомерСтроки), Обработка.ЧейМодуль(Уровень.Модуль), Уровень.ИсходнаяСтрока));
		КонецЕсли;
		Строки.Добавить("      " + Уровень.Описание);
	КонецЦикла;

	Строки.Добавить("3. Кто ещё участвует в проведении");
	Для Каждого Участник Из Обработка.УчастникиПроведения(Документ.Метаданные()) Цикл
		Строки.Добавить("   " + Участник);
	КонецЦикла;

	Возврат СтрСоединить(Строки, Символы.ПС);

КонецФункции

Проведение выполняется от текущего пользователя, поэтому права сотрудника проверяет только первый блок. Персональную дату запрета и ограничения на уровне записей покажет запуск под учётной записью сотрудника с пустым полем «Имя пользователя», если ему разрешено открывать внешние обработки; с ТолькоПроверить база не изменится.

Как отказать в проведении в своей доработке

Многие «непонятные» ошибки проведения приходят из доработок: проверка ставит Отказ и молчит, обращается к реквизиту, которого нет у части документов из источника подписки, или перехватывает исключение и работает дальше. Шаблон обработчика подписки ПередЗаписью, который отказывает правильно:

// Общий модуль КонтрольОтгрузкиСобытия, флаг «Сервер» (имена условные).
// Обработчик подписки ПередЗаписью, источник - несколько видов документов
// отгрузки. Как доработка должна отказывать в проведении: до записи движений,
// с понятным текстом у нужного поля, через Отказ, без «глухих» Попытка.
Процедура ПроверитьОтгрузкуПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт

	// Загрузка при обмене: данные приходят как есть, проверки не выполняют
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

	// Черновик записываем без проверок, контролируем только проведение
	Если РежимЗаписи <> РежимЗаписиДокумента.Проведение Тогда
		Возврат;
	КонецЕсли;

	// Реквизит есть не у всех документов источника: без этой проверки
	// проведение «чужого» документа упадёт с «Поле объекта не обнаружено (Склад)»
	МетаданныеДокумента = Источник.Метаданные();
	Если МетаданныеДокумента.Реквизиты.Найти("Склад") <> Неопределено
		И Не ЗначениеЗаполнено(Источник.Склад) Тогда
		СообщитьОбОтказе("Не указан склад отгрузки.", Источник, "Склад", Отказ);
	КонецЕсли;

	ТабличнаяЧасть = МетаданныеДокумента.ТабличныеЧасти.Найти("Товары");
	Если ТабличнаяЧасть = Неопределено
		Или ТабличнаяЧасть.Реквизиты.Найти("Количество") = Неопределено Тогда
		Возврат;
	КонецЕсли;

	Для Каждого СтрокаТоваров Из Источник.Товары Цикл
		Если СтрокаТоваров.Количество <= 0 Тогда
			// Индекс строки в пути к полю считается с нуля; XMLСтрока - без пробелов
			// между разрядами, которые СтрШаблон вставил бы в число больше 999
			ПутьКПолю = "Товары[" + XMLСтрока(СтрокаТоваров.НомерСтроки - 1) + "].Количество";
			СообщитьОбОтказе(СтрШаблон("Строка %1: количество должно быть больше нуля.",
				СтрокаТоваров.НомерСтроки), Источник, ПутьКПолю, Отказ);
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

// Сообщение привязано к полю: в форме документа оно встанет у нужного реквизита.
Процедура СообщитьОбОтказе(Текст, Источник, Поле, Отказ)

	Сообщение = Новый СообщениеПользователю;
	Сообщение.Текст = Текст;
	Сообщение.Поле = Поле;
	Сообщение.УстановитьДанные(Источник);
	Сообщение.Сообщить();
	Отказ = Истина;

КонецПроцедуры

Почему Отказ, а не ВызватьИсключение: проведение прервётся в обоих случаях, но с Отказ сотрудник увидит понятный текст у нужного поля, а не технический стек. Проверки, которым нужны остатки после записи движений, ставят в конец ОбработкаПроведения, как в типовой. Перехватывать исключения внутри проведения и продолжать нельзя — почему, разобрано в статье про транзакции.

Типичные ошибки

  • Проверка под администратором. С полными правами не воспроизводятся ни нехватка ролей, ни персональные даты запрета — проверяйте под учётной записью сотрудника.
  • Чтение только первой строки. «Ошибка при вызове метода контекста (Записать)» — это место вызова. Причина — в последнем «по причине:».
  • Снятый контроль остатков. Документ проведётся, но склад уйдёт в минус, и разбирать это придётся при закрытии месяца.
  • Перехваченное исключение в подписке. Попытка без ВызватьИсключение в ветке Исключение превращает понятную ошибку в «В данной транзакции уже происходили ошибки!» в другом модуле.
  • Отказ = Истина без сообщения. Пользователь видит «Не удалось провести» и ничего больше, а обработчик приходится искать по всем подпискам.

Частые вопросы

Почему «Недостаточно товара», если товар на складе есть?

Остаток считается на момент документа, а не на сегодня: поступление того же дня с более поздним временем ещё не учтено. Ещё причины — резерв под другие заказы, другая характеристика, серия или склад, непроведённое поступление.

Почему у меня документ проводится, а у сотрудника — «Не удалось провести»?

Разные права и разные даты запрета: в БСП дату можно задать отдельному пользователю или группе. Запустите листинг 2 с именем сотрудника, а проведение — под его учётной записью.

Что значит «Операция не выполнена» без пояснений?

Обработчик выставил Отказ = Истина и не написал причину либо сообщение ушло туда, где его не видно, — например, в фоновое задание: там его забирают методом ПолучитьСообщенияПользователю фонового задания. Найдите обработчик по списку участников из листинга 3.

Перепроведение документов идёт с ошибками: с чего начать?

С самой ранней. Документы перепроводят по возрастанию даты, и одно непроведённое поступление даёт «Недостаточно товара» во всех следующих отгрузках. Исправьте первую ошибку и перезапустите. Как собрать ошибки перепроведения в журнал, описано в статье про перепроведение документов.

Почему обработка провела документ с пустым полем, а из формы он не проводится?

Проверку заполнения вызывает форма, а Записать(РежимЗаписиДокумента.Проведение) из кода её не делает. В своих обработках вызывайте ПроверитьЗаполнение() перед записью, как в листинге 1.

Когда проще заказать

Остатки, даты запрета и права обычно исправляются настройкой по шагам выше. Если падает доработка или расширение, а автора кода уже нет, отдайте разбор программисту: приложите подробный текст ошибки и отчёт обработки диагностики. Разместите задачу или выберите профильную услугу по доработке 1С: оценка бесплатная, ответ в течение рабочего дня.

По теме

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.


1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.