При работе с типовой конфигурацией 1С:Бухгалтерия 3.0 часто возникает необходимость адаптировать стандартные механизмы под специфические требования учета. В данной статье мы рассмотрим распространенную задачу: изменение логики списания материалов из эксплуатации, когда для определенного вида номенклатуры требуется использовать не стандартный забалансовый счет (например, МЦ.04), а собственный, дополнительно введенный счет (например, МЦ.06).
Предположим, мы ведем учет номенклатуры с видом "Учебная литература" на специально добавленном забалансовом счете МЦ.06. Стандартный документ "Списание материалов из эксплуатации" по умолчанию пытается списать все материалы, относящиеся к инвентарю, со счета МЦ.04. Наша задача — модифицировать этот процесс таким образом, чтобы "Учебная литература" списывалась именно с МЦ.06.
Мы проанализируем, как можно решить эту проблему, работая как непосредственно с кодом конфигурации, так и используя механизм расширений, что является предпочтительным подходом для сохранения возможности обновления типовой конфигурации.
Для того чтобы изменить логику определения счета, нам необходимо найти, где формируется список списываемых материалов и какой счет им присваивается. В документе "Списание материалов из эксплуатации" обработка проведения начинается с вызова общего модуля УчетМатериаловВЭксплуатации и его функции СформироватьДвиженияСписаниеИнвентаряИзЭксплуатации(..). Эта функция, в свою очередь, обращается к функции ПодготовитьТаблицуСписанныйИзЭксплуатацииИнвентарь(..), которая выполняет запрос к регистру бухгалтерии для проверки остатков.
Однако, прежде чем попадаем в эти функции, данные о списываемых материалах формируются в документе. Мы обнаружили, что ключевой запрос, который определяет, с какого счета будет списываться номенклатура, находится в модуле менеджера документа "Списание материалов из эксплуатации", в функции ТекстЗапросаСписаниеИнвентаря.
Посмотрим на исходный фрагмент кода этой функции:
Функция ТекстЗапросаСписаниеИнвентаря(НомераТаблиц)
НомераТаблиц.Вставить("СписаниеИнвентаряРеквизиты", НомераТаблиц.Количество());
НомераТаблиц.Вставить("СписаниеИнвентаряТаблица", НомераТаблиц.Количество());
ТекстЗапроса =
"ВЫБРАТЬ
| Реквизиты.Ссылка КАК Регистратор,
| Реквизиты.Дата КАК Период,
| Реквизиты.Организация,
| Реквизиты.ПодразделениеОрганизации КАК Подразделение
|ИЗ
| Документ.СписаниеМатериаловИзЭксплуатации КАК Реквизиты
|ГДЕ
| Реквизиты.Ссылка = &Ссылка
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ""ИнвентарьИХозяйственныеПринадлежности"" КАК ИмяСписка,
| &СинонимИнвентарь КАК СинонимСписка,
| МИНИМУМ(ТаблицаИнвентарь.НомерСтроки) КАК НомерСтроки,
| ТаблицаИнвентарь.Номенклатура,
| ТаблицаИнвентарь.ПартияМатериаловВЭксплуатации,
| ТаблицаИнвентарь.ФизЛицо,
| ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ИнвентарьИХозяйственныеПринадлежностиВЭксплуатации) КАК СчетМЦ,
| СУММА(ТаблицаИнвентарь.Количество) КАК КоличествоМЦ
|ИЗ
| Документ.СписаниеМатериаловИзЭксплуатации.ИнвентарьИХозяйственныеПринадлежности КАК ТаблицаИнвентарь
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.СписаниеМатериаловИзЭксплуатации КАК Реквизиты
| ПО ТаблицаИнвентарь.Ссылка = Реквизиты.Ссылка
|ГДЕ
| Реквизиты.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| ТаблицаИнвентарь.Номенклатура,
| ТаблицаИнвентарь.ПартияМатериаловВЭксплуатации,
| ТаблицаИнвентарь.ФизЛицо
|
|УПОРЯДОЧИТЬ ПО
| ИмяСписка,
| НомерСтроки";
Возврат ТекстЗапроса + ОбщегоНазначенияБПВызовСервера.ТекстРазделителяЗапросовПакета();
КонецФункции
Как мы видим, в этом запросе, в секции ВЫБРАТЬ, для поля СчетМЦ жестко указано значение ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ИнвентарьИХозяйственныеПринадлежностиВЭксплуатации). Это и есть причина того, что система всегда подставляет МЦ.04. Нам необходимо изменить это место, чтобы счет определялся в зависимости от вида номенклатуры.
Если мы решаем задачу напрямую в конфигурации (что не рекомендуется для обновляемых систем), то изменение будет заключаться в добавлении конструкции ВЫБОР КОГДА ТОГДА ИНАЧЕ КОНЕЦ. Для этого нам понадобится доступ к справочнику "Виды номенклатуры", чтобы определить, относится ли текущая номенклатура к "Учебной литературе".
ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ИнвентарьИХозяйственныеПринадлежностиВЭксплуатации), мы добавим условие:
| ВЫБОР
| КОГДА ТаблицаИнвентарь.Номенклатура.ВидНоменклатуры = &ВидНоменклатуры
| ТОГДА &СчетМЦ06
| ИНАЧЕ ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ИнвентарьИХозяйственныеПринадлежностиВЭксплуатации)
| КОНЕЦ КАК СчетМЦ,
&ВидНоменклатуры и &СчетМЦ06 необходимо будет установить перед выполнением запроса. Обычно это делается в функции, которая вызывает ТекстЗапросаСписаниеИнвентаря, например, в ПодготовитьПараметрыПроведения документа или напрямую перед вызовом метода Запрос.ВыполнитьПакет().Для сохранения возможности обновления типовой конфигурации мы будем использовать расширение. Нам потребуется заместить две функции: ПодготовитьПараметрыПроведения и ТекстЗапросаСписаниеИнвентаря.
В этой функции мы будем устанавливать параметры запроса, которые понадобятся нам для динамического определения счета: ссылку на вид номенклатуры "Учебная литература" и ссылку на наш новый забалансовый счет МЦ.06.
Создадим новое расширение и добавим в него модуль менеджера документа "Списание материалов из эксплуатации". В этот модуль поместим следующий код, используя директиву &Вместо:
&Вместо("ПодготовитьПараметрыПроведения")
Функция ИНФ_ПодготовитьПараметрыПроведения(ДокументСсылка, Отказ)
ПараметрыПроведения = Новый Структура;
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
Запрос.Текст =
"ВЫБРАТЬ
| Реквизиты.Дата КАК Период,
| Реквизиты.Организация КАК Организация
|ИЗ
| Документ.СписаниеМатериаловИзЭксплуатации КАК Реквизиты
|ГДЕ
| Реквизиты.Ссылка = &Ссылка";
Выборка = Запрос.Выполнить().Выбрать();
Выборка.Следующий();
Если НЕ УчетнаяПолитика.Существует(Выборка.Организация, Выборка.Период, Истина, ДокументСсылка) Тогда
Отказ = Истина;
Возврат ПараметрыПроведения;
КонецЕсли;
Запрос.УстановитьПараметр("СинонимСпецодежда", НСтр("ru = 'Спецодежда'"));
Запрос.УстановитьПараметр("СинонимСпецоснастка", НСтр("ru = 'Спецоснастка'"));
Запрос.УстановитьПараметр("СинонимИнвентарь", НСтр("ru = 'Инвентарь и хозяйственные принадлежности'"));
//+++ Добавляем свои параметры
Запрос.УстановитьПараметр("ВидНоменклатуры" , Справочники.ВидыНоменклатуры.НайтиПоНаименованию("Учебная литература"));
Запрос.УстановитьПараметр("СчетМЦ06", ПланыСчетов.Хозрасчетный.НайтиПоКоду("МЦ.06"));
//---
НомераТаблиц = Новый Структура;
Запрос.Текст = ТекстЗапросаСписаниеСпецодеждыСпецоснастки(НомераТаблиц)
+ ТекстЗапросаСписаниеИнвентаря(НомераТаблиц); // Здесь вызывается замещенная функция!
Результат = Запрос.ВыполнитьПакет();
Для Каждого НомерТаблицы Из НомераТаблиц Цикл
ПараметрыПроведения.Вставить(НомерТаблицы.Ключ, Результат[НомерТаблицы.Значение].Выгрузить());
КонецЦикла;
Возврат ПараметрыПроведения;
КонецФункции
Обратите внимание на строки, отмеченные //+++ и //---. Здесь мы получаем ссылки на наш вид номенклатуры и счет МЦ.06 и устанавливаем их в качестве параметров запроса.
Далее мы замещаем функцию ТекстЗапросаСписаниеИнвентаря, чтобы включить в нее логику выбора счета. В модуль менеджера документа из расширения добавим:
&Вместо("ТекстЗапросаСписаниеИнвентаря")
Функция ИНФТекстЗапросаСписаниеИнвентаря(НомераТаблиц)
НомераТаблиц.Вставить("СписаниеИнвентаряРеквизиты", НомераТаблиц.Количество());
НомераТаблиц.Вставить("СписаниеИнвентаряТаблица", НомераТаблиц.Количество());
ТекстЗапроса =
"ВЫБРАТЬ
| Реквизиты.Ссылка КАК Регистратор,
| Реквизиты.Дата КАК Период,
| Реквизиты.Организация,
| Реквизиты.ПодразделениеОрганизации КАК Подразделение
|ИЗ
| Документ.СписаниеМатериаловИзЭксплуатации КАК Реквизиты
|ГДЕ
| Реквизиты.Ссылка = &Ссылка
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ""ИнвентарьИХозяйственныеПринадлежности"" КАК ИмяСписка,
| &СинонимИнвентарь КАК СинонимСписка,
| МИНИМУМ(ТаблицаИнвентарь.НомерСтроки) КАК НомерСтроки,
| ТаблицаИнвентарь.Номенклатура,
| ТаблицаИнвентарь.ПартияМатериаловВЭксплуатации,
| ТаблицаИнвентарь.ФизЛицо,
| ВЫБОР
| КОГДА ТаблицаИнвентарь.Номенклатура.ВидНоменклатуры = &ВидНоменклатуры
| ТОГДА &СчетМЦ06
| ИНАЧЕ ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ИнвентарьИХозяйственныеПринадлежностиВЭксплуатации)
| КОНЕЦ КАК СчетМЦ,
| СУММА(ТаблицаИнвентарь.Количество) КАК КоличествоМЦ
|ИЗ
| Документ.СписаниеМатериаловИзЭксплуатации.ИнвентарьИХозяйственныеПринадлежности КАК ТаблицаИнвентарь
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.СписаниеМатериаловИзЭксплуатации КАК Реквизиты
| ПО ТаблицаИнвентарь.Ссылка = Реквизиты.Ссылка
|ГДЕ
| Реквизиты.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| ТаблицаИнвентарь.Номенклатура,
| ТаблицаИнвентарь.ПартияМатериаловВЭксплуатации,
| ТаблицаИнвентарь.ФизЛицо
|
|УПОРЯДОЧИТЬ ПО
| ИмяСписка,
| НомерСтроки";
Возврат ТекстЗапроса + ОбщегоНазначенияБПВызовСервера.ТекстРазделителяЗапросовПакета();
КонецФункции
Здесь мы вставляем нашу логику ВЫБОР КОГДА в поле СчетМЦ, используя параметры &ВидНоменклатуры и &СчетМЦ06, которые мы установили в замещенной функции ИНФ_ПодготовитьПараметрыПроведения.
Если после внедрения расширения вы по-прежнему сталкиваетесь с ошибкой "Указанное количество превышает остаток по счету МЦ.04", это означает, что логика динамического выбора счета в запросе не сработала должным образом, и система по-прежнему пытается найти остатки на МЦ.04 для вашей "Учебной литературы". Фраза "пытается списать 2 раза" является неверной интерпретацией; система просто не находит нужный остаток на неправильном счете.
Давайте разберем по шагам, как локализовать и устранить эту проблему:
ИНФ_ПодготовитьПараметрыПроведения:
Запрос.УстановитьПараметр("ВидНоменклатуры" , Справочники.ВидыНоменклатуры.НайтиПоНаименованию("Учебная литература"));
Запрос.УстановитьПараметр("СчетМЦ06", ПланыСчетов.Хозрасчетный.НайтиПоКоду("МЦ.06"));
Справочники.ВидыНоменклатуры.НайтиПоНаименованию("Учебная литература") возвращает корректную ссылку на ваш предопределенный или добавленный вид номенклатуры. Возможно, вы ошиблись в наименовании или такого вида не существует.ПланыСчетов.Хозрасчетный.НайтиПоКоду("МЦ.06") возвращает ссылку на ваш созданный счет МЦ.06. Убедитесь, что счет действительно существует в плане счетов и имеет код "МЦ.06".ИНФТекстЗапросаСписаниеИнвентаря.&Ссылка (ссылка на ваш тестовый документ списания), &ВидНоменклатуры (та же ссылка, что и в отладчике), &СчетМЦ06 (та же ссылка, что и в отладчике) и &СинонимИнвентарь.СчетМЦ вы должны увидеть МЦ.06 для номенклатуры "Учебная литература" и МЦ.04 для других видов. Если все еще видите МЦ.04 для "Учебной литературы", значит, условие КОГДА ТаблицаИнвентарь.Номенклатура.ВидНоменклатуры = &ВидНоменклатуры не срабатывает. Это может быть связано с тем, что свойство ВидНоменклатуры у вашей конкретной номенклатуры не соответствует значению, переданному в параметр.ПодготовитьТаблицуСписанныйИзЭксплуатацииИнвентарь:
УчетМатериаловВЭксплуатации) является типовой и, скорее всего, не замещена вашим расширением. Именно в ней происходит проверка остатков и формируется сообщение об ошибке.
Если СтрокаТаблицы.КоличествоМЦ > СтрокаТаблицы.КоличествоМЦОстаток Тогда
ТаблицаСписанныеМатериалы (или непосредственно СтрокаТаблицы для проблемной строки).СтрокаТаблицы.СчетМЦ для той строки, которая вызывает ошибку. Если там по-прежнему стоит МЦ.04, а не МЦ.06, то это окончательно подтверждает, что ваш модифицированный запрос не сработал так, как ожидалось, и не подставил правильный счет.Справочники.ВидыНоменклатуры.НайтиПоНаименованию("Учебная литература")). Возможно, номенклатура была создана без указания этого вида или с другим.Важный момент: убедитесь, что ваш забалансовый счет МЦ.06 имеет нужные субконто. В типовом запросе используются субконто Номенклатура, ПартииМатериаловВЭксплуатации и РаботникиОрганизаций. Если на вашем счете МЦ.06 отсутствуют эти субконто, или они настроены иначе, запрос к регистру бухгалтерии может не дать корректных остатков, даже если счет будет правильным.
Тщательная пошаговая отладка и проверка всех промежуточных значений и параметров, начиная с самой верхней точки входа в замещенные функции и спускаясь к выполнению запроса, является наиболее эффективным способом найти и устранить причину проблемы.