Как правильно рассчитать остатки материалов и комплектующих в 1С при упаковке деталей?

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

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

Анализ основной ошибки: Обороты против Остатков

Разберем ситуацию, описанную автором: для учета остатков используется регистр накопления с видом Обороты. В системе 1С существует два принципиально разных типа регистров накопления:

  1. Регистр накопления «Обороты» — предназначен для хранения информации о «потоках» данных (объемы продаж, суммы выручки, количество оказанных услуг за период). Он не хранит итоговое сальдо на конкретный момент времени.
  2. Регистр накопления «Остатки» — специально создан для контроля ресурсов. Система автоматически поддерживает актуальные итоги на любую дату.

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

Проектирование правильной структуры регистра

Для решения задачи упаковки деталей (кейсы, палеты, решетки) нам необходимо создать регистр накопления «ОстаткиМатериалов» (вид — Остатки). Выясним, какие измерения и ресурсы нам понадобятся:

Важный момент в коде автора: ЗапросОстаток.УстановитьПараметр("МодельДетали", Объект.Ссылка);. Это критическая ошибка. В измерениях регистра должна храниться ссылка на элемент справочника (например, «Диск сцепления»), а не ссылка на сам документ. Документ в регистре выступает в роли Регистратора, но не должен быть фильтром для получения остатка по конкретной номенклатуре.

Математика упаковки и переходящий остаток

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

Для получения целого количества упаковок и остатка в 1С эффективно использовать функции работы с числами:


// Количество деталей на линии
ОбщееКоличество = 550; 
ВместимостьПалеты = 60;

// Вычисляем количество полных палет
КоличествоПалет = Цел(ОбщееКоличество / ВместимостьПалеты); 

// Вычисляем остаток, который не влез в целую палету
ОстатокДеталей = ОбщееКоличество % ВместимостьПалеты; 

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

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

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


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

// Используем Границу, чтобы получить остатки строго ДО текущего документа
ГраницаОстатков = Новый Граница(Объект.Дата, ВидГраницы.Исключая);
Запрос.УстановитьПараметр("МоментВремени", ГраницаОстатков);
Запрос.УстановитьПараметр("Номенклатура", ВыбраннаяДеталь);

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

Автоматизация заполнения материалов (Спецификации)

В тексте обсуждения упоминается, что на каждую коробку нужно 2 крышки, 5 решеток и т.д. Программировать такие коэффициенты жестко в коде (Количество * 5) — плохая практика. Правильнее использовать механизм Спецификаций.

Создадим справочник «Спецификации», подчиненный справочнику «Номенклатура». В табличной части спецификации укажем нормативы расхода. Тогда при изменении количества деталей на форме документа, мы выполним следующий алгоритм:

  1. Перейдем на сервер в процедуру &НаСервере.
  2. Запросом выберем состав спецификации для данной модели детали.
  3. Умножим количество планируемых упаковок на норматив из спецификации.
  4. Заполним табличную часть «Материалы» документа полученными строками.

Рассмотрим пример кода для такого заполнения:


&НаСервере
Процедура ЗаполнитьМатериалыПоСпецификации()
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	СпецификацииСостав.Материал,
        |	СпецификацииСостав.Количество * &КоличествоУпаковок КАК НужноМатериалов
        |ИЗ
        |	Справочник.Спецификации.Состав КАК СпецификацииСостав
        |ГДЕ
        |	СпецификацииСостав.Ссылка = &ВыбраннаяСпецификация";
        
    Запрос.УстановитьПараметр("КоличествоУпаковок", Объект.КоличествоПалетов);
    Запрос.УстановитьПараметр("ВыбраннаяСпецификация", Объект.Спецификация);
    
    // Очищаем и заполняем ТЧ
    Объект.Материалы.Очистить();
    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        НоваяСтрока = Объект.Материалы.Добавить();
        НоваяСтрока.НаименованиеМатериала = Выборка.Материал;
        НоваяСтрока.Количество = Выборка.НужноМатериалов;
    КонецЦикла;
КонецПроцедуры

Проблема «Среза последних» в регистрах накопления

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

Если вы хотите реализовать логику «последней записи», как в регистре сведений, но при этом иметь возможность суммировать остатки, вам все равно нужен регистр накопления. Но доступ к данным в нем осуществляется через запросы к виртуальным таблицам, а не через менеджер регистра с методами среза.

Оптимизация работы формы (Клиент-Сервер)

Проанализируем взаимодействие клиента и сервера. Автор вызывает серверную процедуру при каждом изменении количества. Если расчет простой (например, деление на 60), это можно и нужно делать &НаКлиенте. Это избавит пользователя от микро-задержек при вводе данных. На сервер стоит обращаться только тогда, когда нужен запрос к базе данных (получение остатков или чтение спецификации).

Итоги и рекомендации

Для успешной реализации задачи упаковки деталей необходимо:

  1. Изменить вид регистра «ЛайнОстаток» на Остатки.
  2. Пересмотреть логику проведения: при проведении документа «Расход» материалы должны списываться из регистра, а при «Приходе» — зачисляться.
  3. Использовать Справочник Спецификаций для хранения норм расхода материалов вместо «зашитых» в код формул.
  4. В запросах всегда делать отбор по измерениям (Номенклатура, Модель), а не по ссылке на сам документ.

Соблюдение этих архитектурных принципов 1С позволит создать надежную систему, которая будет корректно считать остатки независимо от количества документов и сложности производственных цепочек.

← На главную