Тренинг по подготовке к аттестации.
Разбор задач 09, 10
Публикуем решения задач 9 “Интернет-магазин” и 10 “Пени”.
Предлагаю обсудить и покритиковать в комментариях мое решение ;)
К сожалению, у Вас недостаточно прав для просмотра этой записи. Если Вы еще не залогинены на сайте — залогиньтесь.
Если не активировали токен — посмотрите видео-инструкцию (видео N5)
Если вы залогинены, у Вас активирован токен доступа, но вы все равно видите эту запись — напишите нам на e-mail поддержки.
1. Расскажите пожалуйста, почему РС СостояниеСчета периодический?
Считтаю что можно было бы обойтись обычным.
2. В структура РН ЗадолженностьПоОплате
Вы добавили измерение Контрагент, хотел бы проконсультироваться
по этому поводу, т.к. довольно часто такая ситуация возникает на практике.
Плюсы и минусы Вы описали, объём базы или скорость запросов, но вот
что ещё меня немного тревожит, может это параноя. :)
При такой структуре регистра может сложиться следующая ситуация:
Измерение Контрагент — Вася, Измерение Счет — Счет № 3.
А реквизит Контрагент в Счете № 3 — Петя.
Всегда ведь есть документ Корректировка регистра, или Операция.
Насколько “весомы” мои опасения?
Может дополнительная проверка в модуле регистра не так уж страшна. :)
3. Разве пени “капитализируется”? Мне кажется пени начисляется только
на сумму основного долга, без накопившихся процентов.
Для решения, как вариант, в регистр ЗадолженностьПоОплате можно
добавить ещё один ресурс, СуммаПени. И при поступлении денег
погашать в первую очередь пени. Правда отчеты бы сложней пришлось
формировать.
Подскажите правильный вариант.
Простите за опечатки. Трудно набирать когда ваш волшебный плеер играет,
экран не прорисовывается. :)
А я и без плеера иногда умею здорово опечатываться :)
1. Можно было бы, но хотелось хранить историю изменения и менять состояние регистратором (дабы при отмене проведения возвращать в состояние “как было”).
2. Несоответствие счета контрагенту конечно возможно, но “защиту от дурака” я делать бы на сертификации не стал. Основной плюс контрагента я вижу в блокировках.
3. Судя по отчету: капитализируется и увеличивает долг контрагента.
Отправила отчеты по этой задаче на pavel@Spec8.ru
Хотелось бы посмотреть правильное решение :)
Я письмо получил, отвечу до субботы, сейчас негде базу развернуть.
Доработка Оперативного/НеОперативного проведения + Блокировки.
Документ «РегистрацияЗаказаКлиента».
Движения.СвободныеОстатки.БлокироватьДляИзменения = Истина;
…
Если Режим = РежимПроведенияДокумента.Оперативный Тогда
МоментИтогов = ‘00010101’;
Иначе
МоментИтогов = Новый Граница(МоментВремени(),ВидГраницы.Включая);
КонецЕсли;
Запрос.УстановитьПараметр(“МоментИтогов”,МоментИтогов);
Документ «ВыдачаЗаказов».
Запрос на получение данных разбил на два Запроса с подключением МенеджераВременныхТаблиц.
В первый Запрос добавлено поле Склад (ТочкаВыдачи) через параметр.
По результатам этого запроса устанавливается блокировка на Регистры ОстатковТоваров и СтоимостиТоваров.
Во второй Запрос добавлен параметр «МоментИтогов» для реализации Оперативного/НеОперативного проведения.
Движения.ОстаткиТоваров.Очистить();
Движения.СтоимостьТоваров.Очистить();
Если РежимПроведения = РежимПроведенияДокумента.Оперативный Тогда
Движения.ОстаткиТоваров.Записать();
Движения.СтоимостьТоваров.Записать();
МоментИтогов = ‘00010101’;
Иначе
МоментИтогов = Новый Граница(МоментВремени(), ВидГраницы.Исключая);
КонецЕсли;
Запрос.УстановитьПараметр(“МоментИтогов”, МоментИтогов);
БлокировкаДанных = Новый БлокировкаДанных;
ЭлементБлокировки = БлокировкаДанных.Добавить(“РегистрНакопления.ОстаткиТоваров”);
ЭлементБлокировки.ИсточникДанных = ДанныеДляБлокировки;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(“Склад”, “Склад”);
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(“Номенклатура”, “Номенклатура”);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки = БлокировкаДанных.Добавить(“РегистрНакопления.СтоимостьТоваров”);
ЭлементБлокировки.ИсточникДанных = ДанныеДляБлокировки;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(“Номенклатура”, “Номенклатура”);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
БлокировкаДанных.Заблокировать();
Создание Отчетов
С отчетами по Остаткам и по Продажам проблем не возникло.
А вот с отчетом по Заказам в пути было не просто.
Реализовал следующим образом:
Никаких изменений в структуру регистров вносить не стал.
В справочник Номенклатуры добавил два реквизита: Вес и Объем.
Список заказов в пути получаю из СрезаПоследних регистра сведений.
Присоединяю к нему данные табличной части Товары документа Заказов и сохраняю во временную таблицу.
Затем во временную таблицу получаю данные по остаткам и стоимости товаров.
В следующем запросе соединяю данные первой и второй временных таблиц и рассчитываю себестоимость.
Спасибо, Павел, за решение.
Есть несколько вопросов.
1. О выдаче товаров.
Нет проверки на наличие данного заказа именно в этой точке выдачи.
В таком случае товар может спокойно уйти в минус на одном складе и остаться в плюсе на другом.
2. Перемещение.
На мой взгляд более верным будет формировать движения о Приеме товаров в событии ОбработкаПроведения, а не командой… в этом случае не будет проблем с многочисленным нажатием на эту кнопку, а также не будет проблем при простом перепроведении документа (в вашем случае движения по приему будут затерты).
Можно добавить дополнительный реквизит “ДатаПриемаВТочкеВыдачи”. По этой дате и формировать движения о приеме. Если дата пуста – значит приема еще не было.
3. В общем.
Не попали ли мы при таком решении (смущает частое получение данных не из Регистров, а из таблицы Документов) под ошибку: “Получение расчетных данных не из регистра…”: цена 3 балла?
В любом случае вы потратили на эту задачу (если прибавить время на создание отчетов и включение блокировок) около 90 минут. Весьма похвально!
1. Согласен.
2. Согласен. Но я не хотел регистрировать изменение самого документа.
3. Неудачная задача, каюсь еще раз. Я ориентировался на ввод данных в документах на основании. Задача в более расширенном варианте функционирует в одном из реальных магазинов, но контроль заказов и остатков товаров почти полностью лежит на менеджерах, единственный момент это резервирование и контроль резервов автоматизирован. Но к сертификации это конечно не имеет отношения.
День добрый! Решил описать блокировки и оперативное проведение документов для эталонного решения задания №9, чтобы получить доступ к бонусу :).
В документе РегистрацияЗаказаКлиента модуль процедуры ОбработкаПроведения будет таким:
<code>
Процедура ОбработкаПроведения(Отказ, Режим)
Движения.СвободныеОстатки.БлокироватьДляИзменения = Истина;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = “ВЫБРАТЬ
| РегистрацияЗаказаКлиентаСписокТоваров.Номенклатура КАК Номенклатура,
| СУММА(РегистрацияЗаказаКлиентаСписокТоваров.Количество) КАК Количество,
| СУММА(РегистрацияЗаказаКлиентаСписокТоваров.СуммаПродажи) КАК СуммаПродажи
|ПОМЕСТИТЬ ДокТЧ
|ИЗ
| Документ.РегистрацияЗаказаКлиента.СписокТоваров КАК РегистрацияЗаказаКлиентаСписокТоваров
|ГДЕ
| РегистрацияЗаказаКлиентаСписокТоваров.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| РегистрацияЗаказаКлиентаСписокТоваров.Номенклатура
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ДокТЧ.Номенклатура,
| ДокТЧ.Количество
|ИЗ
| ДокТЧ КАК ДокТЧ”;
Запрос.УстановитьПараметр(“Ссылка”, Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Движения.СвободныеОстатки.Записывать = Истина;
Пока Выборка.Следующий() Цикл
Движение = Движения.СвободныеОстатки.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Номенклатура = Выборка.Номенклатура;
Движение.Количество = Выборка.Количество;
КонецЦикла;
Движения.Записать();
Запрос.Текст = “ВЫБРАТЬ
| СвободныеОстаткиОстатки.Номенклатура.Представление,
| СвободныеОстаткиОстатки.КоличествоОстаток
|ИЗ
| РегистрНакопления.СвободныеОстатки.Остатки(
| &МоментИтогов,
| Номенклатура В
| (ВЫБРАТЬ
| ДокТЧ.Номенклатура
| ИЗ
| ДокТЧ КАК ДокТЧ)) КАК СвободныеОстаткиОстатки
|ГДЕ
| СвободныеОстаткиОстатки.КоличествоОстаток < 0”;
Если Режим = РежимПроведенияДокумента.Оперативный Тогда
МоментИтогов = Дата(‘00010101’);
Иначе
МоментИтогов = Новый Граница(МоментВремени(), ВидГраницы.Включая);
КонецЕсли;
Запрос.УстановитьПараметр(“МоментИтогов”, МоментИтогов);
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Отказ = Истина;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = “Товар: ” + Выборка.НоменклатураПредставление + “, нехватает: ” +
(-Выборка.КоличествоОстаток);
Сообщение.Сообщить();
КонецЦикла;
КонецЕсли;
Движения.СостояниеЗаказов.Записывать = Истина;
Движение = Движения.СостояниеЗаказов.Добавить();
Движение.Период = Дата;
Движение.Заказ = Ссылка;
Движение.Состояние = Перечисления.СостоянияЗаказов.Новый;
КонецПроцедуры
</code>
В документе ВыдачаТоваров модуль процедуры ОбработкаПроведения будет таким:
<code>
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Запрос = Новый Запрос;
Запрос.Текст = “ВЫБРАТЬ
| РегистрацияЗаказаКлиентаСписокТоваров.Номенклатура,
| СУММА(РегистрацияЗаказаКлиентаСписокТоваров.Количество) КАК Количество,
| СУММА(РегистрацияЗаказаКлиентаСписокТоваров.СуммаПродажи) КАК СуммаПродажи,
| ВыдачаЗаказовЗаказы.Заказ
|ПОМЕСТИТЬ ОтгружаемыеТовары
|ИЗ
| Документ.ВыдачаЗаказов.Заказы КАК ВыдачаЗаказовЗаказы
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.РегистрацияЗаказаКлиента.СписокТоваров КАК РегистрацияЗаказаКлиентаСписокТоваров
| ПО ВыдачаЗаказовЗаказы.Заказ = РегистрацияЗаказаКлиентаСписокТоваров.Ссылка
|ГДЕ
| ВыдачаЗаказовЗаказы.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| РегистрацияЗаказаКлиентаСписокТоваров.Номенклатура,
| ВыдачаЗаказовЗаказы.Заказ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ОтгружаемыеТовары.Номенклатура,
| ОтгружаемыеТовары.Количество,
| ОтгружаемыеТовары.СуммаПродажи КАК СуммаПродажи,
| ОстаткиТоваровОстатки.КоличествоОстаток,
| СтоимостьТоваровОстатки.СтоимостьОстаток,
| ОтгружаемыеТовары.Заказ КАК Заказ
|ИЗ
| ОтгружаемыеТовары КАК ОтгружаемыеТовары
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки(
| &МоментИтогов,
| Номенклатура В
| (ВЫБРАТЬ
| ОтгружаемыеТовары.Номенклатура
| ИЗ
| ОтгружаемыеТовары КАК ОтгружаемыеТовары)) КАК ОстаткиТоваровОстатки
| ПО ОтгружаемыеТовары.Номенклатура = ОстаткиТоваровОстатки.Номенклатура
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СтоимостьТоваров.Остатки(
| &МоментИтогов,
| Номенклатура В
| (ВЫБРАТЬ
| ОтгружаемыеТовары.Номенклатура
| ИЗ
| ОтгружаемыеТовары КАК ОтгружаемыеТовары)) КАК СтоимостьТоваровОстатки
| ПО ОтгружаемыеТовары.Номенклатура = СтоимостьТоваровОстатки.Номенклатура
|ИТОГИ
| СУММА(СуммаПродажи)
|ПО
| ОБЩИЕ,
| Заказ”;
Если РежимПроведения = РежимПроведенияДокумента.Оперативный Тогда
Движения.ОстаткиТоваров.Записывать = Истина;
Движения.СтоимостьТоваров.Записывать = Истина;
Движения.ОстаткиТоваров.Очистить();
Движения.СтоимостьТоваров.Очистить();
Движения.Записать();
МоментИтогов = Дата(‘00010101’);
Иначе
МоментИтогов = МоментВремени();
КонецЕсли;
Запрос.УстановитьПараметр(“МоментИтогов”, МоментИтогов);
Запрос.УстановитьПараметр(“Ссылка”, Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Движения.ОстаткиТоваров.Записывать = Истина;
Движения.СтоимостьТоваров.Записывать = Истина;
Движения.Продажи.Записывать = Истина;
Движения.СостояниеЗаказов.Записывать = Истина;
Блокировка = Новый БлокировкаДанных;
ЭлементОстатки = Блокировка.Добавить(“РегистрНакопления.ОстаткиТоваров”);
ЭлементОстатки.ИсточникДанных = РезультатЗапроса;
ЭлементОстатки.ИспользоватьИзИсточникаДанных(“Номенклатура”, “Номенклатура”);
ЭлементОстатки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементСтоимость = Блокировка.Добавить(“РегистрНакопления.СтоимостьТоваров”);
ЭлементСтоимость.ИсточникДанных = РезультатЗапроса;
ЭлементСтоимость.ИспользоватьИзИсточникаДанных(“Номенклатура”, “Номенклатура”);
ЭлементСтоимость.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
СебестоимостьИтого = 0;
КолЗаказов = 0;
ВыборкаОбщиеИтоги = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаОбщиеИтоги.Следующий() Цикл
ВыборкаИтоги = ВыборкаОбщиеИтоги.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаИтоги.Следующий() Цикл
Выборка = ВыборкаИтоги.Выбрать();
Пока Выборка.Следующий() Цикл
Движение = Движения.ОстаткиТоваров.ДобавитьРасход();
Движение.Период = Дата;
Движение.Номенклатура = Выборка.Номенклатура;
Движение.Склад = ТочкаВыдачи;
Движение.Количество = Выборка.Количество;
Движение = Движения.СтоимостьТоваров.ДобавитьРасход();
Движение.Период = Дата;
Движение.Номенклатура = Выборка.Номенклатура;
Если Выборка.Количество = Выборка.КоличествоОстаток Тогда
Себестоимость = Выборка.СтоимостьОстаток;
Иначе
Себестоимость = Выборка.Количество / Выборка.КоличествоОстаток * Выборка.СтоимостьОстаток;
КонецЕсли;
Движение.Стоимость = Себестоимость;
СебестоимостьИтого = СебестоимостьИтого + Себестоимость;
КонецЦикла;
Движение = Движения.СостояниеЗаказов.Добавить();
Движение.Период = Дата;
Движение.Заказ = ВыборкаИтоги.Заказ;
Движение.Состояние = Перечисления.СостоянияЗаказов.Завершен;
КолЗаказов = КолЗаказов + 1;
КонецЦикла;
Движение = Движения.Продажи.Добавить();
Движение.Период = Дата;
Движение.ТочкаВыдачи = ТочкаВыдачи;
Движение.КолЗаказов = КолЗаказов;
Движение.Себестоимость = СебестоимостьИтого;
Движение.Выручка = ВыборкаОбщиеИтоги.СуммаПродажи;
КонецЦикла;
КонецПроцедуры
</code>
В документах ПоступлениеТоваров и ПеремещениеТоваров изменения не нужны.