Как правильно организовать списание товаров по партиям из собственного регистра накопления в 1С: разбираем методы и подходы?

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

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

Суть партионного учета заключается в том, что каждый ресурс, поступающий на склад, рассматривается как отдельная партия. Эти партии могут иметь различные свойства: разную закупочную цену, поставщика, срок годности, номер ГТД и так далее. Это позволяет нам не просто знать общее количество товара, но и понимать, из какой "кучки" он поступил, и, соответственно, корректно рассчитывать себестоимость при его списании.

Для реализации партионного учета в 1С мы, как правило, используем регистры накопления вида "Остатки". Эти регистры позволяют нам хранить информацию о текущем наличии ресурсов в различных разрезах и отслеживать их движение.

Основные методы списания себестоимости при партионном учете

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

  1. ФИФО (FIFO - First In, First Out): Метод "первым пришел, первым ушел". Это наиболее распространенный подход, согласно которому товары списываются в той последовательности, в которой они поступили на склад. То есть, сначала списываются самые ранние партии.
  2. ЛИФО (LIFO - Last In, First Out): Метод "последним пришел, первым ушел". При этом методе товары списываются из последних поступивших партий. В настоящее время метод ЛИФО редко применяется из-за требований бухгалтерского учета.
  3. По средней себестоимости: В этом случае себестоимость списывается по усредненной цене всех имеющихся запасов товара. Если выбран этот метод, то конкретная партия для расчета себестоимости не имеет значения, и субконто "Партии" может не заполняться в движениях регистра.

Выбор метода списания обычно устанавливается в учетной политике предприятия и определяет логику формирования движений по регистрам.

Структура собственного регистра накопления для партионного учета

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

Подходы к определению и фиксации партий в документах

Давайте проанализируем различные сценарии, когда и как "партии" определяются и фиксируются в документах, основываясь на практическом опыте:

1. Партии исключительно для расчета себестоимости

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

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

Мы должны понимать, что оперативное проведение документа в 1С подразумевает контроль остатков и актуальность данных "здесь и сейчас". Неоперативное проведение позволяет регистрировать операции прошедшей или будущей датой без такого строгого контроля. Для партионного учета, особенно при расчете себестоимости, изменения задним числом требуют перепроведения всех последующих документов, чтобы восстановить правильную последовательность списания партий.

2. Привязка партий к документу через табличную часть

В некоторых случаях, когда "партии" необходимо жестко закрепить за конкретным документом (например, документом реализации или производства), мы можем заполнять их автоматически в отдельной табличной части документа. Посмотрим на пример стандартных конфигураций, таких как УТ/ЕРП/КА, где аналогично реализован учет ГТД.

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

3. Партии, определяемые уникальными характеристиками товара

Если ваши "партии" определяются по уникальным характеристикам самого товара, таким как серии на лекарствах, IMEI-коды телефонов или коды маркировки в системе "Честный Знак", то подход будет иным. В этом случае придется заполнять данные о партии "ручками" (например, путем сканирования штрихкода) или с использованием специализированного оборудования. Эти данные также должны быть зафиксированы в документе.

Алгоритм списания партий из регистра накопления

Теперь давайте перейдем к практической реализации списания партий. Мы с вами разберем по шагам, как это можно сделать в коде 1С.

1. Итерация по строкам документа и подтягивание партий

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

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ОстаткиПартий.Номенклатура,
    |    ОстаткиПартий.Партия,
    |    ОстаткиПартий.КоличествоОстаток,
    |    ОстаткиПартий.СуммаОстаток
    |ИЗ
    |    РегистрНакопления.МойРегистрПартий.Остатки(
    |        &ДатаДокумента,
    |        Номенклатура В (&СписокНоменклатуры)
    |    ) КАК ОстаткиПартий
    |ГДЕ
    |    ОстаткиПартий.КоличествоОстаток > 0
    |
    |УПОРЯДОЧИТЬ ПО
    |    ОстаткиПартий.Партия.ДатаПоступления ВОЗР"; // Для ФИФО

Запрос.УстановитьПараметр("ДатаДокумента", МоментВремениДокумента);
Запрос.УстановитьПараметр("СписокНоменклатуры", СписокНоменклатурыИзДокумента);

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

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

В этом примере мы сначала получаем все остатки нужной номенклатуры, отсортированные по дате поступления партии (для метода ФИФО). Затем мы итерируем по строкам документа и для каждой строки пытаемся списать необходимое количество из доступных партий.

2. Двойной контроль остатков регистра

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

Контроль на дату документа: Мы проверяем, достаточно ли остатков на момент проведения документа, чтобы предотвратить списание "в минус" по партиям. Это можно сделать, используя запрос к виртуальной таблице Остатки с параметром &ДатаДокумента.

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

3. Связывание строк документа с движениями регистра

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

Давайте посмотрим, как это можно добавить в наш пример:


// ... (начало цикла по строкам документа)

    // ... (внутри цикла по строкам документа, перед добавлением движения)
    Движение = Движения.МойРегистрПартий.Добавить();
    Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
    Движение.Период = МоментВремениДокумента;
    Движение.Номенклатура = СтрокаДокумента.Номенклатура;
    Движение.Партия = СтрокаОстатка.Партия;
    Движение.Количество = КоличествоСписатьИзПартии;
    Движение.Сумма = КоличествоСписатьИзПартии * СтрокаОстатка.СуммаОстаток / СтрокаОстатка.КоличествоОстаток;
    
    // Привязываем движение к строке табличной части документа
    Движение.ПривязыватьСтроку(СтрокаДокумента); 
    
    ОсталосьСписать = ОсталосьСписать - КоличествоСписатьИзПартии;
    СтрокаОстатка.КоличествоОстаток = СтрокаОстатка.КоличествоОстаток - КоличествоСписатьИзПартии;

// ... (продолжение цикла)

Метод ПривязыватьСтроку() создает неявную связь между строкой табличной части и движением, что позволяет, например, при изменении или удалении строки документа автоматически корректировать связанные с ней движения регистра.

Дополнительные рекомендации и особенности

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

← К списку