При разработке механизмов складского учета в системе 1С программисты часто сталкиваются с задачей отражения перемещения товаров между складами. Казалось бы, это простая операция, требующая лишь формирования проводки по счету 41 (Товары на складах). Однако ключевая сложность заключается в правильном расчете суммы проводки — себестоимости перемещаемого товара. Поскольку в самом документе перемещения цена обычно не указывается пользователем (так как она определяется учетной политикой), система должна рассчитать ее автоматически в момент проведения на основании данных регистра бухгалтерии.
В этой статье мы подробно разберем, как реализовать этот алгоритм, на что обратить внимание при получении остатков и как избежать типичных ошибок, из-за которых в учете возникают «зависшие копейки».
Прежде чем приступать к написанию кода, проанализируем структуру нашего регистра. Для счета 41 (или его аналога в вашей конфигурации) обычно определены два основных субконто: Номенклатура и Склад. Важно понимать, как настроен учет по этим аналитикам в Плане счетов.
Рассмотрим два варианта настройки учета по складам:
Проанализируем ситуацию: если мы перемещаем товар со Склада 1 на Склад 2, нам необходимо получить остатки по счету 41 в разрезе Организации, Номенклатуры и Склада-отправителя.
Наиболее популярный метод оценки ТМЦ при выбытии — расчет по средней стоимости. Выясним причину, почему это стандарт индустрии: он прост в реализации и дает предсказуемый результат без привязки к конкретным партиям (если не используется ФИФО).
Математическая формула расчета выглядит следующим образом:
СуммаСписания = (СуммаОстатка / КоличествоОстатка) * КоличествоКПеремещению
Однако при программной реализации этой формулы возникают нюансы. Рассмотрим их подробнее.
Для получения данных мы должны обратиться к виртуальной таблице Остатки регистра бухгалтерии. Проанализируем пример кода для получения остатков перед формированием движений. Важно использовать Границу, чтобы не учитывать движения самого документа при его перепроведении.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстатки.СуммаОстаток КАК СуммаОстаток,
| ХозрасчетныйОстатки.КоличествоОстаток КАК КоличествоОстаток
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(&МоментВремени, Счет = &Счет41, ,
| Организация = &Организация
| И Субконто1 = &Номенклатура
| И Субконто2 = &СкладОтправитель) КАК ХозрасчетныйОстатки";
Запрос.УстановитьПараметр("МоментВремени", Новый Граница(МоментВремени(), ВидГраницы.Исключая));
Запрос.УстановитьПараметр("Счет41", ПланыСчетов.Хозрасчетный.ТоварыНаСкладах);
Запрос.УстановитьПараметр("Организация", Организация);
Запрос.УстановитьПараметр("Номенклатура", СтрокаТовары.Номенклатура);
Запрос.УстановитьПараметр("СкладОтправитель", СкладОтправитель);
Обратите внимание: мы используем Субконто1 и Субконто2. В реальной конфигурации лучше использовать обращение по имени вида субконто (ВидыСубконто.Номенклатура), чтобы код оставался рабочим при изменении порядка субконто в плане счетов.
Разберем ситуацию, описанную в сообщениях форума: что будет, если на складе осталось 3 единицы товара общей стоимостью 10 рублей, и мы перемещаем все 3 единицы? Если мы просто разделим 10 на 3, получим 3.3333... При округлении до 2 знаков (3.33) и умножении на 3, мы получим сумму 9.99. В итоге на складе останется 0 единиц товара, но «зависнет» копейка в 0.01 рубля.
Чтобы этого избежать, мы должны использовать проверку: если количество к перемещению равно остатку на складе, мы должны списать всю сумму остатка полностью без вычислений.
Посмотрим на пример правильной логики расчета в коде:
Если Выборка.КоличествоОстаток > 0 Тогда
Если Выборка.КоличествоОстаток = КоличествоКПеремещению Тогда
// Списываем всё под ноль, включая копейки
СуммаСписания = Выборка.СуммаОстаток;
Иначе
// Считаем пропорционально
СуммаСписания = Выборка.СуммаОстаток / Выборка.КоличествоОстаток * КоличествоКПеремещению;
КонецЕсли;
Иначе
// Обработка ситуации отрицательного остатка (если разрешено учетной политикой)
СуммаСписания = 0;
КонецЕсли;
Теперь соберем все воедино и сформируем движение. В перемещении товаров проводка будет иметь вид Дт 41 (Склад-получатель) — Кт 41 (Склад-отправитель). Поскольку это внутреннее перемещение в рамках одной организации, сумма по дебету и кредиту будет одинаковой, а количество отражается только по тем счетам/субконто, где ведется количественный учет.
Движение = Движения.Хозрасчетный.Добавить();
Движение.Период = Дата;
Движение.Организация = Организация;
// Настройка дебета (Куда пришел товар)
Движение.СчетДт = ПланыСчетов.Хозрасчетный.ТоварыНаСкладах;
Движение.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконто.Номенклатура] = СтрокаТовары.Номенклатура;
Движение.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконто.Склады] = СкладПолучатель;
Движение.КоличествоДт = КоличествоКПеремещению;
// Настройка кредита (Откуда ушел товар)
Движение.СчетКт = ПланыСчетов.Хозрасчетный.ТоварыНаСкладах;
Движение.СубконтоКт[ПланыВидовХарактеристик.ВидыСубконто.Номенклатура] = СтрокаТовары.Номенклатура;
Движение.СубконтоКт[ПланыВидовХарактеристик.ВидыСубконто.Склады] = СкладОтправитель;
Движение.КоличествоКт = КоличествоКПеремещению;
// Сумма перемещения (рассчитанная выше себестоимость)
Движение.Сумма = СуммаСписания;
Движение.Содержание = "Перемещение товаров между складами";
Проанализируем еще несколько важных моментов, которые помогут сделать ваше решение профессиональным:
БлокировкаДанных.КоличествоОстаток будет равно нулю, и сумма также будет нулевой. Всегда добавляйте проверку: если остатка недостаточно, документ не должен проводиться (или выводить предупреждение).СуммаНУ, если ваша организация ведет учет по налогу на прибыль.ОбработкаПроведения. Не пытайтесь рассчитывать себестоимость «на лету» в форме документа, так как данные в базе могут измениться к моменту нажатия кнопки «Провести».Подведем итог: расчет себестоимости при перемещении — это не просто деление суммы на количество. Это комплексная задача, включающая контроль момента времени, работу с остатками и обязательную проверку на полное списание остатка для предотвращения накопления копеек. Следуя приведенным шагам, вы сможете реализовать надежный механизм складского учета в любой конфигурации на платформе 1С.