Как распределить остатки материалов по многоуровневым спецификациям в 1С?

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

При автоматизации производственного учета на базе конфигураций 1С (например, 1С:УПП или 1С:ERP) часто возникает классическая задача: распределить имеющиеся на складах свободные остатки материалов по запланированному выпуску продукции. Проблема существенно усложняется, если изделия имеют многоуровневую структуру спецификаций (полуфабрикаты изготавливаются из других полуфабрикатов), а один и тот же материал встречается несколько раз на разных уровнях вложенности.

Рассмотрим причину возникновения этой проблемы и разберем архитектурно правильные алгоритмы её решения.

Суть проблемы: почему простой обход «сверху вниз» выдает ошибочный результат

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

Представим, что материал А используется на уровне 1 (в финальной сборке) и на уровне 5 (при производстве базового полуфабриката). Технологически изготовление полуфабриката на уровне 5 должно произойти раньше, чем сборка готового изделия. Если мы спишем складской остаток материала А на уровне 1, то на уровне 5 возникнет дефицит. В результате производство не сможет даже начать изготовление базовых деталей, и вся цепочка остановится.

С точки зрения теории графов многоуровневая спецификация представляет собой не простое дерево, а ориентированный ациклический граф (DAG). Складские остатки необходимо распределять с учетом хронологической последовательности потребления и технологических приоритетов.

Алгоритм 1. Расчет по календарным датам потребностей (Backward Scheduling)

Это наилучший и самый практичный способ решения задачи. Разберем его по шагам:

  1. Рассчитываем технологические циклы (опережения): Для каждого полуфабриката и готового изделия задается длительность его производства (в днях или часах).
  2. Выполняем обратное планирование: Зная целевую дату выпуска готовой продукции, рассчитываем точную дату, к которой материал должен физически присутствовать на рабочем месте для выполнения конкретного этапа. Назовем её ДатаПотребности.
  3. Формируем плоскую структуру потребления: Разузловываем весь производственный план в единую плоскую таблицу (ТЗ потребностей), расщепляя все вхождения материалов на отдельные строки.
  4. Сортируем потребности: Упорядочиваем таблицу потребностей по следующим ключам:

    [ПриоритетЗаказа] -> [ДатаПотребности (возрастание)] -> [УровеньВложенности (убывание)]

  5. Распределяем остатки: За один проход сверху вниз по отсортированной таблице закрываем потребности имеющимися складскими остатками.

Рассмотрим пример реализации сортировки плоской таблицы потребностей в коде 1С:


// Формируем структуру колонок таблицы потребностей
ТЗПотребностей = Новый ТаблицаЗначений;
ТЗПотребностей.Колонки.Добавить("Заказ", Новый ОписаниеТипов("ДокументСсылка.ЗаказПокупателя"));
ТЗПотребностей.Колонки.Добавить("ПриоритетЗаказа", Новый ОписаниеТипов("Число"));
ТЗПотребностей.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗПотребностей.Колонки.Добавить("КоличествоПотребность", Новый ОписаниеТипов("Число"));
ТЗПотребностей.Колонки.Добавить("ДатаПотребности", Новый ОписаниеТипов("Дата"));
ТЗПотребностей.Колонки.Добавить("УровеньВложенности", Новый ОписаниеТипов("Число"));

// Сортируем потребности: сначала ранние даты потребностей и более глубокие переделы
ТЗПотребностей.Сортировать("ПриоритетЗаказа Возр, ДатаПотребности Возр, УровеньВложенности Убыв");

Алгоритм 2. Классический код нижнего уровня (Low-Level Code / LLC)

В стандартах MRP II для корректной работы с графами спецификаций используется индекс Low-Level Code (LLC).

Выясним принцип его работы:

  1. Для каждой номенклатурной позиции в системе определяется максимальная глубина, на которой эта номенклатура встречается во ВСЕХ спецификациях предприятия.
  2. Если материал используется на уровнях 1, 3 и 5, его общесистемный код LLC устанавливается равным 5.
  3. Расчет чистой потребности и распределение остатков выполняется строго в порядке возрастания кода LLC (начиная с самых глубоких узлов и чистого сырья вверх к готовой продукции).

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

Алгоритм 3. Двухпроходный учет наличных полуфабрикатов

Частая ошибка при распределении сырья — игнорирование готовых полуфабрикатов, уже находящихся на складе. Если полуфабрикат уже произведен, разузловывать его и запрашивать под него исходные материалы не требуется.

Разберем двухпроходный алгоритм:

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

Пример алгоритмической обработки структуры в 1С при анализе полуфабрикатов:


Функция РазузловатьСУчетомОстатковПФ(НоменклатураУзла, КоличествоПотребное, СборкаОстатков)
    
    // Проверяем остаток полуфабриката на складе
    ОстатокПФ = ПолучитьОстатокНаСкладе(НоменклатураУзла, СборкаОстатков);
    
    ОбеспеченоПФ = Мин(КоличествоПотребное, ОстатокПФ);
    НеобходимыйВыпуск = КоличествоПотребное - ОбеспеченоПФ;
    
    // Списываем использованный остаток полуфабриката
    ЗафиксироватьРасчетОстатка(НоменклатураУзла, ОбеспеченоПФ, СборкаОстатков);
    
    // Если готового полуфабриката не хватило — разузловываем его спецификацию дальше
    Если НеобходимыйВыпуск > 0 Тогда
        Спецификация = ПолучитьОсновнуюСпецификацию(НоменклатураУзла);
        Для Каждого СтрокаСостава Из Спецификация.Состав Цикл
            РазузловатьСУчетомОстатковПФ(СтрокаСостава.Номенклатура, СтрокаСостава.Количество * НеобходимыйВыпуск, СборкаОстатков);
        КонецЦикла;
    КонецЕсли;

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

Подводим итоги

Для корректного распределения остатков материалов по многоуровневым спецификациям необходимо отказаться от простого сплошного списания материалов по дереву спецификации. Выберите подходящую методику:

← На главную