вторник, 3 марта 2015 г.

1c специалист задача 1.24

Условие из сборника:
Компания занимается оптовой торговлей. Поступление товаров отражается документом «Приходная накладная», продажа - «Расходная накладная». Учет товаров ведется в разрезе складов. Каждый из складов имеет свой приоритет, который не меняется. При проведении расходной накладной необходимо в первую очередь контролировать хватает ли товара вообще. Если нет – выдавать соответствующее предупреждение с указанием количества нехватки и не позволять проводить документ. Списание себестоимости должно быть организовано по складам, в зависимости от текущего значения их приоритета и выбранного в документе склада. В первую очередь товар списывается со склада, указанного для данного товара в табличной части документа, далее со склада с минимальным приоритетом, потом со следующего склада с большим приоритетом и т.д. Пока не спишется все необходимое количество. Если склад не указан, то происходит списание со складов, согласно их приоритету. Себестоимость товаров рассчитывается как средняя по складу. Поступление товара происходит на один выбранный пользователем в документе «Приходная накладная» склад. Необходимо построить отчет по движениям товаров за период по количеству и сумме.
Решение:
1) Заведем справочник "Склады" и добавим реквизит этого справочника "Приоритет".
2) Отредактируем регистр "Остатки номенклатуры".
3) С помощью конструктора движений сформируем обработку проведения "Приходной накладной"
4) Переходим к "Расходной накладной".
Здесь потребуется составить довольно сложный запрос и его обработку.
В решении я учел возможность того что один товар может быть в нескольких строках.
Например:

В документе
Товар "А" кол= 2 склад не   заполнен.
Товар "А" кол =35 склад = "Запасной"склад не   заполнен.
Остатки
Товар "А" на складе "Запасной" =10.
Товар "А" на складе "Основной" =30.
Приоритеты: "Основной =1" , "Запасной=2"

В этом случае должно списаться
1) с основного 2 шт (так как склад основной имеет меньший приоритет)
2) с запасного 10 шт (так как выбран склад "запасной")
3 с основного 25 шт ( списываем оставшееся  требуемое количество учетом  приоритетов)


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



Процедура ОбработкаПроведения(Отказ, РежимПроведения)
//1 Очистка движений
Движения.ОстаткиНоменклатуры.Записывать = Истина;
Движения.ОстаткиНоменклатуры.Очистить();
Движения.ОстаткиНоменклатуры.Записать();


// Блокировка
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ОстаткиНоменклатуры");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.ИсточникДанных = СписокНоменклатуры;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Склад", "Склад");
Блокировка.Заблокировать(); 

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


Запрос.УстановитьПараметр("Ссылка",Ссылка);
Запрос.УстановитьПараметр("Период",Дата);
Если РежимПроведения = РежимПроведенияДокумента.Оперативный Тогда  
ТочкаИтогов=Неопределено;
Иначе
ТочкаИтогов = Новый Граница(МоментВремени(),ВидГраницы.Исключая);
КонецЕсли;
Запрос.УстановитьПараметр("ТочкаИтогов", ТочкаИтогов);
// Номенклатура
ВыборкаНоменлатура = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам,"Номенклатура");
Пока ВыборкаНоменлатура.Следующий() Цикл
Товар  = ВыборкаНоменлатура.Номенклатура;

Если ВыборкаНоменлатура.ОстатокВсего <ВыборкаНоменлатура.КолДок Тогда
Отказ = Истина;
Сообщение = Новый("СообщениеПользователю");
Сообщение.Текст ="Недостаточно товара "+ ВыборкаНоменлатура.Номенклатура +" надо еще " +(ВыборкаНоменлатура.колДок - ВыборкаНоменлатура.ОстатокВсего);
Сообщение.Сообщить();
Иначе
ВыборкаСклад = ВыборкаНоменлатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам,"ДокСклад");
Пока ВыборкаСклад.Следующий() Цикл
ТребуетсяСписать = ВыборкаСклад.КолДок;

// если склад заполнен, то спишем с него
Если ЗначениеЗаполнено(ВыборкаСклад.ДокСклад) Тогда
Выборка = ВыборкаСклад.Выбрать();
СтруктураПоиска = Новый Структура("Склад", ВыборкаСклад.ДокСклад);
Если Выборка.НайтиСледующий(СтруктураПоиска) И ТребуетсяСписать > 0 Тогда 
КоличествоКСписанию = Мин(ТребуетсяСписать, Выборка.ОстатокКол);
Движение = Движения.ОстаткиНоменклатуры.ДобавитьРасход();
Движение.Период = Дата;
Движение.Номенклатура = Товар;
Движение.Склад = Выборка.Склад;
Движение.Количество = КоличествоКСписанию;
Если ВыборкаСклад.ОстатокКол <> 0 Тогда 
Себестоимость= КоличествоКСписанию * Выборка.ОстатокСум/Выборка.ОстатокКол;
Иначе
Себестоимость =0;
КонецЕсли;
Движение.Сумма = Себестоимость;
ТребуетсяСписать = ТребуетсяСписать - КоличествоКСписанию;
КонецЕсли;

// списываем оставшееся количество
Если ТребуетсяСписать>0 Тогда 
СформироватьДвижение(ВыборкаСклад,ТребуетсяСписать);
КонецЕсли;
ИначеЕсли ТребуетсяСписать>0 Тогда 
СформироватьДвижение(ВыборкаСклад,ТребуетсяСписать);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;




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


Процедура СформироватьДвижение(ВыборкаСклад, ТребуетсяСписать)
Выборка = ВыборкаСклад.Выбрать();
Пока Выборка.Следующий() и ТребуетсяСписать > 0 Цикл
КоличествоКСписанию = Мин(ТребуетсяСписать, Выборка.ОстатокКол);

Движение = Движения.ОстаткиНоменклатуры.ДобавитьРасход();
Движение.Период = Дата;
Движение.Номенклатура = ВыборкаСклад.Номенклатура;
Движение.Склад = Выборка.Склад;
Движение.Количество = КоличествоКСписанию;
Если ВыборкаСклад.ОстатокКол <> 0 Тогда 
Себестоимость= КоличествоКСписанию * Выборка.ОстатокСум/Выборка.ОстатокКол;
Иначе
Себестоимость =0;
КонецЕсли;
Движение.Сумма = Себестоимость;
ТребуетсяСписать = ТребуетсяСписать - КоличествоКСписанию;
КонецЦикла;
КонецПроцедуры

5) Отчет аналогичен отчету из задачи 1.22


Скачать решение задачи 1.24



Комментариев нет:

Отправить комментарий