пятница, 30 января 2015 г.

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

Скачать решение

Условие задачи из сборника:
Начисление зарплаты сотрудникам предприятия осуществляется
ежемесячно с использованием метода отклонений. Все сотрудники работают по
пятидневному графику работы, однако в решении необходимо предусмотреть
возможность работы по нескольким различным графикам.
Сотрудники предприятия получают оплату по часовому тарифу. Сумма
начисления по тарифу определяется как тарифная ставка, умноженная на
количество фактически отработанных часов. Тарифная ставка должна быть
определена отдельно для каждого подразделения по специальной шкале в
зависимости от отработанного времени. Например:


Ежемесячно, сотрудникам компании может выплачиваться фиксированная
сумма денег. Размер суммы задается в документе «Начисление зарплаты» и в
последствии может быть изменен.
Сотрудникам предоставляется оплачиваемый отпуск, размер которого
определяется как количество дней отпуска умноженное на среднюю дневную
ставку. Дни отпуска рассчитываются по шестидневному графику. Средняя
дневная ставка определяется как сумма всех начислений за три предыдущих
месяца, поделенная на количество отработанных дней в трех предыдущих
месяцах. Следует учесть, что данные об отпуске не могут вводиться в систему
задним числом.
Механизм перерасчетов в рамках данной задачи использовать не надо.
Ввод всех начислений происходит документом «Начисление зарплаты».
Считать, что все данные вводятся только в пределах одного месяца, например,
можно указать начисление по тарифу с 10.01 по 31.01, а запись: тариф с 10.01 по
03.02 вводить нельзя.
Необходимо предоставить пользователю возможность исправлять
результат расчета в форме документа, а также самостоятельно создавать новые
виды расчетов и привязывать их к существующим алгоритмам расчета.
Для анализа сделанных сотрудникам предприятия начислений в
конфигурации необходимо предусмотреть отчет следующего вида:
Решение задачи :
1) Первым делом заполним регистр сведений "Графики работы". Для этого потребуется создать новый справочник "Графики работы". Можно в нем сразу же добавить предопределенные элементы 5дневка  и 6дневка. Заполнять график будем с помощью обработки "Заполнение графика". Необходимо выполнить минимум доработок.
  1. Добавить реквизит обработки "График". 
  2. В модуле обработки установить отбор на набор записей:  Набор.Отбор.График.Установить(График); после первой строки кода.
  3. Далее при создании новой записи упомянуть график "везде где только нужно" ).
  4. Заполнить график в режиме предприятия. Для пятидневки в поле выходные дни пишем 67, для шестидневки только 7. 
2) Создадим и заполним регистр сведений "Тарифные ставки".
Измерения:
Подразделение
ОтработаноС
ОтработаноПо
Ресурс (тип число(10,1))
После заполнения регистр будет иметь вид:



3) Заведем требуемые виды расчета.
ПВР "Основные начисления" установим флаг "Использует период действия", зависимость от базы = "Зависит по периоду действия", базовые виды расчета включим "Основные начисления" и "Дополнительные начисления" (так как отпуск будет зависеть от фиксированной суммы)
Заведем в ПВР "Основные начисления" следующие предопределенные ВР: ПоТарифу и "Отпуск". 
Так как по условию необходимо предоставить пользователю возможность  самостоятельно создавать новые виды расчетов и привязывать их к существующим алгоритмам расчета, то 
заведем новое перечисление  "СпособыРасчета" с данными (Пропорционально отработанному времени,фиксированной суммой, по среднему). В ПВР  добавим реквизит "Способ расчета" (Тип созданное перечисление, проверка заполнения="выдавать ошибку").
Таким образом пользователь сможет создавать сколько угодно видов расчета, но рассчитывать их мы будем согласно реквизиту "способ расчета" (чудес ведь не бывает:) ).
Заполняем базовые  и вытясняющие ВР для отпуска и тарифа.
Тут все очевидно:
Отпуск - базовые все.
По тарифу- вытесяняющие отпуск.


ПВР "Дополнительные начисления" сбросим флаг "Использует период действия", зависимость от базы = "Не зависит". Заведем  предопределенный ВР: "ПремияФиксСуммой".

4) Понадобятся 2 регистра расчета "Основные начисления" и "Дополнительные начисления".

реквизит график необходимо связать с измерением регистра сведений.

5). Переходим к документу "Начисление ЗП".
Добавим реквизиты шапки и таб. частей.

В условии сказано "Считать, что все данные вводятся только в пределах одного месяца, например,можно указать начисление по тарифу с 10.01 по 31.01, а запись: тариф с 10.01 по
03.02 вводить нельзя."
Понимаю что реализовать это можно процедурой проверки поля"Период действия конец".
&НаКлиенте
Процедура ОсновныеНачисленияДатаОкончанияПриИзменении(Элемент)
ТекСтрока = Элементы.ОсновныеНачисления.ТекущиеДанные;
Если НачалоМесяца(ТекСтрока.ПериодДействияНачало) <> НачалоМесяца(ТекСтрока.ПериодДействияКонец) Тогда
ТекСтрока. ПериодДействияКонец = Дата(1,1,1);
Сообщение = Новый("СообщениеПользователю");
Сообщение.Текст = "Даты должны принадлежать одному периоду";
Сообщение.Сообщить();
КонецЕсли;
КонецПроцедуры

В условии требуется "предоставить пользователю возможность исправлять
результат расчета в форме документа".
Реализую это требование следующим образом: В форме документа создам процедуру "Рассчитать", которая и выполнит расчет и загрузит данные расчета в ТЧ, а по команде провести выполнится запись в регистр значений "как есть" исправленных пользователем.
В решении я вижу пару нереализованных моментов:
1) Для отпуска базой являются 3 предыдущих месяца. По идее если пользователь заводит подобный  ВР с типом "по среднему", то еще необходимо с помощью реквизита запросит количество месяцев базы для нового ВР. В решении для всех это кол-во =3.
2) В подобных задачах иногда используются приоритеты для указания последовательности выполнения расчетов, но как мне кажется в этой задаче и так достаточно заморочек и без этого, и особой нужды в этом нет.



6) Несложный отчет "Начисления", в котором необходимо объединить 2 таблицы и добавить в группировку по колонкам поле "период регистрации"
Итак. ниже листинги процедур и сама база.



&НаСервере
Процедура РассчитатьНаСервере()
Документ = РеквизитФормыВЗначение("Объект");
Документ.Рассчитать();
ЗначениеВРеквизитФормы( Документ, "Объект");
КонецПроцедуры

&НаКлиенте
Процедура Рассчитать(Команда)
РассчитатьНаСервере();
КонецПроцедуры


Процедура Рассчитать() Экспорт
Если ЭтоНовый() Или Модифицированность() Тогда
Режим  =РежимЗаписиДокумента.Запись;
Записать(РежимЗаписиДокумента.Запись);
КонецЕсли;
Если ЭтотОбъект.Проведен Тогда
Записать(РежимЗаписиДокумента.ОтменаПроведения);
КонецЕсли;
Запрос = Новый("Запрос");
Запрос.Текст ="ВЫБРАТЬ
| НачислениеЗарплатыОсновныеНачисления.Ссылка,
| НачислениеЗарплатыОсновныеНачисления.НомерСтроки,
| НачислениеЗарплатыОсновныеНачисления.Сотрудник,
| НачислениеЗарплатыОсновныеНачисления.Подразделение,
| НачислениеЗарплатыОсновныеНачисления.ВидРасчета,
| НачислениеЗарплатыОсновныеНачисления.ПериодДействияНачало,
| НачислениеЗарплатыОсновныеНачисления.ПериодДействияКонец,
| НачислениеЗарплатыОсновныеНачисления.Параметр,
| НачислениеЗарплатыОсновныеНачисления.Результат,
| НачислениеЗарплатыОсновныеНачисления.График,
| НачислениеЗарплатыОсновныеНачисления.Ссылка.ПериодРегистрации КАК ПериодРегистрации,
| НАЧАЛОПЕРИОДА(НачислениеЗарплатыОсновныеНачисления.ПериодДействияНачало, МЕСЯЦ) КАК БазовыйПериодНачало,
| КОНЕЦПЕРИОДА(НачислениеЗарплатыОсновныеНачисления.ПериодДействияКонец, МЕСЯЦ) КАК БазовыйПериодКонец,
| НачислениеЗарплатыОсновныеНачисления.ВидРасчета.СпособРасчета КАК СпособРасчета
|ИЗ
| Документ.НачислениеЗарплаты.ОсновныеНачисления КАК НачислениеЗарплатыОсновныеНачисления
|ГДЕ
| НачислениеЗарплатыОсновныеНачисления.Ссылка = &Ссылка";
Запрос.УстановитьПараметр( "Ссылка" ,Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Движение = Движения.ОсновныеНачисления.Добавить();
ЗаполнитьЗначенияСвойств(Движение,Выборка); 
Если Выборка.СпособРасчета = Перечисления.СпособыРасчета.ПоСреднему Тогда
Движение.БазовыйПериодНачало = НачалоМесяца(ДобавитьМесяц(Выборка.ПериодДействияНачало,-3));
Движение.БазовыйПериодКонец = КонецМесяца(ДобавитьМесяц(Выборка.ПериодДействияКонец,-1));
Движение.График = Справочники.ГрафикиРаботы.НайтиПоНаименованию("6дневка").Ссылка;
Иначе
Движение.БазовыйПериодНачало = НачалоМесяца(Выборка.ПериодДействияНачало);
Движение.БазовыйПериодКонец = КонецМесяца(Выборка.ПериодДействияКонец);
КонецЕсли;
КонецЦикла;
Движения.ОсновныеНачисления.Записать();
Рассчет.ВыполнитьРассчет(Движения.ОсновныеНачисления, Перечисления.СпособыРасчета.ПропорциональноОтработанномуВремени, ОсновныеНачисления.ВыгрузитьКолонку("Сотрудник"));
Движения.ОсновныеНачисления.Записать(Истина);
Рассчет.ВыполнитьРассчет(Движения.ОсновныеНачисления, Перечисления.СпособыРасчета.ПоСреднему, ОсновныеНачисления.ВыгрузитьКолонку("Сотрудник"));
Движения.ОсновныеНачисления.Записать(Истина);
ОсновныеНачисления.Загрузить(Движения.ОсновныеНачисления.Выгрузить());

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


Листинг процедуры Рассчет общего модуля:

Процедура ВыполнитьРассчет(НаборЗаписей, СпособРасчета, МассивСотрудников) Экспорт

Регистратор=НаборЗаписей.Отбор.Регистратор.Значение;

Если СпособРасчета = Перечисления.СпособыРасчета.ПропорциональноОтработанномуВремени Тогда

Запрос = Новый("Запрос");
Запрос.Текст ="ВЫБРАТЬ
| ЕСТЬNULL(ОсновныеНачисленияДанныеГрафика.ЗначениеФактическийПериодДействия, 0) КАК Факт,
| ЕСТЬNULL(ТарифныеСтавки.РазмерСтавки, 0) КАК Тариф,
| ОсновныеНачисленияДанныеГрафика.НомерСтроки,
| ОсновныеНачисленияДанныеГрафика.ОтработаноДней

|ИЗ
| РегистрРасчета.ОсновныеНачисления.ДанныеГрафика(
| Сотрудник В (&МассивСотрудников)
| И ВидРасчета.СпособРасчета = &СпособРасчета
| И Регистратор = &Регистратор) КАК ОсновныеНачисленияДанныеГрафика
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ТарифныеСтавки КАК ТарифныеСтавки
| ПО ОсновныеНачисленияДанныеГрафика.Подразделение = ТарифныеСтавки.Подразделение
| И ОсновныеНачисленияДанныеГрафика.ЗначениеФактическийПериодДействия >= ТарифныеСтавки.ОтработаноС
| И ОсновныеНачисленияДанныеГрафика.ЗначениеФактическийПериодДействия <= ТарифныеСтавки.ОтработаноПо";

Запрос.УстановитьПараметр("СпособРасчета", СпособРасчета);
Запрос.УстановитьПараметр("Регистратор", Регистратор);
Запрос.УстановитьПараметр("МассивСотрудников", МассивСотрудников);

Выборка = Запрос.Выполнить().Выбрать();

Для Каждого Запись Из НаборЗаписей Цикл

Отбор  = Новый("Структура");
Отбор.Вставить("НомерСтроки",Запись.НомерСтроки);
Выборка.Сбросить();
Если выборка.НайтиСледующий(Отбор) тогда
Запись.Параметр = Выборка.Факт;
Запись.Результат = (Выборка.Факт) * Выборка.Тариф;
Запись.ОтработаноДней = Выборка.Факт/8;

КонецЕсли;
КонецЦикла;


ИначеЕсли    СпособРасчета = Перечисления.СпособыРасчета.ПоСреднему Тогда

Измер = Новый("Массив");
Измер.Добавить("Сотрудник");

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

Запрос.УстановитьПараметр("СпособРасчета", СпособРасчета);
Запрос.УстановитьПараметр("Регистратор", Регистратор);
Запрос.УстановитьПараметр("МассивСотрудников", МассивСотрудников);
Запрос.УстановитьПараметр("ИзмеренияОсновного", Измер);
Запрос.УстановитьПараметр("ИзмеренияБазового", Измер);
Выборка = Запрос.Выполнить().Выбрать();

Для Каждого Запись Из НаборЗаписей Цикл

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


КонецПроцедуры
Скачать решение

Возможно Вам будет интересен курс "Профессиональный учет в 1С:ЗУП 3.0»

вторник, 27 января 2015 г.

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

Условие задачи из сборника:

Товар на складе размещается в ячейках. При поступлении на склад каждый
товар помещается в отдельную ячейку, которая однозначно определяется своим
рядом и стеллажом. При продаже товара определяется способ отгрузки: сразу или
с доставкой. Если товар отгружается сразу, то чтобы быстрее осуществить
продажу в первую очередь должен отпускаться ближайший товар. Если же
производится доставка товара, то тогда должен списываться товар, до которого
неудобнее всего добираться.
Критерием удобства отгрузки (расстояние) служит сумма номера ряда и
номера стеллажа.
После проведения расходной накладной должна формироваться печатная
форма, в которой будет указано, из каких ячеек должен быть получен товар.


Решение задачи :

Изменим регистр "ОстаткиНоменклатуры":
Измерения:
Номенклатура
Ряд (число)
Стеллаж (число)
Ресурсы:
Количество:
Документ "Приходная накладная".
Так как учет себестоимости вести не нужно заменим рекизиты ТЧ "Цена" и "Сумма" на "ряд" и "стеллаж".
Потребуется незамысловатая обработка проведения с группировкой по номенклатуре, ряду и стеллажу на случай ввода дублей строк.


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


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

Переходим к "Расходной накладной".
Потребуется завести новое перечисление "СпособОтгрузки" с 2-мя значениями "Сразу" и "С доставкой". Реквизит этого типа добавим в документ РН. Так как для печатной формы потребуется цена и сумма, то реализуем пересчет ТЧ.

&НаКлиенте
Процедура СписокНоменклатурыКоличествоПриИзменении(Элемент)
Пересчет();
КонецПроцедуры
&НаКлиенте
Процедура СписокНоменклатурыЦенаПриИзменении(Элемент)
Пересчет()
КонецПроцедуры

&НаКлиенте
Процедура Пересчет()
ТекДанные = Элементы.СписокНоменклатуры.ТекущиеДанные;
ТекДанные.сумма = ТекДанные.Количество * ТекДанные.Цена;
КонецПроцедуры

Переходим к обработке проведения. "Новая методика" в этом случае не прокатит, реализуем ее  старым добрым способом с выборкой по группировкам и проверкой "Осталось списать".

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
СуммаПоДокументу = СписокНоменклатуры.Итог("сумма");
КонецПроцедуры

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


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

из клиентской процедуры вызываем серверную, на которой и сформируем сам макет.
Решил не "заморачиваться" с СКД, а нарисовать "по старинке" макет и заполнить его должным образом.

&НаСервере
Процедура Печать(ТабДок);
Макет = Документы.РасходнаяНакладная.ПолучитьМакет("Макет");
ОбластьЗаголовок=Макет.ПолучитьОбласть("Заголовок");
ОбластьСтрока=Макет.ПолучитьОбласть("Строка");
ОбластьЗаголовок.Параметры.ссылка = "Расходная накладная № "+Объект.Номер +" от "+Формат(Объект.Дата,"ДФ=dd.MM.yyyy");
ТабДок.Вывести(ОбластьЗаголовок);
Запрос = Новый("Запрос");
Запрос.Текст ="ВЫБРАТЬ
| ОстаткиНоменклатуры.Регистратор,
| ОстаткиНоменклатуры.НомерСтроки,
| ОстаткиНоменклатуры.Стеллаж ,
| ОстаткиНоменклатуры.Ряд ,
| ОстаткиНоменклатуры.Количество,
| РасходнаяНакладнаяСписокНоменклатуры.Цена,
| ОстаткиНоменклатуры.Номенклатура как товар
|ИЗ
| РегистрНакопления.ОстаткиНоменклатуры КАК ОстаткиНоменклатуры
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.РасходнаяНакладная.СписокНоменклатуры КАК РасходнаяНакладнаяСписокНоменклатуры
| ПО ОстаткиНоменклатуры.Номенклатура = РасходнаяНакладнаяСписокНоменклатуры.Номенклатура
|ГДЕ
| ОстаткиНоменклатуры.Регистратор = &Ссылка
| И РасходнаяНакладнаяСписокНоменклатуры.Ссылка = &Ссылка";
Запрос.Параметры.Вставить("Ссылка", Объект.Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ОбластьСтрока.Параметры.Заполнить(Выборка);
ОбластьСтрока.Параметры.Сумма  = Выборка.Количество * Выборка.Цена;
ОбластьСтрока.Параметры.Стеллаж = "Ст №" + Выборка.стеллаж ;
ОбластьСтрока.Параметры.Ячейка = "Яч." + Выборка.стеллаж +"/"+ Выборка.Ряд;
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;

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




понедельник, 26 января 2015 г.

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

Условие задачи из сборника:


Компания занимается оптовой торговлей складских стеллажей и
комплектующих. Закупка комплектующих отражается документом «Приходная
накладная», продажа - «Расходная накладная».
Каждый стеллаж представляет собой некоторый фиксированный наб
комплектующих (например, 4 стойки, 5 полок и 20 болтов). Необходимо
обеспечить уникальность деталей, т.е. одна и та же деталь не может относить с
разным стеллажам.
Учет остатков ведется в разрезе складов. В документах «Приходная
накладная» и «Расходная накладная» склад только один (склад – реквизит шапки
Возможна продажа как отдельных комплектующих, так и цел
стеллажей, причем и стеллажи и их комплектующие указываются в одной
табличной части. В случае продажи стеллажа осуществляется списание со склада
соответствующего количества комплектующих. В том случае, если каких-ли
комплектующих на складе не хватает, документ проводится не должен. У
себестоимости деталей вести не требуется.
Создать отчет, который в разрезе складов будет показывать количество
целых стеллажей, и отчет, который будет показывать количество деталей
разрезе стеллажей, к которым они относятся, и складов. Например, если стеллаж
состоит из 4 стоек, 5 полок и 20 болтов, а на складе есть 8 стоек 15 полок и
болтов, то целый стеллаж только один.











Решение задачи :

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


&НаКлиенте
Процедура КомплектующаяОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
Если ЭтоСтеллаж(ВыбранноеЗначение)  Тогда
ВыбранноеЗначение="";
КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция  ЭтоСтеллаж(ВыбранноеЗначение)
Если ВыбранноеЗначение.ЭтоСтеллаж Тогда
Сообщить("Стелаж не может быть выбран");
Возврат Истина;
Иначе
Возврат Ложь;
КонецЕсли;
КонецФункции.

Процедуры формы справочника номенклатуры:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
ЗаполнитьТЧ();
КонецПроцедуры

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

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

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

При проведении необходимо стеллажи "перевести" в комплектующие.

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

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

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

3) Переходим к накладной. Это редкий случай когда обработка проведения не многим сложнее обработки проведения приходной.


Процедура ОбработкаПроведения(Отказ, РежимПроведения)

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

//2 Блокировка
Движения.ОстаткиНоменклатуры.БлокироватьДляИзменения = Истина;

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

Запрос.УстановитьПараметр("Ссылка", Ссылка);

Результат = Запрос.Выполнить();
МассивНоменклатуры = Новый("Массив");


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

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

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

4. Отчеты.
"Наличие стеллажей". 

В обоих отчетах потребуется левое соединение регистра сведений и регистра остатков. Главная задача: теперь обратно нужно "перевести " детали в стеллажи.
Сделаем это с помощью деления

Текст запроса:
ВЫБРАТЬ
ОстаткиНоменклатурыОстатки.Склад,
Комплекты.Стеллаж,
МИНИМУМ(ОстаткиНоменклатурыОстатки.КоличествоОстаток / Комплекты.Количество) КАК Количество
ИЗ
РегистрНакопления.ОстаткиНоменклатуры.Остатки(&НаДату, ) КАК ОстаткиНоменклатурыОстатки
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Комплекты КАК Комплекты
ПО ОстаткиНоменклатурыОстатки.Номенклатура = Комплекты.Комплектующая
ГДЕ
НЕ Комплекты.Стеллаж ЕСТЬ NULL 

СГРУППИРОВАТЬ ПО
Комплекты.Стеллаж,
ОстаткиНоменклатурыОстатки.Склад

Со вторым отчетам еще проще, делений не требуется, только необходимо еще добавить измерение "деталь".

Как "бонус" для тех кто дочитал до конца ссылка)