gifts2017

Основы реализации подборов в 1С 8.2 для начинающих

Опубликовал Алексей (1C_tradeomsk) в раздел Программирование - Практика программирования

Основные механизмы реализации подборов в 1С  для начинающих

ОПЫТ ПРАКТИЧЕСКОЙ РЕАЛИЗАЦИИ ПОДБОРОВ в 1С 8.2

Итак, предыстория. Для одной копании торгующей кабелем и электротехникой понадобилось реализовать учёт остатков и резервов кабеля в разрезе определенных свойств в конфигурации УТ (11.0.6.7 - на управляемых формах) с минимальными доработками и за минимальные деньги.

Нужно сделать отступление. Это задача уже решалась в вначале в «1С 7.7 - Торговле», а потом в «1С 8.0 - Управлении Торговлей». Тогда выяснилось, что в силу целого ряда причин, о которых мы не будем здесь говорить штатные средства системы не позволяют это реализовать (так чтобы это было удобно). Как оказалось ситуация в современной конфигурации «Управление торговлей» практически не изменилась.

Во время реализации этой задачи встал вопрос о том, как организовать подборы по остаткам и резервам кабеля из документа «Распоряжение на склад».

 

общий интерфейс 

 

1) Создание команды.

В окне редактирования формы, создаём новую команду. 

Размещаем её на форме в её командной панели и затем в свойствах команды:

- создаём процедуру в свойствах команды;

- настраиваем имя команды и картинку, которая будет отображаться рядом с ней. 

 

 этапы создания команды на форме

 

2) Заполняем созданную процедуру исходным кодом.

 

&НаКлиенте
Процедура Подбор(Команда)

//Фильтр_Номенклатура = Вернуть_СписокНоменклатуры(Объект.Основание);
//АдресХранилища = ПоместитьВоВременноеХранилище(Фильтр_Номенклатура, ЭтаФорма.УникальныйИдентификатор);
АдресХранилища = "";

ОткрытьФорму("ОбщаяФорма.я_ПодборКабеля", Новый Структура("Основание,Склад,ЗакрыватьПриВыборе,АдресТов", Объект.Основание, Объект.Склад, Ложь, АдресХранилища), Элементы.Кабель);

КонецПроцедуры

 

------------------------------------------------------------------------------------------------- 

 

С помощью функции ОткрытьФорму() открываем специально созданную для подборов форму, в ней с помощью структуры передаём ряд важных параметров:

ЗакрыватьПриВыборе = Ложь - этот параметр позволит организовывать множественный выбор в открываемой форме

Элементы.Кабель - наша табличная часть, куда будут передаваться подобранные данные.

Остальные параметры используются для накладывания фильтров в открываемой форме.

Комментарий.

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

Затем на форме документа создаём процедуру обработки подбора в документ.

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

 

 процедура клиента - Обработка выбора

 

&НаКлиенте
Процедура КабельОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)

Если
ТипЗнч(ВыбранноеЗначение) = Тип("Структура")
Тогда



Если
ВыбранноеЗначение.Количество = 0
Тогда
Возврат;
КонецЕсли;



var_Флаг = Истина;
// -------------------
Для каждого стр из Объект.Кабель
Цикл

Если (
стр.Номенклатура = ВыбранноеЗначение.Номенклатура) и
(
стр.Тара = ВыбранноеЗначение.Тара)
Тогда
стр.Кол = стр.Кол + ВыбранноеЗначение.Количество;
Сообщить("Подбор ("+ВыбранноеЗначение.Количество+") "+ВыбранноеЗначение.Номенклатура + " был добавлен в строку № "+стр.НомерСтроки);
var_Флаг = Ложь;

Прервать;
КонецЕсли;
КонецЦикла;
// -------------------
Если var_Флаг
Тогда

НоваяСтрока = Объект.Кабель.Добавить();
НоваяСтрока.Номенклатура = ВыбранноеЗначение.Номенклатура;
НоваяСтрока.Тара = ВыбранноеЗначение.Тара;
НоваяСтрока.Кол = ВыбранноеЗначение.Количество;
// -------------------
Сообщить("В документ добавлено: "+НоваяСтрока.Номенклатура+" ("+НоваяСтрока.Тара+") в кол - " + НоваяСтрока.Кол + " м.");
КонецЕсли;
// -------------------
ЭтаФорма.Модифицированность = Истина;
КонецЕсли;



КонецПроцедуры

 

 

3)      Создаём общую форму

 Создаём именно общую форму, например для того, чтобы подбор можно было вызывать из разных документов (например, ещё из документов резервов).

 

создание общей формы - для подборов

 

Красиво размещаем элементы на форме (с помощью групп). Размещаем на форме две кнопки «Отобрать» и «Закрыть» и настраиваем запрос в свойствах объекта «Динамический список».

 

 настройка

 

Текст запроса по остаткам и резервам кабеля: 

 

ВЫБРАТЬ
Таблица_Сводная.Владелец,
Таблица_Сводная.Код,
Таблица_Сводная.Вид,
Таблица_Сводная.Номер,
Таблица_Сводная.Номер_Длины,
Таблица_Сводная.Метраж,
Таблица_Сводная.Вес,
Таблица_Сводная.Цвет,
Таблица_Сводная.Тара,
Таблица_Сводная.Поставщик,
Таблица_Сводная.Документ_Прихода,
Таблица_Сводная.Остаток,
Таблица_Сводная.Резерв,
Таблица_Сводная.Ссылка,
Таблица_Сводная.Остаток_Свободный

ИЗ

(
ВЫБРАТЬ
я_Кабель.Владелец КАК Владелец,
я_Кабель.Код КАК Код,
я_Кабель.Вид КАК Вид,
я_Кабель.Номер КАК Номер,
я_Кабель.Номер_Длины КАК Номер_Длины,
я_Кабель.Метраж КАК Метраж,
я_Кабель.Вес КАК Вес,
я_Кабель.Цвет КАК Цвет,
я_Кабель.Тара КАК Тара,
я_Кабель.Поставщик КАК Поставщик,
я_Кабель.Документ_Прихода КАК Документ_Прихода,
ЕСТЬNULL(Остатки_КПП.МетражОстаток, 0) КАК Остаток,
ЕСТЬNULL(Резервы_КПП.МетражОстаток, 0) КАК Резерв,
я_Кабель.Ссылка КАК Ссылка,
ЕСТЬNULL(Остатки_КПП.МетражОстаток, 0) - ЕСТЬNULL(Резервы_КПП.МетражОстаток, 0) КАК Остаток_Свободный

ИЗ
Справочник.я_Кабель КАК я_Кабель


ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.я_Кабель_Остатки.Остатки(, Склад = &Фильтр_Склад) КАК Остатки_КПП
ПО (Остатки_КПП.Тара = я_Кабель.Ссылка)

ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.я_Кабель_Резервы.Остатки(, ) КАК Резервы_КПП
ПО (Резервы_КПП.Тара = я_Кабель.Ссылка)

ГДЕ
я_Кабель.ПометкаУдаления = ЛОЖЬ
И
я_Кабель.Владелец В(&Фильтр_Номенклатура)) КАК Таблица_Сводная

ГДЕ
Таблица_Сводная.Остаток_Свободный > 0

 

Для того чтобы выделить среди других (раскрасим в желтый) главную для нас колонку свободного остатка мы настраиваем оформление колонки на форме.

 

настройка оформления 

 

 

4)      Создаём процедуры модуля формы подбора.

Алгоритм здесь такой. При открытии формы заполняются реквизиты формы, и запускается процедура отбора по запросу. Перед отбором по запросу, текст его корректируется в зависимости от заполненных на поле фильтров. При нажатии на клавишу «Отбор» происходит всё тоже самое, но без заполнения  реквизитов.

 

&НаСервере
Процедура Установить_Отбор()

var_ТЗ = Новый ТаблицаЗначений;
var_ТЗ = var_Основание.Товары.Выгрузить();
var_ТЗ.Свернуть("Номенклатура");

Фильтр_Номенклатура = var_ТЗ.ВыгрузитьКолонку("Номенклатура");
// -----------------------------
Тара.ТекстЗапроса =

"ВЫБРАТЬ
| Таблица_Сводная.Владелец,
| Таблица_Сводная.Код,
| Таблица_Сводная.Вид,
| Таблица_Сводная.Номер,
| Таблица_Сводная.Номер_Длины,
| Таблица_Сводная.Метраж,
| Таблица_Сводная.Вес,
| Таблица_Сводная.Цвет,
| Таблица_Сводная.Тара,
| Таблица_Сводная.Поставщик,
| Таблица_Сводная.Документ_Прихода,
| Таблица_Сводная.Остаток,
| Таблица_Сводная.Резерв,
| Таблица_Сводная.Ссылка,
| Таблица_Сводная.Остаток_Свободный
|ИЗ
| (ВЫБРАТЬ
| я_Кабель.Владелец КАК Владелец,
| я_Кабель.Код КАК Код,
| я_Кабель.Вид КАК Вид,
| я_Кабель.Номер КАК Номер,
| я_Кабель.Номер_Длины КАК Номер_Длины,
| я_Кабель.Метраж КАК Метраж,
| я_Кабель.Вес КАК Вес,
| я_Кабель.Цвет КАК Цвет,
| я_Кабель.Тара КАК Тара,
| я_Кабель.Поставщик КАК Поставщик,
| я_Кабель.Документ_Прихода КАК Документ_Прихода,
| ЕСТЬNULL(Остатки_КПП.МетражОстаток, 0) КАК Остаток,
| ЕСТЬNULL(Резервы_КПП.МетражОстаток, 0) КАК Резерв,
| я_Кабель.Ссылка КАК Ссылка,
| ЕСТЬNULL(Остатки_КПП.МетражОстаток, 0) - ЕСТЬNULL(Резервы_КПП.МетражОстаток, 0) КАК Остаток_Свободный
| ИЗ
| Справочник.я_Кабель КАК я_Кабель
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.я_Кабель_Остатки.Остатки(, ) КАК Остатки_КПП
| ПО (Остатки_КПП.Тара = я_Кабель.Ссылка)
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.я_Кабель_Резервы.Остатки(, ) КАК Резервы_КПП
| ПО (Резервы_КПП.Тара = я_Кабель.Ссылка)
| ГДЕ
| я_Кабель.ПометкаУдаления = ЛОЖЬ
| И я_Кабель.Владелец В(&Фильтр_Номенклатура)) КАК Таблица_Сводная"
;
//|ГДЕ
//| Таблица_Сводная.Остаток_Свободный > 0";



var_Строка_Фильтр = "";
// -----------------------------
Если ЗначениеЗаполнено(Фильтр_Вид) Тогда

var_Строка_Фильтр = var_Строка_Фильтр + "И (я_Кабель.Вид = &Фильтр_Вид) ";

КонецЕсли;

Если
ЗначениеЗаполнено(Фильтр_Цвет) Тогда
var_Строка_Фильтр = var_Строка_Фильтр + "И (я_Кабель.Цвет = &Фильтр_Цвет) ";
КонецЕсли;

Если
ЗначениеЗаполнено(Фильтр_Тара) Тогда
var_Строка_Фильтр = var_Строка_Фильтр + "И (я_Кабель.Тара = &Фильтр_Тара) ";
КонецЕсли;
// -----------------------------
Если ЗначениеЗаполнено(var_Строка_Фильтр) Тогда
Тара.ТекстЗапроса = СтрЗаменить(Тара.ТекстЗапроса,"В(&Фильтр_Номенклатура)", "В(&Фильтр_Номенклатура) "+var_Строка_Фильтр);
КонецЕсли;







Тара.ПроизвольныйЗапрос = Истина;
// -----------------------------
Если ЗначениеЗаполнено(Фильтр_Склад) Тогда
Тара.ТекстЗапроса = СтрЗаменить(Тара.ТекстЗапроса,".я_Кабель_Остатки.Остатки(, )", ".я_Кабель_Остатки.Остатки(, Склад = &Фильтр_Склад)");
Тара.Параметры.УстановитьЗначениеПараметра("Фильтр_Склад", Фильтр_Склад);
Иначе
Тара.ТекстЗапроса = СтрЗаменить(Тара.ТекстЗапроса,"Склад = &Фильтр_Склад", "");
КонецЕсли;

// -----------------------------

Тара.Параметры.УстановитьЗначениеПараметра("Фильтр_Номенклатура", Фильтр_Номенклатура);









Если
ЗначениеЗаполнено(Фильтр_Вид) Тогда
Тара.Параметры.УстановитьЗначениеПараметра("Фильтр_Вид", Фильтр_Вид);
КонецЕсли;

Если
ЗначениеЗаполнено(Фильтр_Цвет) Тогда
Тара.Параметры.УстановитьЗначениеПараметра("Фильтр_Цвет", Фильтр_Цвет);
КонецЕсли;

Если
ЗначениеЗаполнено(Фильтр_Тара) Тогда
Тара.Параметры.УстановитьЗначениеПараметра("Фильтр_Тара", Фильтр_Тара);
КонецЕсли;

// -----------------------------
Элементы.Тара.Обновить();

КонецПроцедуры







&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

//Сообщить(Параметры.Основание);
// ------------------------------
var_Основание = Параметры.Основание;
Фильтр_Склад = Параметры.Склад;
// ------------------------------
var_Адрес = Параметры.АдресТов;

//Фильтр_Номенклатура = Новый СписокЗначений;
//Фильтр_Номенклатура.ЗагрузитьЗначения(ПолучитьИзВременногоХранилища(var_Адрес));
//Фильтр_Номенклатура = ПолучитьИзВременногоХранилища(var_Адрес);

Установить_Отбор();


КонецПроцедуры



&НаКлиенте
Процедура Отобрать(Команда)

Установить_Отбор();

КонецПроцедуры




&НаКлиенте
Процедура ТараВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)

Перем
Количество;

СтандартнаяОбработка = Ложь;
Количество = Элемент.ТекущиеДанные.Остаток_Свободный;
// --------------------------------
Если ВвестиЗначение(Количество, "Введите количество поступления", Новый ОписаниеТипов("Число"))
Тогда
парам_Номен = Элемент.ТекущиеДанные.Владелец;
парам_Тара = Элемент.ТекущиеДанные.Ссылка;
Элемент.ТекущиеДанные.Остаток_Свободный = Элемент.ТекущиеДанные.Остаток_Свободный - Количество;
ЭтаФорма.ОбновитьОтображениеДанных();
// -----------------------------------
ОповеститьОВыборе( Новый Структура("Номенклатура,Тара,Количество", парам_Номен,парам_Тара,Количество ));
КонецЕсли;

КонецПроцедуры



&НаКлиенте
Процедура ПередЗакрытием(Отказ, СтандартнаяОбработка)
// УдалитьИзВременногоХранилища(var_Адрес);
КонецПроцедуры



 

НЕДОСТАТОК ПРИВЕДЕННОГО КОДА

 

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

 

var_ТЗ = var_Основание.Товары.Выгрузить();

 

Путь, который ни к чему не приведет. Сформировать в документе список значений, записать его во временное хранилище и в форме многократно его загружать из хранилища.

Первый недостаток - этого решения заключается в том, что значение из хранилища можно загрузить только один раз! Второй, в том что операция чтения из хранилища представляет собой физическую операцию чтения, в отличие от параметров формы располагающихся в оперативной памяти ПК, т.е. выполняется медленно.

 

Правильный путь № 1. Создать параметр формы типа «список значений» и каждый раз перед использованием преобразовывать его в массив и фильтровать по нему в запросе. При этом если в запрос подставить не массив, а «список значений», то запрос сработает только по первому параметру «списка значений».

 

Правильный путь № 2. Создать общий модуль с настройкой «Повторное использование возвращаемых значений» = «на время вызова», тогда возвращаемые значения экспортных функций повторно будут использоваться в разрезе входных значений их параметров.

 

 5)      Возможные варианты повышения «юзабилити»

 

Наглядность.

 

Можно создать на форме ещё один объект (например, ТаблицаЗначений) для наглядности хранения уже выбранных нами позиций.

 

В нем при открытии формы заполнять список уже добавленными в документ строками. Тогда при нажатии на клавишу «Выполнить» мы будем передавать в наш документ массив с выбранными нами значениями, которым мы будем перезаполнять табличную часть документа.

 

Множественный выбор.

 

Если в форму подбора открываемую функцией ОткрытьФорму() передать параметр «МножественныйВыбор» = «Истина», то в форме подбора станет возможным выбирать сразу несколько строк для добавления в документ. Для нас программистов это изменит только, то что теперь параметр выбора будет представлять собой ни строку, а массив строк который нужно обрабатывать в цикле Для каждого ... из ... Цикл.

 

Потеря владельца.

 

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

 

 настройка доступности окна-владельца

 

 

6) НЮАНСЫ, на которые стоит обратить внимание.



Повторный подбор одного и того же товара.

Представим следующую ситуацию. Вы подобрали в документ некий товар, потом решили, что мало и решили подобрать ещё ту же номенклатуру. Логично, что не стоит размножать строки с одинаковым товаром в документе. Поэтому перед добавлением строки в таблицу выбора надо проверить, а есть ли там уже строка с выбранным товаром? Если есть, то добавим туда выбранное количество. Если нет, добавим строку.

В моём варианте это делается в процедуре обработки выбора табличной части документа.

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

Например, так:

 

Для каждого СтрокаТоваров из ВыбранныеТовары Цикл
    Поиск = Новый Структура(«Товар», Товар);
    МассивНайденныхСтрок = ТЧ_Документа.НайтиСтроки(Поиск);

    Если
МассивНайденныхСтрок.Количество() > 0 Тогда
         Строка = МассивНайденныхСтрок [0];
    Иначе
         Строка = ТЧ_Документа.Добавить();
         Строка.Товар = Товар;
    КонецЕcли;
КонецЦикла;



Переотбор по фильтрам.

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





Надеюсь, этот материал был Вам полезен.

С уважением, Кутанов Алексей  

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Fomix (fomix) 23.12.11 10:04
Молодец! Очень подробно и наглядно рассказал. Спасибо и +
2. Юрий Зайцев (Yury1001) 23.12.11 10:07
Нормальная тема, сам хотел выложить Подбор для Списания товаров в УТ 11, теперь не нужно+
3. Vladimir (Boroda) 27.12.11 21:09
Спасибо за интересную и познавательную статью. Узнал много нового.
4. Игорь Юртаев (ipyu) 10.01.12 23:35
5. Сергей Сытько (8SiriuS8) 11.01.12 00:00
Молодец. Молоток. Развивай тему
6. Дмитрий Титов (dtitov) 11.01.12 14:47
Спасибо за статью, интересно.
7. Сергей Жестовский (post279) 25.01.12 18:33
8. Андрей Андреев (Andrey12Andrey) 20.02.12 11:09
9. Иван Василишин (Notorius) 20.02.12 11:12
10. Andrey Gerasynik (neo2012) 27.03.12 10:50
Как на мое мнение все написано доходчиво и понятно все что хотел понял поетому автору респект 5+ заслуженое
11. Дмитрий (KneZ) 31.08.12 01:43
Как раз вовремя попалась статья на глаза, спасибо
12. элла иванова (2011b11) 13.12.12 12:35
Спасибо автору за подробное разъяснение, все доходчево и понятно. Респект автору.
13. Дмитрий Марданов (ogion) 02.04.13 16:10
Хоть и написано: "для начинающих", но ничего не понятно, что за Объект??? ошибка на нём выскакивает.
14. serge_focus (serge_focus) 01.08.13 20:26
Спасибо автору и + за подробное и наглядное разъяснение вопроса.
15. Елена (Penka) 10.06.14 09:16
16. Илья Никифоров (Prince_1) 01.07.14 12:24
17. Алексей Кит (kitun) 12.11.15 14:49
18. Алексей Смирнов (plur) 22.09.16 12:22
Спасибо, очень доступно и полезно!
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа