При работе в 1С:Предприятие 8.3 Управление Торговлей (УТ) многие пользователи сталкиваются с ситуацией, когда в расходной накладной колонка «Мест» автоматически округляет количество упаковок до целого числа, даже если фактическое количество товара не составляет полную упаковку. Это создает сложности при отгрузке, учете и контроле товарных остатков, особенно для кладовщиков, которые ориентируются на точные логистические единицы. В данном материале мы подробно разберем эту проблему и предложим несколько подходов к ее решению, начиная от рекомендуемой программной доработки и заканчивая альтернативными методами.
Давайте вместе проанализируем, почему возникает такая ситуация и что мы можем предпринять, чтобы настроить систему под наши специфические требования.
Суть проблемы заключается в том, что в расходной накладной (документ Реализация товаров и услуг) обычно присутствуют две важные колонки для количественного учета товара: «Мест» и «Количество». Колонка «Количество», как правило, отражает товар в базовых единицах измерения (например, в штуках), а колонка «Мест» предназначена для указания количества логистических единиц (упаковок, коробок, паллет, дисплеев). Изначально программа 1С:УТ спроектирована таким образом, чтобы отображать количество «Мест» как целое число, так как предполагается, что эти места являются физическими, неделимыми упаковками.
Рассмотрим пример, который приводится в нашей теме: если одна упаковка товара, которую мы назовем «дисплеем», содержит 48 штук (например, «Киндеры»), и мы отгружаем 30 штук, что не является кратным 48, то программа все равно может заполнить колонку «Мест» значением «1 дисп». Это происходит из-за внутреннего алгоритма округления или взятия целой части, который стремится показать, что хотя бы часть товара находится в одной такой упаковке, или же просто округляет до ближайшего целого. В результате, кладовщик или любой другой сотрудник, работающий с накладной, может быть введен в заблуждение, увидев «1 дисплей» при фактической отгрузке неполной упаковки.
Даже более показательный пример – отгрузка 440 штук. В этом случае 440 штук составляют 9.17 дисплеев (440 / 48). Типовая конфигурация 1С:УТ может округлить это значение до 10 дисплеев в колонке «Мест», что является еще большим искажением реальной картины. Желаемым поведением в таких ситуациях является либо оставление колонки «Мест» пустой, либо обнуление ее значения, если количество товара не кратно полному дисплею.
Мы выясним причину такого поведения: стандартное округление в 1С:УТ часто обусловлено тем, что поле «Мест» предназначено для отражения логистических единиц (транспортных мест, паллет, коробок) и ожидается, что они будут целыми. Программа не всегда учитывает сценарии, когда часть упаковки может быть отгружена отдельно без создания новой неполной упаковки. Таким образом, типовая логика направлена на упрощение учета целых упаковок, но вводит в заблуждение при работе с их частями.
Прежде чем переходить к решениям, давайте кратко рассмотрим, как устроены единицы измерения и упаковки в 1С:УТ, так как это напрямую влияет на обсуждаемую проблему.
Базовая единица измерения: Для каждой номенклатуры обязательно указывается базовая единица, в которой ведется основной учет остатков (например, «шт» для штук, «кг» для килограммов).
Единицы измерения-упаковки: Помимо базовой единицы, для номенклатуры можно настроить дополнительные единицы измерения, которые являются упаковками. Например, для товара «Киндер» базовой единицей будет «шт», а упаковками могут быть «дисплей» или «коробка». Для каждой такой упаковки мы задаем коэффициент пересчета относительно базовой единицы (например, 1 дисплей = 48 штук).
Настройка номенклатуры: В карточке номенклатуры (справочник Номенклатура) указываются основные единицы измерения, а также может быть задан набор упаковок, что позволяет системе автоматически пересчитывать количество между различными единицами.
Несмотря на эти настройки, типовая конфигурация 1С:УТ зачастую не предоставляет достаточной гибкости для управления округлением колонки «Мест» в расходной накладной в случае некратных количеств. То есть, даже если мы четко указали, что 1 дисплей = 48 штук, программа все равно будет «округлять» количество мест в накладной, если введенное количество штук не делится нацело на 48.
Для решения этой проблемы, к сожалению, чаще всего требуется модификация типовой конфигурации 1С:УТ, так как стандартные настройки не позволяют достичь желаемого поведения. Мы рассмотрим несколько подходов, начиная с наиболее эффективного и рекомендованного.
Этот подход является наиболее прямым и эффективным, поскольку он позволяет изменить поведение системы непосредственно в том месте, где происходит расчет и заполнение колонки «Мест» в документе Реализация товаров и услуг. Мы будем вмешиваться в алгоритм, который автоматически рассчитывает количество упаковок.
Мы изменим стандартный алгоритм, который заполняет поле КоличествоМест (или аналогичное) в табличной части документа. Наша цель — добавить проверку: если введенное количество товара в базовых единицах (штуках) не кратно коэффициенту упаковки (дисплея), то значение в колонке «Мест» должно быть установлено в 0 или оставаться пустым.
Выясняем, где происходит расчет: Прежде всего, нам необходимо найти, какой именно код отвечает за заполнение поля «Мест» (обычно это поле КоличествоМест) в табличной части Товары документа Реализация товаров и услуг. Чаще всего этот расчет происходит в модуле формы документа, в обработчике события ПриИзменении для колонки «Количество» или «КоличествоУпаковок» (если такая есть). Также это может быть вызвано из общего модуля, который обрабатывает логику документов.
РеализацияТоваровУслуг.Товары и ее колонками Количество, ЕдиницаИзмерения, Упаковка или КоличествоУпаковок. Ищите методы, которые пересчитывают одно количество в другое.Алгоритм внедрения проверки кратности: После того как мы локализовали нужный участок кода, мы внедрим в него нашу логику.
ЕдиницыИзмерения или регистре сведений НаборыУпаковок, связанных с номенклатурой.КоличествоМест в 0 или пустую ссылку на единицу измерения, чтобы оно не отображалось.КоличествоМест как Количество / КоэффициентУпаковки.Пример кода: Представим, что мы нашли подходящий обработчик. Ниже приведен пример псевдокода, который демонстрирует логику. Обратите внимание, что реальная реализация может отличаться в зависимости от конкретной версии УТ (например, УТ 11.4) и структуры метаданных.
// Этот код предполагает, что мы находимся в обработчике события,
// которое срабатывает при изменении количества товара в табличной части документа
// "Реализация товаров и услуг" или в функции, которую этот обработчик вызывает.
&НаСервере
Процедура ТоварыКоличествоПриИзменении(Элемент)
// Получаем текущую строку табличной части "Товары"
ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
// Проверяем, что номенклатура заполнена, чтобы избежать ошибок
Если ТекущаяСтрока.Номенклатура.Пустая() Тогда
Возврат;
КонецЕсли;
// Получаем Номенклатуру из текущей строки
Номенклатура = ТекущаяСтрока.Номенклатура;
// Определяем коэффициент упаковки ("дисплея") для данной номенклатуры.
// В УТ 11, информация об упаковках обычно хранится в регистре сведений "НаборыУпаковок"
// или в справочнике "ЕдиницыИзмерения" с указанием принадлежности к номенклатуре.
// Мы должны найти ту единицу измерения, которая соответствует понятию "дисплей" или "коробка"
// и ее коэффициент.
// Для примера, предположим, что у нас есть вспомогательная функция,
// которая возвращает коэффициент для "основной" упаковки, если она настроена для номенклатуры.
// Ищем коэффициент упаковки.
// Если в строке документа есть поле "ЕдиницаИзмеренияМест" или "Упаковка",
// и оно заполнено, берем коэффициент оттуда.
// В противном случае, ищем стандартную упаковку для номенклатуры (например, "Дисплей").
КоэффициентУпаковки = 1; // Значение по умолчанию
// Попытаемся получить коэффициент из поля "Упаковка" строки документа
// (в УТ 11.4 часто используется именно такой подход для удобства)
Если НЕ ТекущаяСтрока.Упаковка.Пустая() Тогда
КоэффициентУпаковки = ТекущаяСтрока.Упаковка.Коэффициент;
Иначе
// Если "Упаковка" не заполнена в строке, попробуем получить коэффициент
// из основной упаковки номенклатуры, если она настроена (например, "Дисплей").
// Это требует более сложного запроса или функции, которая найдет нужную упаковку
// в справочнике "ЕдиницыИзмерения" или регистре "НаборыУпаковок".
// Для простоты примера, мы можем вызвать функцию, которая ищет упаковку по имени.
// Например, ищем упаковку с наименованием "Дисплей" для данной номенклатуры.
ЕдиницаИзмеренияДисплей = ПолучитьЕдиницуИзмеренияУпаковкиПоНаименованию(Номенклатура, "Дисплей");
Если НЕ ЕдиницаИзмеренияДисплей.Пустая() Тогда
КоэффициентУпаковки = ЕдиницаИзмеренияДисплей.Коэффициент;
КонецЕсли;
КонецЕсли;
// Избегаем деления на ноль, если коэффициент равен 0 или не найден
Если КоэффициентУпаковки = 0 Тогда
КоэффициентУпаковки = 1;
КонецЕсли;
// Получаем количество в базовых единицах (штуках) из текущей строки
КоличествоШтук = ТекущаяСтрока.Количество;
// Выполняем проверку кратности.
// Если остаток от деления КоличествоШтук на КоэффициентУпаковки не равен 0,
// значит, количество не кратно полной упаковке.
Если КоличествоШтук % КоэффициентУпаковки <> 0 Тогда
// Если количество не кратно, устанавливаем количество мест в 0
ТекущаяСтрока.КоличествоМест = 0;
// Также можно очистить поле "ЕдиницаИзмеренияМест" или "Упаковка",
// чтобы оно не отображалось, если неполная упаковка.
// ТекущаяСтрока.ЕдиницаИзмеренияМест = Справочники.ЕдиницыИзмерения.ПустаяСсылка();
// ТекущаяСтрока.Упаковка = Справочники.Упаковки.ПустаяСсылка(); // Если используется справочник Упаковки
Иначе
// Если количество кратно, рассчитываем количество мест стандартным образом
// и убеждаемся, что единица измерения мест установлена корректно.
ТекущаяСтрока.КоличествоМест = КоличествоШтук / КоэффициентУпаковки;
// Если мы ранее очищали "Упаковка", теперь восстановим ее
Если ТекущаяСтрока.Упаковка.Пустая() И НЕ ЕдиницаИзмеренияДисплей.Пустая() Тогда
ТекущаяСтрока.Упаковка = ЕдиницаИзмеренияДисплей;
// Или ЕдиницаИзмеренияМест, если это другое поле
// ТекущаяСтрока.ЕдиницаИзмеренияМест = ЕдиницаИзмеренияДисплей;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
// Вспомогательная функция для поиска единицы измерения упаковки по наименованию.
// Это упрощенный пример, в реальной УТ может потребоваться более сложный запрос
// к регистру сведений "НаборыУпаковок" или использование методов БСП (Библиотеки Стандартных Подсистем).
&НаСервере
Функция ПолучитьЕдиницуИзмеренияУпаковкиПоНаименованию(Номенклатура, НаименованиеУпаковки)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ЕдиницыИзмерения.Ссылка,
| ЕдиницыИзмерения.Коэффициент
|ИЗ
| Справочник.ЕдиницыИзмерения КАК ЕдиницыИзмерения
|ГДЕ
| ЕдиницыИзмерения.Владелец = &Номенклатура
| И ЕдиницыИзмерения.Наименование = &НаименованиеУпаковки";
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
Запрос.УстановитьПараметр("НаименованиеУпаковки", НаименованиеУпаковки);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Ссылка;
Иначе
Возврат Справочники.ЕдиницыИзмерения.ПустаяСсылка();
КонецЕсли;
КонецФункции
Важные моменты при доработке:
КоличествоМест, Упаковка, ЕдиницаИзмеренияМест) могут незначительно отличаться в разных версиях УТ. Вам понадобится проанализировать конкретную структуру вашего документа.Если цель состоит в том, чтобы кладовщик получал максимально точную и недвусмысленную информацию для сборки заказа, но при этом мы хотим минимизировать изменения в самом документе Реализация товаров и услуг, можно использовать механизм «Заданий на отбор».
Вместо того чтобы изменять логику непосредственно в расходной накладной, мы создаем или модифицируем документ Задание на отбор (или аналогичный документ управления складом), который формируется на основе расходной накладной. В этом документе мы можем вывести информацию о количестве товара в удобном для кладовщика виде.
Гибкость вывода информации: В документе Задание на отбор или в его печатной форме мы можем программно разделить общее количество товара на две отдельные колонки: «Целые дисплеи» и «Остаток в штуках».
Например, для 440 штук будет выведено: «Целые дисплеи: 9», «Остаток в штуках: 8». Это гораздо нагляднее, чем «10 дисплеев» или «1 дисплей» при неполной отгрузке.
Минимум изменений в типовой конфигурации: Для реализации такого подхода достаточно будет изменить (или создать новую) печатную форму для Задания на отбор, не затрагивая сложную логику документа Реализация товаров и услуг.
Ориентированность на процесс: Этот подход хорошо вписывается в процессы современного склада, где кладовщик работает не с первичным документом реализации, а со специальными документами по сборке.
Создание или модификация печатной формы: Откройте конфигуратор, найдите документ Задание на отбор и его макеты печатных форм. Если стандартный макет не подходит, создайте новый.
Программный расчет: В коде, отвечающем за формирование печатной формы Задания на отбор, мы будем рассчитывать целую часть и остаток для каждой позиции товара. Для этого нам понадобится знать общее количество товара в базовых единицах и коэффициент упаковки (например, 48 штук для одного дисплея).
// Пример логики расчета в модуле вывода печатной формы или отчета
// Предположим, у нас есть переменные:
// КоличествоШтук - общее количество товара в базовых единицах
// КоэффициентУпаковки - количество базовых единиц в одной упаковке (например, 48 для дисплея)
Если КоэффициентУпаковки > 0 Тогда
// Рассчитываем количество целых упаковок
ЦелыеУпаковки = Цел(КоличествоШтук / КоэффициентУпаковки);
// Рассчитываем остаток в базовых единицах
ОстатокБазовыхЕдиниц = КоличествоШтук % КоэффициентУпаковки;
Иначе
// Если коэффициент равен 0, считаем, что упаковок нет или он равен 1
ЦелыеУпаковки = 0;
ОстатокБазовыхЕдиниц = КоличествоШтук;
КонецЕсли;
// В печатной форме можно выводить это так:
// Если ЦелыеУпаковки > 0 Тогда
// Область.Параметры.ТекстЦелыхУпаковок = Строка(ЦелыеУпаковки) + " дисп.";
// Иначе
// Область.Параметры.ТекстЦелыхУпаковок = "";
// КонецЕсли;
// Если ОстатокБазовыхЕдиниц > 0 Тогда
// Область.Параметры.ТекстОстатка = Строка(ОстатокБазовыхЕдиниц) + " шт.";
// Иначе
// Область.Параметры.ТекстОстатка = "";
// КонецЕсли;
// Или комбинировать в одну строку
// Если ЦелыеУпаковки > 0 И ОстатокБазовыхЕдиниц > 0 Тогда
// Область.Параметры.КоличествоДляОтбора = Строка(ЦелыеУпаковки) + " дисп. и " + Строка(ОстатокБазовыхЕдиниц) + " шт.";
// ИначеЕсли ЦелыеУпаковки > 0 Тогда
// Область.Параметры.КоличествоДляОтбора = Строка(ЦелыеУпаковки) + " дисп.";
// ИначеЕсли ОстатокБазовыхЕдиниц > 0 Тогда
// Область.Параметры.КоличествоДляОтбора = Строка(ОстатокБазовыхЕдиниц) + " шт.";
// Иначе
// Область.Параметры.КоличествоДляОтбора = "";
// КонецЕсли;
Такой подход позволяет точно информировать кладовщика, не затрагивая логику основного документа реализации, что делает его более безопасным с точки зрения обновлений.
Теоретически, можно было бы вводить товар в документ Реализация товаров и услуг двумя отдельными строками: одна для целых упаковок, другая для остатка в штуках. Например, для 440 штук это выглядело бы так:
Однако, как справедливо отметил пользователь в нашем обсуждении (сообщение 15), 1С:УТ имеет встроенный механизм объединения строк. Если товар идентичен (одна и та же номенклатура, характеристики, серии и т.д.), программа попытается объединить эти две строки в одну. Это приведет нас обратно к исходной проблеме округления, так как общее количество снова будет объединено, и колонка «Мест» снова будет округлена.
Для реализации этого подхода потребовалась бы отдельная, довольно сложная доработка, чтобы программно запретить объединение строк для определенных условий, или чтобы система автоматически разделяла введенное количество на целые упаковки и остатки при заполнении табличной части. Это делает данный подход менее привлекательным, чем прямая доработка логики заполнения колонки «Мест».
Если проблема носит исключительно визуальный характер и заключается только в том, что на бумажной печатной форме расходной накладной отображается некорректное количество мест, то можно ограничиться изменением только печатной формы.
Этот подход не меняет внутреннюю логику документа или его данные, а лишь корректирует то, как эти данные выводятся на печать.
Данный подход подходит, если:
Открытие макета печатной формы: В конфигураторе откройте документ РеализацияТоваровУслуг, затем перейдите к его макетам печатных форм. Выберите тот макет, который используется для печати расходной накладной.
Изменение формулы вывода: В макете печатной формы найдите область, которая выводит поле «КоличествоМест». Измените формулу или выражение, которое используется для вывода этого поля. В этой формуле вы сможете добавить условие, которое проверяет кратность количества товара коэффициенту упаковки. Если количество не кратно, вы можете вывести пустое значение или ноль.
// Пример выражения в макете печатной формы (зависит от синтаксиса макетов)
// Представьте, что у вас есть параметр "Количество" и "КоэффициентУпаковки"
// Пример 1: Вывести ноль, если не кратно
// Выбор Когда [Количество] % [КоэффициентУпаковки] <> 0 Тогда 0 Иначе [Количество] / [КоэффициентУпаковки] Конец
// Пример 2: Вывести пустую строку, если не кратно (визуально выглядит как пустое поле)
// Выбор Когда [Количество] % [КоэффициентУпаковки] <> 0 Тогда "" Иначе Формат([Количество] / [КоэффициентУпаковки], "ЧЦ=0") Конец
// Где [Количество] - это параметр, передаваемый в макет,
// а [КоэффициентУпаковки] - это также параметр, который нужно будет рассчитать
// в модуле команды печати и передать в макет.
Для этого вам потребуется либо заранее рассчитать коэффициент упаковки в модуле, который формирует печатную форму, и передать его в макет как параметр, либо получить его непосредственно в выражении макета, если это позволяет синтаксис (например, через свойства объекта или связанные данные).
Этот подход наименее инвазивный, но он решает проблему только на уровне печати, не затрагивая внутренние данные и логику документа в самой системе 1С.
Мы рассмотрели распространенную проблему некорректного округления количества мест в расходной накладной 1С:Управление Торговлей 8.3 и предложили различные пути ее решения. Наиболее эффективным и комплексным решением является программная доработка логики заполнения табличной части документа Реализация товаров и услуг. Этот метод позволяет добиться желаемого поведения – пустого поля «Мест» при некратном количестве товара – непосредственно в системе, влияя на данные документа.
Альтернативные подходы, такие как использование Заданий на отбор или изменение только печатной формы, могут быть полезны в определенных сценариях, особенно если необходимо минимизировать изменения в типовой конфигурации. Однако они не решают проблему некорректных данных в самом документе. Метод с разделением строк в документе, хоть и кажется логичным, оказывается неэффективным из-за механизма объединения строк в 1С:УТ.
Мы рекомендуем обращаться к опытным специалистам по 1С для реализации программных доработок. Это позволит вам получить решение, которое будет не только функциональным, но и устойчивым к будущим обновлениям конфигурации, например, через использование механизма расширений.