Тестовое задание
Дано:
Есть склад, на котором реализована адресная система хранения.
Каждое место хранения маркируется 3-х значным индексом вида:
<SS><NN><LL>
Где, SS номер ряда стеллажей, NN – номер стойки в ряду стеллажей, LL уровень стеллажа.
На складе ведется только количественный учет, без суммового.
Хранение товаров на складе определяется следующими правилами:
- На каждом месте хранения одновременно может находиться только товар одного вида (один SKU).
- Каждому товару присуще свойство – коэффициент паллетирования, указывающий сколько единиц хранения товара составляет паллету.
- На одном месте хранения может храниться не более одной полной паллеты.
Задание:
Реализовать процессы склада, отвечающие следующим критериям:
|
|
|
|
|
|
Создать следующие отчеты:
|
|
|
|
|
|
Реализация похожа на ту, что в этой публикации //infostart.ru/1c/articles/556329/
Реализована конфигурация управления адресным складом., подход немного иной - через объект СкладскаяЯчейка, которая по сути есть паллета
1. Реализован алгоритм помещения на склад (размещения на паллете (складская ячейка)) произвольного количества некоего произвольного товара (генерируется автоматически случайным числом).
&НаСервере
Функция РазместитьТоварыПоЯчейкамСклада()
тз = Новый ТаблицаЗначений;
тз.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
тз.Колонки.Добавить("Ячейка", Новый ОписаниеТипов("СправочникСсылка.СкладскиеЯчейки"));
тз.Колонки.Добавить("КоличествоПриход", Новый ОписаниеТипов("Число",,, Новый КвалификаторыЧисла(5,0,ДопустимыйЗнак.Неотрицательный)));
тз.Колонки.Добавить("Прим", Новый ОписаниеТипов("Строка"));
тзТов = ЭтотОбъект.Товары.Выгрузить();
тзТов.Свернуть("Номенклатура","Количество");
// добавл. вспомогательную колонку для отслеживания распределения, пока не 0.
тзТов.Колонки.Добавить("КоличОстаток", Новый ОписаниеТипов("Число",,, Новый КвалификаторыЧисла(5,0,ДопустимыйЗнак.Неотрицательный)));
// список не задействованных или уже освободившихся ячеек
// вариант, когда ячейки создаются по мере их потребности., иначе - создасть полный набор заранее...
мПустЯч = ОбщНазнСерв.ПолучитьПустыеЯчейки(ЭтотОбъект.Дата);
тзЯчеекЕстьМесто = ОбщНазнСерв.ПолучитьЯчейкиТовараНедозаполненные(ЭтотОбъект.Дата, тзТов.ВыгрузитьКолонку("Номенклатура"));
для каждого стрИст из тзТов цикл
стрИст.КоличОстаток = стрИст.Количество;
если стрИст.Номенклатура.КоэфПалетирования = 0 Тогда
ВызватьИсключение "КоэфПалетирования = 0 в товаре " + стрИст.Номенклатура.Наименование;
Конецесли;
для каждого стрТ1 из тзЯчеекЕстьМесто.Скопировать(Новый Структура("Номенклатура", стрИст.Номенклатура)) цикл
новСтр = тз.Добавить();
новСтр.Ячейка = стрТ1.Ячейка;
новСтр.Номенклатура = стрИст.Номенклатура;
КоличествоМест = стрИст.Номенклатура.КоэфПалетирования - стрТ1.ВНаличииОстаток;
если КоличествоМест <= стрИст.КоличОстаток Тогда
новСтр.КоличествоПриход = КоличествоМест;
иначе
новСтр.КоличествоПриход = стрИст.КоличОстаток;
Конецесли;
новСтр.Прим = "add";
стрИст.КоличОстаток = стрИст.КоличОстаток - новСтр.КоличествоПриход;
если стрИст.КоличОстаток <= 0 Тогда // < 0 на случай ошибок
прервать;
КонецЕсли;
КонецЦикла;
если стрИст.КоличОстаток > 0 Тогда // остальное кол-во этого Товара нужно разместить в других ячейках (кратно коэф.парлет)
для счПя = -(мПустЯч.Количество()-1) по 0 цикл
новСтр = тз.Добавить();
новСтр.Ячейка = мПустЯч[-счПя];
новСтр.Номенклатура = стрИст.Номенклатура;
если стрИст.Номенклатура.КоэфПалетирования <= стрИст.КоличОстаток Тогда
новСтр.КоличествоПриход = стрИст.Номенклатура.КоэфПалетирования;
иначе
новСтр.КоличествоПриход = стрИст.КоличОстаток;
КонецЕсли;
мПустЯч.Удалить(-счПя);
новСтр.Прим = "неисп";
стрИст.КоличОстаток = стрИст.КоличОстаток - новСтр.КоличествоПриход;
если стрИст.КоличОстаток <= 0 Тогда // < 0 на случай ошибок
прервать;
КонецЕсли;
КонецЦикла
Конецесли;
если стрИст.КоличОстаток > 0 Тогда // остальное кол-во этого Товара нужно разместить уже только в новых ячейках (кратно коэф.парлет)
// упрощ. вариант, однако в некоторых случая при таком подходе будет создаваться +1 лишняя палета без движений по ней...
//мНовЯч = СоздатьНовуюЯчейкуСклада(1+(стрИст.КоличОстаток/стрИст.Номенклатура.КоэфПалетирования));
//создаем по одной:
пока (стрИст.КоличОстаток > 0) цикл
новСтр = тз.Добавить();
новСтр.Ячейка = ОбщНазнСерв.СоздатьНовуюЯчейкуСклада();
новСтр.Номенклатура = стрИст.Номенклатура;
если стрИст.Номенклатура.КоэфПалетирования <= стрИст.КоличОстаток Тогда
новСтр.КоличествоПриход = стрИст.Номенклатура.КоэфПалетирования;
иначе
новСтр.КоличествоПриход = стрИст.КоличОстаток;
КонецЕсли;
новСтр.Прим = "+нов";
стрИст.КоличОстаток = стрИст.КоличОстаток - новСтр.КоличествоПриход;
если стрИст.КоличОстаток <= 0 Тогда // < 0 на случай ошибок
прервать;
КонецЕсли;
КонецЦикла
Конецесли
КонецЦикла;
возврат тз;
КонецФункции
2. Регистр сведений АдресацияСкладскихЯчеек используется для обеспечения корректности (уникальности) адресации, а так же для блокировки ячеек от их одновременного изменения в соседнем процессе. Проверяющие посчитали это лишним., вопрос спорный., конечное решение за Вами.
по поводу реквизита блокировки - проблема в том, что расчет количеств которые записаны за ячейкой ведется по текущим данным регистра накопления, и есть вероятность, что соседний документ еще не успеет прочитать изменения регистра, и назначит на эти ячейки свое количество. Реквизит добавлен, но пока не использован., тк в задании не оговаривалось.
3. В целях тестирования добавлен документ списания, который позволяет списать единичные позиции с паллет, чтобы образовались "дырки", которые потом должен заполнить алгоритм поступления на склад. Однако, это явилось поводом снижения баллов (лишние метаданные)
Код его движений:
&НаСервере
Функция ПолучитьТоварыПоЯчейкамСклада()
тз = Новый ТаблицаЗначений;
тз.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
тз.Колонки.Добавить("Ячейка", Новый ОписаниеТипов("СправочникСсылка.СкладскиеЯчейки"));
тз.Колонки.Добавить("КоличествоРасход", Новый ОписаниеТипов("Число",,, Новый КвалификаторыЧисла(5,0,ДопустимыйЗнак.Неотрицательный)));
тзТов = ЭтотОбъект.Товары.Выгрузить();
тзТов.Свернуть("Номенклатура","Количество");
// добавл. вспомогательную колонку для отслеживания распределения, пока не 0.
тзТов.Колонки.Добавить("КоличОстаток", Новый ОписаниеТипов("Число",,, Новый КвалификаторыЧисла(5,0,ДопустимыйЗнак.Неотрицательный)));
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыВЯчейкахОстатки.Номенклатура КАК Номенклатура,
| ТоварыВЯчейкахОстатки.Ячейка КАК Ячейка,
| ТоварыВЯчейкахОстатки.ВНаличииОстаток КАК ВНаличииОстаток,
| 0 КАК Расход
|ИЗ
| РегистрНакопления.ТоварыВЯчейках.Остатки(&НаДату, Номенклатура В (&ТребНоменкл)) КАК ТоварыВЯчейкахОстатки
|
|УПОРЯДОЧИТЬ ПО
| ТоварыВЯчейкахОстатки.Ячейка.Код УБЫВ";
Запрос.УстановитьПараметр("НаДату", Дата);
Запрос.УстановитьПараметр("ТребНоменкл", тзТов.ВыгрузитьКолонку("Номенклатура"));
тзОстаткиПоЯчейкам = Запрос.Выполнить().Выгрузить();
для каждого стрПотреб из тзТов цикл
стрПотреб.КоличОстаток = стрПотреб.Количество;
мСтрНом = тзОстаткиПоЯчейкам.НайтиСтроки(Новый Структура("Номенклатура", стрПотреб.Номенклатура) );
для каждого стрТ1 из мСтрНом цикл
если стрТ1.ВНаличииОстаток >= стрПотреб.КоличОстаток Тогда
стрТ1.Расход = стрПотреб.КоличОстаток;
иначе
стрТ1.Расход = стрТ1.ВНаличииОстаток;
КонецЕсли;
стрПотреб.КоличОстаток = стрПотреб.КоличОстаток - стрТ1.Расход;
если стрПотреб.КоличОстаток <= 0 Тогда // < 0 на случай ошибок
прервать;
КонецЕсли;
КонецЦикла;
если стрПотреб.КоличОстаток > 0 Тогда // не хватает
ВызватьИсключение "Товара " + стрПотреб.Номенклатура.Наименование + " не хватило: " + Строка(стрПотреб.КоличОстаток);;
КонецЕсли;
КонецЦикла;
для каждого стр из тзОстаткиПоЯчейкам.НайтиСтроки(Новый Структура("Расход", 0)) цикл
тзОстаткиПоЯчейкам.Удалить(стр);
КонецЦикла;
возврат тзОстаткиПоЯчейкам;
КонецФункции
4. Инвентаризация
сделана лишь в части заполнения тч товары расчетными количеством по двум вариантам - по адресам или по товару свернуто.
в задании не описаны требования, соответственно, ввод факта, расчет расхождений и проведение НЕ ДЕЛАЛ.
5. Диаграмма сделана дважды. По тем датам, по которым были движения (что логично, тк в интервалах изменений нет), и по всем датам периода (что привело к расширению диаграммы столбиками одинаковой длины.
Реализована на СКД через соединение двух источников данных (запросов). один из который дает периоды а второй значений в эти периоды. Так проще, чем делать запрос с последовательным получением остатка на начало, соединять с оборотами за период.
Однако, есть мнение, что такой подход не оптимален.
Платформа 8.3.14.