Список работ

1С8: компенсация питания

Содержание

Постановка задачи

Создается обработка, в форме которой имеется таблица (элемент Сотрудники и одноименный реквизит типа ТаблицаЗначений).
В этой таблице перечисляются сотрудники (рис. 1), которым компенсируется питание в виде дохода Питание сотрудников, вводимого документом Доход в натуральной форме (рис. 2).

1с8: Форма обработки Питание

Рис. 1. Форма обработки Питание

Доход вводится документом Доход в натуральной форме (рис. 2).

1с8: Доход в натуральной форме

Рис. 2. Доход в натуральной форме

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

Элементы формы и реквизиты

Показаны на рис. 3.

Элементы формы и реквизиты

Рис. 3. Элементы формы и реквизиты

Кнопке выбора периода отвечает соответствующая команда. В результате ее выполнения открывается приведенный на рис. 4 диалог.

Выбор периода

Рис. 4. Выбор периода

Кнопка Добавить добавляет пустую строку в таблицу.
Кнопкам Заполнить, Распределить, Документ и Печать отвечают одноименные команды.

Код модуля формы обработки

В нем расположены процедуры и функции, обеспечивающие решение поставленных задач. В частности, после нажатия на кнопку Печать выводятся приведённые на рис. 5 и 6 отчеты.

Отчет о расходах на питание

Рис. 5. Расходы на питание

Дни питания

Рис. 6. Дни питания

&НаСервере
процедура запНаСервере()
    в = справочники.ФизическиеЛица.Выбрать();
    вки = справочники.ВидыКонтактнойИнформации.НайтиПоНаименованию("Домашний телефон");
    з = новый запрос;
    з.Текст = "выбрать представление
    | из справочник.ФизическиеЛица.КонтактнаяИнформация
    | где ссылка = &сотр и вид = &вки";
    з.УстановитьПараметр("вки", вки);
    мас = новый массив;
    сСотр = справочники.Сотрудники;
    пока в.Следующий() цикл
        физЛ = в.Ссылка;
        сотр = сСотр.НайтиПоРеквизиту("ФизическоеЛицо", физЛ);
        з.УстановитьПараметр("сотр", физЛ);
        р = з.Выполнить();
        если р.Пустой() тогда продолжить конецЕсли;
        вр = р.Выбрать();
        вр.следующий();
        с = сотрудники.Добавить();
        с.сотр = сотр;
        с.питание = истина;
        с.дней = 15;
        с.карта = вр.представление;
        мас.Добавить(сотр);
    конецЦикла;
    з = новый запрос;
    з.Текст = "выбрать *
    | из документ.ТабельУчетаРабочегоВремени.ДанныеОВремени
    | где ссылка.ДатаНачалаПериода = &началоПериода и сотрудник в (&мас)
    | упорядочить по сотрудник.наименование";
    з.УстановитьПараметр("началоПериода", началоПериода);
    з.УстановитьПараметр("мас", мас);
    р = з.Выполнить();
    тз = р.Выгрузить();
    явка = справочники.ВидыИспользованияРабочегоВремени.Явка;
    м = -1;
    для каждого с из тз цикл
        дни = 0;
        для к = 3 по 33 цикл
            если с[к] > 0 и с[к + 31] = явка тогда дни = дни + 1 конецЕсли;
        конецЦикла;
        м = м + 1;
        сотрудники[м].дней = дни;
    конецЦикла;
КонецПроцедуры

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

&НаКлиенте
Процедура ПослеОтветаНаВопрос(Результат, Параметры) экспорт
    Если Результат = КодВозвратаДиалога.Нет Тогда возврат КонецЕсли;
    сотрудники.Очистить();
    запНаСервере();
КонецПроцедуры

&НаКлиенте
Процедура заполнить(Команда)
    если не значениеЗаполнено(началоПериода) или не значениеЗаполнено(конецПериода) тогда сообщить("Не выбран период"); возврат конецЕсли;
    если сотрудники.Количество() > 0 тогда
        ЗадатьВопрос()
    иначе
        запНаСервере();
    конецЕсли;
КонецПроцедуры

&НаСервере
функция найтиСотр(код)
    возврат справочники.Сотрудники.НайтиПоКоду(код)
конецФункции

&НаКлиенте
Процедура распределить(Команда)
    если сотрудники.Количество() = 0 тогда сообщить("Список сотрудников пуст"); возврат конецЕсли;
    если сумма = 0 тогда сообщить("Укажите распределяемую сумму"); возврат конецЕсли;
    всегоДней = 0;
    для каждого с из сотрудники цикл
        если с.питание тогда всегоДней = всегоДней + с.дней конецЕсли;
    конецЦикла;
    если всегоДней = 0 тогда сообщить("Не указаны дни"); возврат конецЕсли;
    доля = сумма / всегоДней;
    всегоСумма = 0;
    для каждого с из сотрудники цикл
        если с.питание тогда
            сум = цел(с.дней * доля);
            с.сумма = сум;
            всегоСумма = всегоСумма + сум;
        конецЕсли;
    конецЦикла;
    руководитель = найтиСотр("0001");
    если не руководитель.пустая() тогда
        разница = сумма - всегоСумма;
    конецЕсли;
    для каждого с из сотрудники цикл
        если с.сотр = руководитель тогда
            с.сумма = с.сумма + разница;
            прервать
        конецЕсли;
    конецЦикла;
КонецПроцедуры

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

&НаКлиенте
Процедура ВыбратьПериодЗавершение(РезультатВыбора, ДопПараметры) Экспорт
    Если РезультатВыбора = Неопределено Тогда Возврат КонецЕсли;
    началоПериода = РезультатВыбора.ДатаНачала;
    конецПериода = конецМесяца(началоПериода); // РезультатВыбора.ДатаОкончания;
    если значениеЗаполнено(НачалоПериода) тогда
        мес = формат(НачалоПериода, "ДФ='ММММ гггг'");
    иначе
        мес = "";
    конецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    если не значениеЗаполнено(началоПериода) тогда
        началоПериода = началоМесяца(текущаяДата());
        конецПериода = конецМесяца(началоПериода);
    конецЕсли;
    мес = формат(НачалоПериода, "ДФ='ММММ гггг'");
КонецПроцедуры

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

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

&НаСервере
функция печатьНаСервере()
    месГод = формат(конецМесяца(текущаяДата()), "ДФ='ММММ гггг'");
    макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет");
    блЗг = макет.ПолучитьОбласть("зг");
    блЗг.параметры.месГод = "за " + мес + " года";
    блСотр = макет.ПолучитьОбласть("сотр");
    прмСотр = блСотр.параметры;
    тд = новый табличныйДокумент;
    тд.Вывести(блЗг);
    н = 0;
    вс = 0;
    для каждого с из сотрудники цикл
        н = н + 1;
        прмСотр.н = "" + н + " ";
        прмСотр.карта = с.карта;
        прмСотр.сотр = с.сотр;
        прмСотр.акт = ?(с.питание, "активна", "нет");
        прмСотр.дней = с.дней;
        сум = с.сумма;
        прмСотр.сум = сум;
        тд.Вывести(блСотр);
        вс = вс + сум;
    конецЦикла;
    блДно = макет.ПолучитьОбласть("дно");
    блДно.параметры.вс = вс;
    тд.Вывести(блДно);
    возврат тд;
конецфункции

&НаСервере
функция печатьНаСервереДни()
    мас = новый массив;
    для каждого с из сотрудники цикл
        если с.питание тогда мас.Добавить(с.сотр) конецЕсли;
    конецЦикла;
    з = новый запрос;
    з.Текст = "выбрать *
    | из документ.ТабельУчетаРабочегоВремени.ДанныеОВремени
    | где ссылка.ДатаНачалаПериода = &началоПериода и сотрудник в (&мас)
    | упорядочить по сотрудник.наименование";
    з.УстановитьПараметр("началоПериода", началоПериода);
    з.УстановитьПараметр("мас", мас);
    р = з.Выполнить();
    тз = р.Выгрузить();
    макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Дни");
    блЗг = макет.ПолучитьОбласть("зг|нач");
    блЗг.параметры.месГод = мес;
    тд = новый табличныйДокумент;
    тд.Вывести(блЗг);
    длинаМес = день(конецПериода);
    блЗг = макет.ПолучитьОбласть("зг|день");
    для к = 1 по длинаМес цикл
        блЗг.параметры.день = к;
        тд.Присоединить(блЗг);
    конецЦикла;
    блСотрНач = макет.ПолучитьОбласть("сотр|нач");
    прмСотрНач = блСотрНач.параметры;
    блСотрДень = макет.ПолучитьОбласть("сотр|день");
    прмСотрДень = блСотрДень.параметры;
    н = 0;
    явка = справочники.ВидыИспользованияРабочегоВремени.Явка;
    для каждого с из сотрудники цикл
        если не с.питание тогда продолжить конецЕсли;
        н = н + 1;
        прмСотрНач.н = "" + н + " ";
        прмСотрНач.сотр = с.сотр;
        прмСотрНач.всДней = с.дней;
        тд.Вывести(блСотрНач);
        с2 = тз.Найти(с.сотр, "сотрудник");
        для к = 1 по длинаМес цикл
            попытка
                к2 = к + 2;
                прмСотрДень.д = ?(с2[к2 + 31] = явка, "+", "");
                тд.Присоединить(блСотрДень);
            исключение
                сообщить("");
            конецПопытки;
        конецЦикла;
    конецЦикла;
    блДно = макет.ПолучитьОбласть("дно");
    тд.Вывести(блДно);
    возврат тд;
конецфункции

&НаКлиенте
процедура печать(команда)
    если сотрудники.Количество() = 0 тогда сообщить("Список пуст"); возврат конецЕсли;
    тд = печатьНаСервере();
    тд.показать("Расходы");
    тд = печатьНаСервереДни();
    тд.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
    тд.показать("Дни");
конецПроцедуры

Код модуля обработки

В нем расположены функции, обеспечивающие регистрацию обработки.

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область СлужебныеПроцедурыИФункции
Функция СведенияОВнешнейОбработке() Экспорт
    Перем ПараметрыРегистрации;
    Если ПодсистемаСуществует("СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки") Тогда
        МодульДополнительныеОтчетыИОбработки = ОбщийМодуль("ДополнительныеОтчетыИОбработки");
        МодульДополнительныеОтчетыИОбработкиКлиентСервер = ОбщийМодуль("ДополнительныеОтчетыИОбработкиКлиентСервер");
        ПараметрыРегистрации = МодульДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.1.3.1");
        ПараметрыРегистрации.Вид = МодульДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
        ПараметрыРегистрации.Версия = "2.2.1";
        ПараметрыРегистрации.БезопасныйРежим = истина;
        НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
        НоваяКоманда.Представление = НСтр("ru = 'Питание'");
        НоваяКоманда.Идентификатор = "ОткрытьГлобально";
        НоваяКоманда.Использование = МодульДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы();
        НоваяКоманда.ПоказыватьОповещение = Ложь;
    КонецЕсли;
    Возврат ПараметрыРегистрации;
КонецФункции

Функция ПодсистемаСуществует(ПолноеИмяПодсистемы) Экспорт
    ИменаПодсистем = ИменаПодсистем();
    Возврат ИменаПодсистем.Получить(ПолноеИмяПодсистемы) <> Неопределено;
КонецФункции

Функция ОбщийМодуль(Имя) Экспорт
    Если Метаданные.ОбщиеМодули.Найти(Имя) <> Неопределено Тогда
        Модуль = Вычислить(Имя);
    Иначе
        Модуль = Неопределено;
    КонецЕсли;
    Если ТипЗнч(Модуль) <> Тип("ОбщийМодуль") Тогда
        ВызватьИсключение ПодставитьПараметрыВСтроку(
            НСтр("ru = 'Общий модуль ""%1"" не найден.'"), Имя);
    КонецЕсли;
    Возврат Модуль;
КонецФункции

Функция ИменаПодсистем() Экспорт
    Возврат Новый ФиксированноеСоответствие(ИменаПодчиненныхПодсистем(Метаданные));
КонецФункции

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

Функция ПодставитьПараметрыВСтроку(Знач СтрокаПодстановки, Знач Параметр) Экспорт
    Возврат СтрЗаменить(СтрокаПодстановки, "%1", Параметр);
КонецФункции
#КонецОбласти
#КонецЕсли

Заключение

Для упрощения кода вместо оповещений употребляются сообщения, например, при отсутствии распределяемой суммы.
Оповещение будет создано (рис. 7), если будет выполнена попытка перезаполнить таблицу Сотрудники.

Оповещение

Рис. 7. Оповещение

Заметим, что оповещение используется в качестве первого параметра диалога ПоказатьВопрос.

Список работ

Рейтинг@Mail.ru