Как заполнить Приходную накладную остатками из Заказа поставщику в 1С?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

При разработке функционала в системе 1С:Предприятие одной из наиболее часто встречающихся задач является реализация механизма «Ввод на основании». В частности, когда мы создаем Приходную накладную на базе Заказа поставщику, критически важно, чтобы в новый документ попадали не просто все строки из заказа, а только те позиции, которые еще не были фактически получены. Для этого нам необходимо обратиться к остаткам по регистрам накопления. Рассмотрим подробно, как реализовать этот алгоритм правильно и эффективно.

Использование механизма ОбработкаЗаполнения

Первым делом проанализируем, где именно должен располагаться программный код. Вся логика по заполнению данных при создании документа на основании другого объекта должна находиться в модуле объекта документа-приемника (в нашем случае это Приходная накладная). Нам потребуется предопределенная процедура ОбработкаЗаполнения.

Разберем структуру этой процедуры:


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

Параметр ДанныеЗаполнения в данном контексте будет содержать ссылку на Заказ поставщику, послуживший основанием. Важно понимать, что на этом этапе сам объект Приходная накладная еще не записан в базу данных, и мы работаем с его оперативной памятью (свойство ЭтотОбъект).

Получение данных через запрос к виртуальной таблице остатков

Для того чтобы получить актуальные остатки, мы не должны просто копировать строки из табличной части заказа. Нам необходимо обратиться к виртуальной таблице Остатки соответствующего регистра накопления (например, ЗаказыПоставщикам.Остатки). Рассмотрим пример построения такого запроса.

Выясним причину, по которой это важно: если поставщик привозит товар частями, то в каждой новой накладной должны отображаться только «хвосты» — то, что еще не доехало. Если мы просто скопируем ТЧ заказа, мы получим завышенные данные.

Пример программного кода для получения остатков:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЗаказыПоставщикамОстатки.Номенклатура КАК Номенклатура,
    |	ЗаказыПоставщикамОстатки.Характеристика КАК Характеристика,
    |	ЗаказыПоставщикамОстатки.КоличествоОстаток КАК Количество
    |ИЗ
    |	РегистрНакопления.ЗаказыПоставщикам.Остатки(, ЗаказПоставщику = &ЗаказПоставщику) КАК ЗаказыПоставщикамОстатки";

Запрос.УстановитьПараметр("ЗаказПоставщику", ДанныеЗаполнения);
РезультатЗапроса = Запрос.Выполнить();

Важный нюанс: Обратите внимание на параметры виртуальной таблицы Остатки(). Мы обязательно передаем условие по конкретному заказу. Если этого не сделать, система попытается рассчитать остатки по всем заказам всех поставщиков в базе данных, что приведет к катастрофическому падению производительности на реальных объемах данных.

Перенос данных в табличную часть документа

После того как мы получили таблицу с остатками, нам нужно перенести эти данные в табличную часть Товары нашего документа. Существует два основных способа: использование метода Загрузить() и ручной обход в цикле. Проанализируем каждый из них.

Способ 1: Метод Загрузить()

Этот способ самый быстрый. Он полностью очищает табличную часть и заполняет ее данными из таблицы значений. Однако, имена колонок в результате запроса должны в точности совпадать с именами колонок в табличной части документа.


ТаблицаОстатков = РезультатЗапроса.Выгрузить();
ЭтотОбъект.Товары.Загрузить(ТаблицаОстатков);

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

Способ 2: Обход в цикле

Если нам нужно выполнить дополнительную обработку данных (например, пересчитать цены или заполнить счета учета), мы используем цикл Для каждого.


Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    НоваяСтрока = ЭтотОбъект.Товары.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
    // Здесь можно добавить произвольную логику
    // НоваяСтрока.Цена = ПолучитьЦенуНоменклатуры(Выборка.Номенклатура);
КонецЦикла;

Обработка характеристик и единиц измерения

Проанализируем ситуацию, когда учет ведется в разрезе характеристик или используются разные единицы измерения. Если в Заказе поставщику товар указан в упаковках, а в регистре остатки хранятся в базовых единицах (штуках), при заполнении Приходной накладной необходимо выполнить обратный пересчет.

  1. Характеристики: Всегда включайте Характеристика в измерения регистра и в группировки запроса. Иначе остатки по разным цветам или размерам одного товара «схлопнутся» в одну строку.
  2. Единицы измерения: Если выгружаете КоличествоОстаток, убедитесь, что в документе-приемнике используется та же единица. Если нет — умножайте или делите на Коэффициент из справочника упаковок.

Проверка на пустой результат

Хорошей практикой считается добавление проверки перед заполнением. Если по заказу уже нет остатков (все товары поступили), программа должна сообщить об этом пользователю, а не просто открывать пустой документ.


Если РезультатЗапроса.Пустой() Тогда
    ТекстСообщения = "По выбранному заказу нет доступных остатков для оформления поступления.";
    ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения);
    Возврат;
КонецЕсли;

Посмотрим на ситуацию со стороны пользователя: если он случайно нажмет «Создать на основании» для уже закрытого заказа, он сразу увидит предупреждение, что сэкономит его время на выяснение причин пустой таблицы в накладной.

Резюме

Для корректной реализации добавления остатков мы выполнили следующие шаги: во-первых, использовали процедуру ОбработкаЗаполнения в модуле объекта; во-вторых, составили эффективный запрос к виртуальной таблице остатков регистра накопления с фильтром по документу-основанию; в-третьих, обеспечили корректный перенос данных в табличную часть, учитывая контекст выполнения кода и структуру метаданных.

← На главную