В практической работе торговых компаний часто возникает задача жесткого контроля ценообразования. Руководство стремится исключить человеческий фактор, чтобы менеджеры по продажам не могли самостоятельно занижать цены, предоставлять несанкционированные скидки или выбирать пункт «Произвольная цена» непосредственно в документе Заказ клиента.
При этом многие пользователи конфигурации «1С:Управление торговлей 11» (а также родственных решений «1С:Комплексная автоматизация 2» и «1С:ERP Управление предприятием 2») сталкиваются с непонятным поведением системы: в договоре жестко прописан конкретный вид цены, у пользователя в профиле полномочий снята роль Отклонение от условий продаж, но менеджер все равно без труда может очистить вид цены, выбрав «Произвольная», и написать в поле «Цена» любую цифру.
Давайте подробно проанализируем ситуацию, выясним глубинную причину такого поведения архитектуры 1С и рассмотрим по шагам все возможные варианты решения этой проблемы — как стандартными средствами конфигурации, так и с помощью небольших программных доработок.
Для того чтобы понять, почему система ведет себя именно так, обратимся к архитектурной логике современных ERP-систем фирмы 1С. В этих прикладных решениях зоны ответственности между справочниками Договоры контрагентов и Соглашения с клиентами строго разделены:
Технически выбор «Произвольной цены» в табличной части заказа означает установку пустой ссылки в поле ВидЦены. Когда в программе отключено использование соглашений с клиентами, у системы исчезает эталон («правила игры»), с которым она могла бы сопоставить цену, введенную менеджером вручную. Так как эталона нет, проверка на отклонение от условий продаж при проведении документа просто не запускается. Следовательно, ограничение прав пользователя (отсутствие роли Отклонение от условий продаж) не имеет никакого эффекта.
Рассмотрим подробнее два принципиальных подхода к решению этой задачи.
---
Если мы хотим решить задачу исключительно стандартным функционалом 1С, без привлечения программистов и без внесения изменений в конфигурацию, нам потребуется задействовать механизм соглашений. При этом, чтобы не усложнять жизнь менеджерам заполнением лишней аналитики, мы можем настроить систему максимально прозрачно.
Разберем по шагам этот процесс:
Включение функциональной опции:
Перейдем в раздел НСИ и администрирование -> Настройка НСИ и разделов -> Продажи. В блоке Оптовые продажи установим флаг использования соглашений. Рекомендуется выбрать вариант «Типовые и индивидуальные соглашения» или хотя бы «Только типовые соглашения».
Создание единого типового соглашения:
Перейдем в раздел CRM и маркетинг -> Типовые соглашения с клиентами. Создадим одно общее соглашение (например, с наименованием «Основное соглашение оптовых продаж»), которое будет действовать для всех партнеров без исключения. В карточке соглашения:
Ограничение прав пользователей:
Перейдем в раздел НСИ и администрирование -> Настройки пользователей и прав -> Профили групп доступа. Откроем профиль, назначенный вашим менеджерам по продажам. Убедимся, что у данного профиля снята (отсутствует) роль Отклонение от условий продаж (в некоторых версиях она называется Самостоятельное отклонение от условий продаж).
Как это работает на практике: Теперь при создании заказа клиента менеджер по-прежнему физически сможет очистить поле вида цены или вручную отредактировать цену в табличной части. Однако при попытке провести документ в статусе К выполнению или Закрыт система автоматически сопоставит параметры документа с условиями нашего типового соглашения, обнаружит несоответствие и заблокирует проведение, выдав информационное сообщение: «Недостаточно прав для отклонения от условий продаж».
---
Если бизнес-процессы вашей организации категорически исключают использование соглашений, либо вы хотите сделать интерфейс более строгим (например, физически заблокировать менеджеру возможность изменять ячейку с ценой), единственным выходом будет разработка небольшого расширения конфигурации. Этот метод безопасен, так как сама база данных остается на стандартной поддержке 1С.
Рассмотрим три наиболее эффективных сценария реализации в расширении.
Этот способ наиболее дружелюбен к пользователю: менеджер сразу видит, что он не может изменить цену, так как ячейки недоступны для редактирования. Цены рассчитываются строго автоматически по виду цен, подтянутому из договора.
Для реализации добавим в расширение форму документа ЗаказКлиента и переопределим процедуру ПриСозданииНаСервере:
&После("ПриСозданииНаСервере")
Процедура Расш_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем, обладает ли пользователь правами администратора или спец. ролью
Если Не РольДоступна("ПолныеПрава") И Не РольДоступна("Расш_РазрешитьРедактированиеЦенВЗаказах") Тогда
// Делаем колонки цены, скидок и вида цен недоступными для редактирования
Элементы.ТоварыЦена.Доступность = Ложь;
Элементы.ТоварыВидЦены.Доступность = Ложь;
Элементы.ТоварыПроцентРучнойСкидки.Доступность = Ложь;
Элементы.ТоварыСуммаРучнойСкидки.Доступность = Ложь;
КонецЕсли;
КонецПроцедуры
Если нам нужно гарантировать, что ни при каких обстоятельствах (включая импорт заказов из внешних систем или использование мобильных приложений) незарегистрированная цена не попадет в систему, мы должны написать жесткую проверку непосредственно в модуле объекта документа ЗаказКлиента.
Добавим обработчик события ПередЗаписью в расширение модуля объекта документа:
&Перед("ПередЗаписью")
Процедура Расш_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Проверка актуальна только при непосредственном участии пользователя и проведении документа
Если ЭтотОбъект.ОбменДанными.Загрузка Или Не (РежимЗаписи = РежимЗаписиДокумента.Проведение) Тогда
Возврат;
КонецЕсли;
// Если у пользователя есть полные права, проверку пропускаем
Если РольДоступна("ПолныеПрава") Или РольДоступна("Расш_РазрешитьПроизвольныеЦены") Тогда
Возврат;
КонецЕсли;
Для Каждого СтрокаТЧ Из ЭтотОбъект.Товары Цикл
// 1. Проверяем, установлена ли произвольная цена (пустой вид цены)
Если Не ЗначениеЗаполнено(СтрокаТЧ.ВидЦены) Тогда
Отказ = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
"В строке № " + СтрокаТЧ.НомерСтроки + " не указан вид цены (установлена произвольная цена). Выберите разрешенный вид цены!",
ЭтотОбъект,
"Товары[" + (СтрокаТЧ.НомерСтроки - 1) + "].ВидЦены"
);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Мы также можем программно перехватить момент выбора вида цены в табличной части и удалить из выпадающего списка предопределенный элемент «Произвольная цена».
Для этого в форме документа переопределим событие ТоварыВидЦеныНачалоВыбораИзСписка:
&НаКлиенте
&Перед("ТоварыВидЦеныНачалоВыбораИзСписка")
Процедура Расш_ТоварыВидЦеныНачалоВыбораИзСписка(Элемент, СтандартнаяОбработка)
// Если пользователю запрещено использовать произвольные цены
Если Не ДоступноИспользованиеПроизвольныхЦенСервер() Тогда
// Формируем список выбора программно, исключая пустую ссылку (произвольную цену)
СтандартнаяОбработка = Ложь;
СписокВыбора = Новый СписокЗначений;
// Заполняем список только доступными видами цен из базы данных
ПолучитьДоступныеВидыЦенНаСервере(СписокВыбора);
Элемент.СписокВыбора = СписокВыбора;
КонецЕсли;
КонецПроцедуры
---
Выбор конкретного решения зависит от специфики автоматизации вашего предприятия: