# Основные объекты
1. Регистр сведений «пр_НастройкиУведомленийПроектов»
Измерение: Проект.
*Ресурсы:* Сроки анализа/разработки, пользователи для уведомлений, тексты шаблонов, флаги включения.
**2. Справочник «пр_ОтправленныеУведомленияПоПросроченымЗаданиям»**
*Назначение:* Фиксация отправки для избежания дублирования.
*Реквизиты:* Задание, проект, пользователь, текст уведомления.
**3. Общий модуль «пр_ОтправкаУведомленийПоПросроченымЗаданиям»**
*Тип:* Серверный, с вызовом сервера.
*Ключевая процедура:* `ОтправкаУведомления()`.
# Ключевые модификации
**Документ «ЗаданиеНаРаботу»**
*В форме:* Автоматическое заполнение дат начала этапов при смене статуса (процедура `УстановитьДатыНачалаСтатусов`).
**Обработка «КонтактЦентр»**
*В главной форме:* Добавлены кнопки для работы с уведомлениями (открыть настройки, журнал, запустить отправку).
# Алгоритм отправки
1. **Инициализация:** Проверка системы взаимодействия, создание бота-отправителя.
2. **Отбор заданий:** Выборка просроченных заданий по критериям (активные, без дублей, с настройками).
3. **Расчет:** Определение продолжительности в рабочих днях (по производственному календарю РФ).
4. **Подготовка:** Проверка/создание пользователя в системе взаимодействия, формирование обсуждения.
5. **Отправка:** Заполнение шаблона и отправка сообщения.
6. **Фиксация:** Запись в справочник отправленных уведомлений и журнал регистрации.
Чтобы создать расширение конфигурации, нужно вызвать команду главного
меню «Конфигурация» – «Расширения конфигурации».
Подробнее об этом можно прочитать в книге «Расширения конфигураций.
Адаптация прикладных решений с сохранением поддержки в облаках и на земле» Е.
Ю. Хрусталева Глава 1 – Создание и отладка
(https://its.1c.ru/db/pubextensions#content:9:hdoc).
В окне «Создание хранилища расширения Основное» укажите папку на
https://drive.google.com/file/d/1mdm_6GLtW-Tl44mViGrWxTd2g-TCo4no/view?usp=drivesdk
компьютере для расположения хранилища. Путь к хранилищу должен быть
полностью на английском, а также папка должны быть пустой.
Нажмите два раза на кнопку «Далее» перейдя к шагу создания пользователя
Администратора хранилища. Измените имя администратора, а также задайте пароль
согласно заданию.
Нажмите кнопку «ОК». В окне с вопросом «Подключиться к созданному
хранилищу конфигурации?» ответьте положительно.
После данных действий расширение автоматически подключиться к хранилищу
с правами администратора и у расширения отобразиться значок замка.
Для создания дополнительного пользователя хранилища необходимо вызвать
команду главного меню «Конфигурация» пункт «Хранилище конфигурации» -
«Администрирование хранилища».
В окне «Администрирование хранилища расширения Основное» нажмите
кнопку «Добавить». В окне «Параметры пользователя хранилища конфигурации»
укажите имя, пароль дополнительного пользователя согласно заданию.
Перейдите на вкладку «Права». Включите «Изменение состава версий» и
нажмите «ОК».
В результате добавится дополнительный пользователь. Закройте окно
«Администрирование хранилища расширения Основное».
Для подключения к Хранилищу в дереве расширения конфигурации нажмите
правой кнопкой мыши на корень конфигурации и выберите команду «Захватить в
хранилище».
В открывшемся окне нажмите кнопку «ОК».
Выведется служебное сообщение, что расширение захвачено в хранилище
конфигурации.
После данных действий у расширения отобразиться значок замка с галочкой.
Самостоятельно переименуйте справочник «пр_ТестовыйСправочник» в
«пр_ТестовыйСправочник1» предварительно поместите его в хранилище. Сохраните
расширение Основное и отправьте изменения в хранилище с комментарием.
Нажмите пункт главного меню «Конфигурация» затем пункт «Хранилище
конфигурации» команду «История хранилища».
В окне «История хранилища расширения Основное» можно посмотреть
историю изменений данных в хранилище и их комментарии.
В окне «История хранилища расширения Основное» можно посмотреть
историю изменений данных в хранилище и их комментарии.
Создайте файл «how_to_connect.md» в любом месте на Вашем компьютере.
Подготовьте файлы с картинками для инструкции и разместите их в той же папке где
находиться файл инструкция.
Откройте файл «how_to_connect.md» в Visual Studio Code.
Заполните данный файл следующей инструкцией, где в команде  вместо
точек указывается название картинки. Для отображения предварительного просмотра
Markdown в Visual Studio Code нажмите комбинацию клавиш Ctrl + K, V.
# Как подключиться к Хранилищу и не потерять текущие изменения
***
1. Нажмите "Конигурация" -> "Расширения конфигурации".

2. Откройте окно с расширениями, выберите своё расширение.

3. Нажмите правой кнопкой мыши на своём расширении и выберите пункт меню "Конфигурация" -> "Сохранить конфигурацию в файл".

4. Выберите место для сохранения и нажмите кнопку "Сохранить".

5. Нажмите правой кнопкой мыши на расширение конфигурации выберите пункт меню "Хранилище конфигурации" -> "Подключится к хранилищу".

6. В окне с предупреждением о замене конфигурации из кдранилища нажмите кнопку "Да".

7. В окне "Подключение к хранилищу Основное" укажите путь где находится Ваше хранилище, напишите Имя пользователя и пароль из хранилища. После чего нажмите "Ок".

8. В окне об успешном подключении к хранилищу нажмите кнопку "Ок".

# Как получить изменения из хранилища
***
## Способ 1
1. Нажмите пункт меню "Конфигурация" -> "Хранилище конфигурации" -> "Сравнить/объединить конфигурацию с хранилищем".

2. Откроется окно "Сравнение, объединение Расширения конфигурации "Основное"" в котором можно посмотреть отличия расширений конфигурации и хранилища. Проведите анализ и установите необходимое объединение. После чего нажмите на кнопку "Выполнить".

## Способ 2
1. Нажмите пункт меню "Конфигурация" -> "Хранилище конфигурации" -> "Обновить конфигурацию из хранилища". Поле чего данные из хранилища обновятся.

# Как добавить новый объект
***
1. Нажмите правой кнопкой мыши на корень расширения конфигурации, и выберите пункт меню "Захватить в хранилище".

2. Нажмите правой кнопкой мыши на объект "Справочники", и выберите пункт меню "Добавить".

3. В результате создастся справочник, который можно менять на свое усмотрение.

# Как отправить изменения в хранилище
***
1. Нажмите правой кнопкой мыши на тот объект, который необходимо поместить в хранилище, и выбериет пункт меню "Поместить в хранилище".

2. Откроется окно с предупреждением о необходимости сохранения. Нажмите кнопку "Да".

3. В окне "Помещение объектов в хранилище расширения конфигурации Основное" можно добавить коментарий перед помещением объекта в хранилище, после чего нажмите кнопку "Ок"

Запустите 1С:Предприятие и создайте новую информационную базу без
конфигурации для загрузки выгруженной ранее информационной базы.
Откройте созданную информационную базу в конфигураторе.
Откройте конфигурацию выполнив команду «Конфигурация» - «Открыть
конфигурацию».
Загрузите каркасную конфигурацию выполнив команду «Загрузить
информационную базу…» из меню «Администрирование».
Откройте расширение конфигурации вызвав команду главного меню
«Конфигурация» – «Расширения конфигурации».
В открывшемся списке расширений откройте расширение «Основное».
Для загрузки списка задач необходимо, чтобы создавался календарь
сотрудника, для того чтобы задача отображалась в разделе «Доски» на форме
«Контакт центр».
В справочник расширения «Проекты» добавьте новый реквизит
«пр_КалендарьСотрудника». Установите тип данных
«СправочникСсылка.КалендариСотрудников», который позволит установить связь данного реквизита со справочником.
Откройте форму элемента справочника «Проекты» и переключитесь на вкладку
«Модуль».
В процедуре «пр_ПриСозданииНаСервереПосле» допишите код программного
размещения реквизита пр_КалендарьСотрудника на форме.
&НаСервере
Процедура пр_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
ПолеФормы = Элементы.Добавить("пр_ИдентификаторПроекта", Тип("ПолеФормы"), Элементы.Реквизиты);
ПолеФормы.Вид = ВидПоляФормы.ПолеВвода;
ПолеФормы.ПутьКДанным = "Объект.пр_ИдентификаторПроекта";
ПолеФормы = Элементы.Добавить("пр_КалендарьСотрудника", Тип("ПолеФормы"), Элементы.Реквизиты);
ПолеФормы.Вид = ВидПоляФормы.ПолеВвода;
ПолеФормы.ПутьКДанным = "Объект.пр_КалендарьСотрудника";
КонецПроцедуры
Чтобы иметь возможность обращаться к значению «ПлатежныйАгент»
перечисления «ПризнакиАгента» из встроенного языка нужно заимствовать в
расширение не только само перечисление, но и его значение.
Заимствуйте значение «ПлатежныйАгент» перечисления «ПризнакиАгента»,
выполнив команду его контекстного меню «Добавить в расширение».
Для предпросмотра данных перед загрузкой необходимо на основании
табличного документа «Список задач.xlsx» создать таблицу на форме обработки
аналогичной структуры.
Имя колонки реквизита Тип Настройка типа
Проект Строка
НазваниеЗадачи Строка
ТекстЗадачи Строка
Статус Строка
Дата Строка
Номер Строка
Исполнитель Строка
Оценка Число Неотрицательное: Истина
ФактическоеВремя Число Неотрицательное: Истина
В обработке должно быть понятно (выделено цветом), какие объекты
невозможно загрузить из-за того, что связанная справочная информация в 1С не
найдена. Ошибка может возникнуть если не найдется соответствия клиента, проекта
и исполнителя.
На вопрос добавить колонки таблицы «ПросмотрДанных» ответьте
положительно. В результате таблица отобразиться на форме.
Перенесите данную команду на вкладку «Элементы» в командную панель
формы, чтобы на форме сформировала кнопка для вызова данной команды.
Аналогично создайте команду «ЗагрузитьДанные» и поместите ее в командной
панели формы.
Откройте свойства элемента «ФормаЗагрузитьДанные» в свойство
«Доступность» снимите флаг.
Откройте свойства формы и в свойстве «УсловноеОформление» и нажмите
ссылку «Открыть».
В окне «Настройка условного оформления» добавьте следующие условия для
оформления. Цвет фона для всех условий установите красный цвет.
Если нет соответствия клиента, проекта или исполнителя с данными
информационной базы, тогда поля Клиент, Проект и Исполнитель выделятся красным
цветом. После того как все условия добавлены нажмите кнопку «ОК».
На вкладке «Элементы» выделите элемент «ПросмотрДанных» и откройте его
свойства. В свойстве «ПоложениеКоманднойПанели» установите «Нет».
Далее следует указать действия у созданных команд. Для этого откройте на
вкладке «Команды» свойства команды «ПросмотретьДанные» и у свойства
«Действие» нажмите на кнопку с изображением лупы.
В окне создания обработчика команды выберите пункт «Создать на клиенте» и
нажмите кнопку «ОК».
Обработка пр_ЗагрузкаСпискаЗадач : Форма(здесь находится кот который написан снизу)
&НаКлиенте
Асинх Процедура ПросмотретьДанные(Команда)
ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
ПараметрыДиалога.Заголовок = "Выберите файл для загрзуки списка задач";
ПараметрыДиалога.Фильтр = "Табличный документ *.xlsx | *.xlsx";
ПараметрыДиалога.МножественныйВыбор = Ложь;
ОписаниеФайла = Ждать ПоместитьФайлНаСерверАсинх(,,,ПараметрыДиалога);
Если ОписаниеФайла<>НЕопределено Тогда
ПрочитатьExcelНаСервере(ОписаниеФайла.Адрес, ОписаниеФайла.СсылкаНаФайл.Расширение);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПрочитатьExcelНаСервере(АдресДанных, РасширениеФайла)
ПутьКФайлу = ПолучитьИмяВременногоФайла(РасширениеФайла);
Данные = ПолучитьИзВременногоХранилища(АдресДанных);
Данные.Записать(ПутьКФайлу);
ПрочитатьExcel_ПостороительЗапроса(ПутьКФайлу);
УдалитьФайлы(ПутьКФайлу);
ПросмотретьДанныеНаОшибки();
КонецПроцедуры
&НаСервере
Процедура ПрочитатьExcel_ПостороительЗапроса(ПутьКФайлу)
ПросмотрДанных.Очистить();
ТабДок = Новый табличныйДокумент;
Попытка
ТабДок.Прочитать(ПутьКФайлу);
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не удалось прочитать файл по причине: " + ОписаниеОшибки();;
Сообщение.Сообщить();
Возврат;
КонецПопытки;
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеисточникаДанных(ТабДок.Область());
Построитель.ЗаполнитьНастройки();
Построитель.Выполнить();
ТаблицаИзExcel = Построитель.Результат.Выгрузить();
ЭтотОбъект.ПросмотрДанных.Загрузить(ТаблицаИзExcel);
КонецПроцедуры
&НаСервере
Процедура ПросмотретьДанныенаОшибки()
ЕстьОшибка = Ложь;
ТекстНеНайденныхДанных = Новый Массив;
ТекстНеНайденныхДанных.Добавить("Информация о ненайденных данных");
ТекстСообщениияОНенайденыхДанных = "Все данные могут быть загруженны";
Для НомерСтроки = 0 По ПросмотрДанных.Количество()-1 Цикл
НовыйКлиент = Справочники.Контрагенты.НайтиПоНаименованию(ПросмотрДанных[НомерСтроки].Клиент);
Если НовыйКлиент = Неопределено Или НовыйКлиент.Пустая() Тогда
ПросмотрДанных[НомерСтроки].НетКлиента = Истина;
КонецЕсли;
НовыйПроект = Справочники.Проекты.НайтиПоНаименованию(ПросмотрДанных[НомерСтроки].Проект);
Если НовыйПроект = Неопределено или Новыйпроект.Пустая() Тогда
ПросмотрДанных[НомерСтроки].НетПроекта = Истина;
КонецЕсли;
НовыйИсполнитель = Справочники.Сотрудники.НайтиПоНаименованию(ПросмотрДанных[НомерСтроки].Исполнитель);
Если НовыйИсполнитель = Неопределено Или НовыйИсполнитель.Пустая()Тогда
ПросмотрДанных[НомерСтроки].Нетисполнителя = Истина;
КонецЕсли;
Если ПросмотрДанных[НомерСтроки].НетИсполнителя = Истина
Или ПросмотрДанных[НомерСтроки].НетПроекта = Истина
Или ПросмотрДанных[НомерСтроки].НетКлиента =Истина Тогда
ТекстНеНайденныхДанных.Добавить("В строке №" + Строка(НомерСтроки+1) + ", не найденый следующие данные: ");
Если ПросмотрДанных[НомерСтроки].нетИсполнителя = Истина Тогда
ТекстНеНайденныхДанных.Добавить("Исполнитель(Сотрудник): " + Строка(ПросмотрДанных[НомерСтроки].Исполнитель));
ПоказатьПолеСНеНайденнымиДанными("сотруднику", НомерСтроки, "Исполнитель");
ЕслтьОшибка = Истина;
КонецЕсли;
Если ПросмотрДанных[НомерСтроки].НетПроекта = Истина Тогда
ТекстНеНайденныхДанных.Добавить(", Проект: " + Строка(ПросмотрДанных[НомерСтроки].Проект));
ПоказатьПолеСНеНайденнымиДанными("проекту", НомерСтроки, "Проект");
КонецЕсли;
Если ПросмотрДанных[НомерСтроки].НетКлиента = Истина Тогда
ТекстНеНайденныхДанных.Добавить(", Клиент: " + Строка(ПросмотрДанных[НомерСтроки].Клиент));
ПоказатьПолеСНеНайденнымиДанными("клиенту", НомерСтроки, "Клиент");
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если ТекстНеНайденныхДанных[0] = "Информация о не найденных данных:" Тогда
ТекстСообщенияОНеНайденныхДанных = СтрСоединить(ТекстНеНайденныхДанных, " ");
КонецЕсли;
Если ЕстьОшибка = Истина Тогда
Элементы.ФормаЗагрузитьДанные.Доступность = Ложь;
Иначе
Элементы.ФормаЗагрузитьДанные.Доступность = Истина;
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПоказатьПолеСНеНайденнымиДанными (НазваниеНеНайденныхДанных, НомерСтроки,НазваниеКолонки)
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не найдены связанные данные по " + НазваниеНенайденныхДанных;
Сообщение.Поле = "ПросмотрДанных[" + XMLСтрока (НомерСтроки) + "]." + НазваниеКолонки;
Сообщение.Сообщить();
КонецПроцедуры
&НаСервере
Процедура ЗагрузитьДанныеНаСервере()
ДанныеДляЗагрузки = ПодготовитьОбщиеДанные();
Если Не ДанныеДляЗагрузки. ОбщиеДанныеПодготовлены Тогда
Возврат;
КонецЕсли;
Для Каждого ТекущаяСтрока Из ЭтотОбъект.ПросмотрДанных Цикл
Попытка
ОбработатьСтрокуДанных (ТекущаяСтрока, ДанныеДляЗагрузки);
Исключение
ОбработатьОшибку(ТекущаяСтрока, ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
КонецПроцедуры
&НаСервере
Функция ПодготовитьОбщиеДанные()
Данные = Новый Структура;
Данные.Вставить("СостояниеЗапланировано", Справочники.СостоянияСобытий.НайтиПоНаименованию("Запланировано"));
Если Данные.СостояниеЗапланировано.Пустая() Тогда
Сообщить("Не найдено состояние 'Запланировано'", СтатусСообщения.Важное);
Данные.Вставить("ОбщиеДанныеПодготовлены", Ложь);
Возврат Данные;
КонецЕсли;
Данные.Вставить("Организация", Справочники.Организации.НайтиПоНаименованию("Ассоль ООО"));
Если Данные.Организация.Пустая() Тогда
Сообщить("Не найдена организация 'Ассоль ООО'", СтатусСообщения.Важное);
Данные.Вставить("ОбщиеДанныеПодготовлены", Ложь);
Возврат Данные;
КонецЕсли;
Данные.Вставить("СтруктурнаяЕдиница", Справочники.СтруктурныеЕдиницы.НайтиПоНаименованию("Администрация"));
Если Данные.СтруктурнаяЕдиница.Пустая() Тогда
Сообщить("Не найдена структурная единица 'Администрация'", СтатусСообщения.Важное);
Данные.Вставить("ОбщиеДанныеПодготовлены", Ложь);
Возврат Данные;
КонецЕсли;
Данные.Вставить("ВидЦен", Справочники.ВидыЦен.НайтиПоНаименованию("Розничная"));
Данные.Вставить("ВидОперации", Перечисления.ВидыОперацийЗаданиеНаРаботу.Внешнее);
Данные.Вставить("КэшСотрудников", Новый Соответствие);
Данные.Вставить("КэшКонтрагентов", Новый Соответствие);
Данные.Вставить("КэшПроектов", Новый Соответствие);
Данные.Вставить("КэшКалендарей", Новый Соответствие);
Данные.Вставить("КэшКолонокКалендарей", Новый Соответствие);
Данные.Вставить("КэшЗаданийНаРаботу", Новый Соответствие);
Данные.Вставить("ОбщиеДанныеПодготовлены", Истина);
Возврат Данные;
КонецФункции
&НаСервере
Процедура ОбработатьСтрокуДанных(ТекущаяСтрока, Данные)
ЗаданиеНаРаботу = СоздатьИлиПолучитьЗаданиеНаРаботу(ТекущаяСтрока, Данные.КэшЗаданийНаРаботу);
Если ЗаданиеНаРаботу = Неопределено Тогда
ВызватьИсключение "Не удалось создать или получить задание на работу";
КонецЕсли;
Сотрудник = ПолучитьИлиСоздатьСотрудника(ТекущаяСтрока.Исполнитель, Данные.КэшСотрудников);
Если Сотрудник = Неопределено Тогда
ВызватьИсключение "Не удалось получить или создать сотрудника";
КонецЕсли;
Контрагент = ПолучитьИлиСоздатьКонтрагента(ТекущаяСтрока.Клиент, Данные.КэшКонтрагентов);
Если Контрагент = Неопределено Тогда
ВызватьИсключение "Не удалось получить или создать контрагента";
КонецЕсли;
Проект = ПолучитьИлиСоздатьПроект(ТекущаяСтрока.Проект, Контрагент, Данные);
Если Проект = Неопределено Тогда
ВызватьИсключение "Не удалось получить или создать проект";
КонецЕсли;
Календарь = ПолучитьИлиСоздатьКалендарь(ТекущаяСтрока.Проект, Данные);
Если Календарь = Неопределено Тогда
ВызватьИсключение "Не удалось получить или создать календарь";
КонецЕсли;
ЗаполнитьИСохранитьВсеОбъекты(ЗаданиеНаРаботу, ТекущаяСтрока, Сотрудник, Проект, Календарь, Данные);
КонецПроцедуры
&НаСервере
Функция СоздатьИлиПолучитьЗаданиеНаРаботу(ТекущаяСтрока, КэшЗаданийНаРаботу)
Если КэшЗаданийНаРаботу[ТекущаяСтрока.Номер] <> Неопределено Тогда
Возврат КэшЗаданийНаРаботу[ТекущаяСтрока.Номер];
КонецЕсли;
ТекущееЗаданиеНаРаботу = Документы.ЗаданиеНаРаботу.НайтиПоНомеру(
ТекущаяСтрока.Номер,
СтрЗаменить(Лев(ТекущаяСтрока.Дата, 10), "-", ""));
Если ТекущееЗаданиеНаРаботу.Пустая() Или ТекущееЗаданиеНаРаботу = Неопределено Тогда
НовыйДокумент = Документы.ЗаданиеНаРаботу.СоздатьДокумент();
КэшЗаданийНаРаботу[ТекущаяСтрока.Номер] = НовыйДокумент;
Возврат НовыйДокумент;
Иначе
СуществующийДокумент = ТекущееЗаданиеНаРаботу.ПолучитьОбъект();
КэшЗаданийНаРаботу[ТекущаяСтрока.Номер] = СуществующийДокумент;
Возврат СуществующийДокумент;
КонецЕсли;
КонецФункции
&НаСервере
Функция ПолучитьИлиСоздатьСотрудника(НаименованиеСотрудника, КэшСотрудников)
Если КэшСотрудников[НаименованиеСотрудника] <> Неопределено Тогда
Возврат КэшСотрудников[НаименованиеСотрудника];
КонецЕсли;
Сотрудник = Справочники.Сотрудники.НайтиПоНаименованию(НаименованиеСотрудника);
Если Сотрудник.Пустая() Или Сотрудник = Неопределено Тогда
Сотрудник = Справочники.Сотрудники.СоздатьЭлемент();
Сотрудник.Наименование = НаименованиеСотрудника;
Сотрудник.Записать();
КонецЕсли;
КэшСотрудников[НаименованиеСотрудника] = Сотрудник;
Возврат Сотрудник;
КонецФункции
&НаСервере
Функция ПолучитьИлиСоздатьКонтрагента(НаименованиеКонтрагента, КэшКонтрагентов)
Если КэшКонтрагентов[НаименованиеКонтрагента] <> Неопределено Тогда
Возврат КэшКонтрагентов[НаименованиеКонтрагента];
КонецЕсли;
Контрагент = Справочники.Контрагенты.НайтиПоНаименованию(НаименованиеКонтрагента);
Если Контрагент.Пустая() Или Контрагент = Неопределено Тогда
Контрагент = Справочники.Контрагенты.СоздатьЭлемент();
Контрагент.Наименование = НаименованиеКонтрагента;
Контрагент.НаименованиеПолное = НаименованиеКонтрагента;
Контрагент.Покупатель = Истина;
Контрагент.Записать();
КонецЕсли;
КэшКонтрагентов[НаименованиеКонтрагента] = Контрагент;
Возврат Контрагент;
КонецФункции
&НаСервере
Функция ПолучитьИлиСоздатьПроект(НаименованиеПроекта, Контрагент, Данные)
// Проверка наличия проекта в оперативном хранилище данных
// Позволяет избежать повторной обработки одинаковых проектов
Если Данные.КэшПроектов[НаименованиеПроекта] <> Неопределено Тогда
Возврат Данные.КэшПроектов[НаименованиеПроекта];
КонецЕсли;
// Поиск проекта в справочнике по точному соответствию наименования
Проект = Справочники.Проекты.НайтиПоНаименованию(НаименованиеПроекта);
// Создание нового проекта с полным набором связанных объектов
Если Проект.Пустая() Или Проект = Неопределено Тогда
Проект = Справочники.Проекты.СоздатьЭлемент();
Проект.Наименование = НаименованиеПроекта;
Проект.Контрагент = Контрагент.Ссылка; // Привязка проекта к конкретному контрагенту
// Создание договора для проекта
Договор = СоздатьИлиПолучитьДоговорКонтрагента(Контрагент, Данные);
Если Договор <> Неопределено Тогда
Проект.Договор = Договор.Ссылка;
КонецЕсли;
// Создание календаря для проекта
Календарь = ПолучитьИлиСоздатьКалендарь(Проект, Данные);
Если Календарь <> Неопределено Тогда
Проект.пр_КалендарьСотрудника = Календарь.Ссылка;
КонецЕсли;
// Сохранение созданного проекта
Проект.Записать();
Иначе
// Если проект существует - открытие объекта для возможного редактирования
// Обеспечивает актуальность данных при повторной обработке
Проект = Проект.ПолучитьОбъект();
КонецЕсли;
// Сохранение ссылки на проект в оперативном хранилище
Данные.КэшПроектов[НаименованиеПроекта] = Проект;
Возврат Проект;
КонецФункции
&НаСервере
Функция СоздатьИлиПолучитьДоговорКонтрагента(Контрагент, Данные)
//{{КОНСТРУКТОР_ЗАПРОСА_С_ОБРАБОТКОЙ_РЕЗУЛЬТАТА
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ДоговорыКонтрагентов.Ссылка КАК Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
|ГДЕ
| ДоговорыКонтрагентов.Владелец = &Владелец";
Запрос.УстановитьПараметр("Владелец", Контрагент.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Ссылка.ПолучитьОбъект();
КонецЕсли;
//}}КОНСТРУКТОР_ЗАПРОСА_С_ОБРАБОТКОЙ_РЕЗУЛЬТАТА
// Создание нового договора с базовыми настройками
Договор = Справочники.ДоговорыКонтрагентов.СоздатьЭлемент();
Договор.Владелец = Контрагент.Ссылка; // Привязка договора к конкретному контрагенту
Договор.Наименование = "Основной договор"; // Типовое наименование для автоматически создаваемых договоров
Договор.ВидДоговора = Перечисления.ВидыДоговоров.СПокупателем; // Установка типа договора
Договор.Организация = Данные.Организация; // Привязка к организации из подготовленных данных
// Установка вида цен при его наличии в общих данных
// Обеспечивает корректное ценообразование в документах
Если Данные.ВидЦен <> Неопределено Тогда
Договор.ВидЦен = Данные.ВидЦен;
КонецЕсли;
// Настройка способов взаимодействия с контрагентом
Договор.СпособВыставленияДокументов = Перечисления.СпособВыставленияДокументов.ЭлектроннаяПочта;
Договор.ПризнакАгента = Перечисления.ПризнакАгента.ПлатежныйАгент;
// Сохранение созданного договора
Договор.Записать();
Возврат Договор;
КонецФункции // СоздатьИлиПолучитьДоговорКонтрагента()
&НаСервере
Функция ПолучитьИлиСоздатьКалендарь(НаименованиеПроекта, Данные)
// Формирование уникального наименования календаря на основе названия проекта
// Обеспечивает понятную идентификацию календаря в системе
НаименованиеКалендаря = "Календарь проекта «" + НаименованиеПроекта + "»";
// Проверка наличия календаря в оперативном хранилище данных
// Исключает повторное создание календарей для одного проекта
Если Данные.КэшКалендарей[НаименованиеКалендаря] <> Неопределено Тогда
Возврат Данные.КэшКалендарей[НаименованиеКалендаря];
КонецЕсли;
// Поиск календаря в справочнике по сформированному наименованию
Календарь = Справочники.КалендариСотрудников.НайтиПоНаименованию(НаименованиеКалендаря);
// Создание нового календаря при его отсутствии в системе
// Настройка базовых параметров для корректной работы
Если Календарь.Пустая() Или Календарь = Неопределено Тогда
// Создание нового элемента справочника календарей сотрудников
Календарь = Справочники.КалендариСотрудников.СоздатьЭлемент();
// Установка наименования календаря в формате "Календарь проекта «НазваниеПроекта»"
Календарь.Наименование = НаименованиеКалендаря;
// Назначение владельца календаря – текущий пользователь системы
// Обеспечивает права доступа и ответственность за календарь
Календарь.ВладелецКалендаря = Справочники.Сотрудники.НайтиПоНаименованию(
ПользователиИнформационнойБазы.ТекущийПользователь().ПолноеИмя).Ссылка;
// Сохранение созданного календарь
// Фиксирует изменения и делает календарь доступным для использования
Календарь.Записать();
КонецЕсли;
// Сохранение ссылки на календарь в оперативном хранилище
// Обеспечивает быстрый доступ к календарю при последующих обращениях
Данные.КэшКалендарей[НаименованиеКалендаря] = Календарь;
Возврат Календарь;
КонецФункции
&НаСервере
Процедура ЗаполнитьИСохранитьВсеОбъекты(ЗаданиеНаРаботу, ТекущаяСтрока, Сотрудник, Проект, Календарь, Данные)
// Начало транзакции - все последующие операции будут выполнены как единое целое
// Обеспечивает согласованность данных при одновременном сохранении нескольких объектов
НачатьТранзакцию();
Попытка
// Заполнение реквизитов документа "Задание на работу" данными из обрабатываемой строки
// Устанавливает связи с сотрудником, проектом и календарем
ЗаполнитьДокументЗаданиеНаРаботу(ЗаданиеНаРаботу, ТекущаяСтрока, Сотрудник, Проект, Календарь, Данные);
// Сохранение и проведение документа "Задание на работу"
ЗаданиеНаРаботу.Записать(РежимЗаписиДокумента.Проведение);
// Создание или обновление записи в календаре сотрудника
// Связывает задание с календарем
ЗаписьКалендаря = СоздатьИлиОбновитьЗаписьКалендаря(ЗаданиеНаРаботу, ТекущаяСтрока, Календарь, Данные);
ЗаписьКалендаря.Записать();
// Фиксация транзакции - все изменения сохраняются
ЗафиксироватьТранзакцию();
Исключение
// Отказ транзакции при возникновении любой ошибки
// Все изменения, выполненные в рамках транзакции, отменяются
ОтменитьТранзакцию();
// Позволяет обработать ошибку на более высоком уровне
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьДокументЗаданиеНаРаботу(ЗаданиеНаРаботу, ТекущаяСтрока, Сотрудник, Проект, Календарь, Данные)
ЗаданиеНаРаботу.Сотрудник = Сотрудник.Ссылка;
ЗаданиеНаРаботу.пр_фактGitLab = ТекущаяСтрока.ФактическоеВремя;
ЗаданиеНаРаботу.пр_ПланGitLab = ТекущаяСтрока.Оценка;
ЗаданиеНаРаботу.Дата = Дата(Лев(ТекущаяСтрока.Дата, 4), Сред(ТекущаяСтрока.Дата, 6, 2), Сред(ТекущаяСтрока.Дата, 9, 2));
Если ЗаданиеНаРаботу.ЭтоНовый() Тогда
ЗаданиеНаРаботу.Номер = ТекущаяСтрока.Номер;
КонецЕсли;
ЗаданиеНаРаботу.ВидОперации = Данные.ВидОперации; // Классификация операции
ЗаданиеНаРаботу.Состояние = Данные.СостояниеЗапланировано; // Установка статуса "Запланировано"
ЗаданиеНаРаботу.Автор = Справочники.Пользователи.НайтиПоНаименованию(
ПользователиИнформационнойБазы.ТекущийПользователь().ПолноеИмя);
ЗаданиеНаРаботу.пр_Проект = Проект.Ссылка; // Привязка к проекту
ЗаданиеНаРаботу.КалендарьСотрудника = Календарь.Ссылка; // Связь с календарем планирования
ЗаданиеНаРаботу.СтруктурнаяЕдиница = Данные.СтруктурнаяЕдиница; // Подразделение исполнителя
ЗаданиеНаРаботу.Организация = Данные.Организация;
Если ЗаданиеНаРаботу.Работы.Количество() = 0 Тогда
НоваяЗаписьРаботы = ЗаданиеНаРаботу.Работы.Добавить();
НоваяЗаписьРаботы.ДатаНачала = Дата(Лев(ТекущаяСтрока.Дата, 4), Сред(ТекущаяСтрока.Дата, 6, 2), Сред(ТекущаяСтрока.Дата, 9, 2));
НоваяЗаписьРаботы.Комментарий = "Название задачи: " + ТекущаяСтрока.НазваниеЗадачи +
Символы.ПС + Символы.ПС + "Текст задачи:" + Символы.ПС + ТекущаяСтрока.ТекстЗадачи;
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция СоздатьИлиОбновитьЗаписьКалендаря(ЗаданиеНаРаботу,ТекущаяСтрока,Календарь,Данные)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ЗаписиКалендаряСотрудника.Ссылка КАК СсылкаЗаписьКалендаряСотрудника
|ИЗ
| Справочник.ЗаписиКалендаряСотрудника КАК ЗаписиКалендаряСотрудника
|ГДЕ
| ЗаписиКалендаряСотрудника.Источник = &Источник";
Запрос.УстановитьПараметр("Источник", ЗаданиеНаРаботу.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Если Выборка.Следующий()Тогда
ЗаписьКалендаря = Выборка.СсылкаЗаписьКалендаряСотрудника.Получитьобъект();
Иначе
ЗаписьКалендаря = Справочники.ЗаписиКалендаряСотрудника.СоздатьЭлемент();
ЗаписьКалендаря.Источник = ЗаданиеНаРаботу.Ссылка;
КонецЕсли;
КолонкаКалендаря = ПолучитьИлиСоздатьКолонкуКалендаря(ТекущаяСтрока.Статус, Календарь, Данные);
Если КолонкаКалендаря <> Неопределено Тогда
ЗаписьКалендаря.КолонкаКалендаря = КолонкаКалендаря;
КонецЕсли;
Возврат ЗаписьКалендаря;
КонецФункции
&НаСервере
Функция ПолучитьИлиСоздатьКолонкуКалендаря (Статус, Календарь, Данные)
КлючКэша = Строка (Календарь.Ссылка.УникальныйИдентификатор()) + Статус;
Если Данные.КэшКолонокКалендарей[КлючКэша] <> Неопределено Тогда
Возврат Данные.КэшКолонокКалендарей[КлючКэша];
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| КолонкиКалендарейСотрудников.Ссылка КАК Ссылка
|ИЗ
| Справочник.КолонкиКалендарейСотрудников КАК КолонкиКалендарейСотрудников
|ГДЕ
| КолонкиКалендарейСотрудников.Наименование = &Наименование
| И КолонкиКалендарейСотрудников.Владелец = &Владелец";
Запрос.УстановитьПараметр("Владелец", Календарь.Ссылка);
Запрос.УстановитьПараметр("Наименование", Статус);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
//}}КОНСТРУКТОР_ЗАПРОСА_С_ОБРАБОТКОЙ_РЕЗУЛЬТАТА
Если Выборка.Следующий() Тогда
Колонка = Выборка.Ссылка;
Иначе
Колонка = Справочники.КолонкиКалендарейСотрудников.СоздатьЭлемент();
Колонка.Наименование = Статус;
Колонка.Владелец = Календарь.Ссылка;
Колонка.Записать();
КонецЕсли;
Данные.КэшКолонокКалендарей[КлючКэша] = Колонка;
Возврат Колонка;
КонецФункции
&НаСервере
Процедура ОбработатьОшибку(ТекущаяСтрока, ТекстОшибки)
Сообщение = "Ошибка при обработке строки с нснерон '" + ТекущаяСтрока.Номер + "':" + ТекстОшибки;
Сообщить(Сообщение, СтатусСообщения.Важное);
ЗаписьЖурналаРегистрации("ЗагрузкаДанных", УровеньЖурналаРегистрации.Ошибка, ,, Сообщение);
КонецПроцедуры
&НаКлиенте
Процедура ЗагрузитьДанные(Команда)
ЗагрузитьДанныеНаСервере();
КонецПроцедуры
---------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
В результате на вкладке «Модуль» создастся заготовка процедуры для описания
логики работы команды «ПросмотретьДанные».
В процедуре напишите код, который открывает диалоговое окно выбора файла
Excel с фильтром на расширение .xlsx. Также допишите перед словом «Процедура»
ключевое слово «Асинх», чтобы указать, что процедура поддерживает асинхронный
режим выполнения и может содержать операторы «Ждать» для работы с
асинхронными вызовами.
Ниже процедуры «ПросмотретьДанные» напишите слово «директ» и нажмите
комбинацию клавиш Ctrl+Q. В результате откроется окно для выбора директивы
компиляции. Выберите директиву «НаСервере».
В результате в модуль обработки установится директива НаСервере.
Ниже директивы НаСервере напишите слово «проц» и нажмите комбинацию
клавиш Ctrl+Q. В результате откроется окно для выбора используемого шаблона.
Выберите директиву пункт «Процедура».
В окне «Процедура» задайте заголовок процедуры
«ПрочитатьExcelНаСервере», которая вызывается в процедуре
«ПросмотретьДанные». В результате создастся заготовка процедуры
«ПрочитатьExcelНаСервере».
В процедуре «ПрочитатьExcelНаСервере» укажите в скобках параметры
АдресДанных и РасширениеФайла.
В процедуре «ПрочитатьExcelНаСервере» напишите код, который выполняет
чтение и обработку данных из файла Excel на сервере, включая извлечение данных из
рабочих листов, преобразование в структуры данных 1С и валидацию полученной
информации.
Создайте процедуру «ПрочитатьExcel_ПостроительЗапроса» на сервере и
напишите ее код, который выполняет чтение данных из файла Excel, преобразует их
в структурированную таблицу значений с помощью построителя запроса и загружает
результат в форму для просмотра и дальнейшей обработки.
Создайте процедуру «ПросмотретьДанныеНаОшибки» на сервере и
напишите ее код, который выполняет валидацию загруженных из Excel данных,
проверяет существование элементов в справочниках системы, формирует
детализированные сообщения об ошибках и управляет доступностью кнопки
загрузки данных в зависимости от результатов проверки.
Создайте процедуру «ПоказатьПолеСНеНайденнымиДанными» на сервере и
напишите ее код, который создает и отображает сообщения об ошибке, которое
указывает на конкретное поле в таблице с не найденными справочными данными.
Рассмотрим алгоритм работы загрузки данных, который представлен на
рисунке.
Алгоритм загрузки данных представляет собой четко структурированный
процесс, разделенный на три последовательных этапа, реализованных в виде 14
процедур и функций.
На первом этапе подготовки и инициализации выполняется базовая настройка
системы.
Главная процедура «ЗагрузитьДанныеНаСервере» запускает весь процесс
загрузки, организует цикл обработки строк данных, обрабатывает ошибки и
финализирует процесс уведомлением пользователя.
Функция «ПодготовитьОбщиеДанные» отвечает за первоначальную загрузку
данных используемых справочников, включая состояние «Запланировано»,
организацию «Ассоль ООО», структурную единицу «Администрация», вид цен
«Розничная» и вид операции документа. Одновременно создаются кэши для
ускорения последующих операций: кэш сотрудников, кэш контрагентов, кэш
проектов, кэш календарей и кэш заданий на работу. Важной частью этого этапа
является проверка наличия критически важных данных, без которых дальнейшая
работа невозможна.
Второй этап представляет собой обработку каждой строки данных.
Процедура «ОбработатьСтрокуДанных» координирует создание всех
связанных объектов для одной строки, последовательно вызывая
специализированные функции.
Функция «СоздатьИлиПолучитьЗаданиеНаРаботу» работает с документами,
проверяя кэш на наличие уже обработанных документов, осуществляя поиск
существующих документов по номеру и создавая новые при необходимости, с
обязательным кэшированием результатов.
Функции «ПолучитьИлиСоздатьСотрудника» и
«ПолучитьИлиСоздатьКонтрагента» аналогичным образом работают с
соответствующими справочниками, используя кэширование для оптимизации
производительности.
Наиболее сложной является функция «ПолучитьИлиСоздатьПроект», которая
не только ищет существующие проекты по наименованию, но и при их отсутствии
автоматически создает объекты: новый проект, договор для контрагента через
функцию «СоздатьИлиПолучитьДоговорКонтрагента» и календарь проекта через
функцию «ПолучитьИлиСоздатьКалендарь».
Функция создания календаря формирует календарь с именем «Календарь
проекта [ИмяПроекта]» и назначает владельцем текущего пользователя.
Ключевой процедурой этого этапа является
«ЗаполнитьИСохранитьВсеОбъекты», которая обеспечивает транзакционность
операций. Она начинает транзакцию, заполняет документ данными через процедуру
«ЗаполнитьДокументЗаданиеНаРаботу», записывает и проводит документ, создает
запись календаря через функцию «СоздатьИлиОбновитьЗаписьКалендаря» и
фиксирует транзакцию при успешном выполнении. При возникновении любых
ошибок выполняется откат транзакции.
Процедура «ЗаполнитьДокументЗаданиеНаРаботу» ответственна за установку
всех полей документа, включая сотрудника, проект, календарь, фактические и
плановые трудозатраты, даты, номер и автора, а также добавляет работы в табличную
часть.
Функция «СоздатьИлиОбновитьЗаписьКалендаря» ищет существующие
записи календаря для документа или создает новые, обеспечивая связь между
записью и документом.
Дополнительная функция «ПолучитьИлиСоздатьКолонкуКалендаря»
настраивает колонки календаря для различных статусов с использованием
кэширования.
Третий этап посвящен финализации и обработке ошибок.
Процедура «ОбработатьОшибку» обеспечивает надежную обработку
исключительных ситуаций, формируя понятные сообщения об ошибках, выводя
уведомления пользователю и записывая детали в журнал регистрации. Важной
особенностью является возможность продолжения обработки следующих строк
данных даже при возникновении ошибок в отдельных строках.
Алгоритм построен на ключевых принципах кэширования для избежания
повторных поисков, транзакционности для обеспечения целостности данных,
модульности для удобства сопровождения и обработки ошибок для повышения
надежности системы. Такой подход гарантирует эффективную и устойчивую
обработку значительных объемов информации.
Создайте действие у команды «ЗагрузитьДанные». Для этого откройте на
вкладке «Команды» свойства команды «ЗагрузитьДанные» и у свойства «Действие»
нажмите на кнопку с изображением лупы. В окне создания обработчика команды
выберите пункт «Создать на клиенте и процедуру на сервере» и нажмите кнопку
«ОК».
В процедуре «ЗагрузитьДанныеНаСервере» напишите код и ознакомьтесь с
комментариями.
После основных процедур создайте серверную функцию
«ПодготовитьОбщиеДанные», напишите код и ознакомьтесь с комментариями.
После основных процедур создайте серверную процедуру
«ОбработатьСтокуДанных», напишите код и ознакомьтесь с комментариями.
После основных процедур создайте серверную функцию
«СоздатьИлиПолучитьЗаданиеНаРаботу», напишите код и ознакомьтесь с
комментариями.
После основных процедур создайте серверную функцию
«ПолучитьИлиСоздатьСотрудника», напишите код и ознакомьтесь с комментариями.
После основных процедур создайте серверную функцию
«ПолучитьИлиСоздатьКонтрагента», напишите код и ознакомьтесь с
комментариями.
После основных процедур создайте серверную функцию
«ПолучитьИлиСоздатьПроект», напишите код и ознакомьтесь с комментариями.
После всех процедур напишите слово «директ» и нажмите комбинацию клавиш
Ctrl+Q. В результате отобразиться окно с выбором директивы компиляции. Выберите
директиву «НаСервере».
На следующей строке напишите слово «функ» и нажмите комбинацию клавиш
Ctrl+Q. В результате отобразиться окно с выбором шаблона. Выберите шаблон
«Функция».
В окне «Функция» укажите имя функции
«СоздатьИлиПолучитьДоговорКонтрагента».
В результате создастся заготовка функции.
В скобках укажите входные параметры «Контрагент» - объект контрагента, для
которого осуществляется поиск или создание договора и «Данные» - структура с
подготовленными общими данными.
Для поиска первого подходящего договора контрагента или создания нового с
типовыми настройками необходимо построить запрос. Для этого нажмите правой
кнопкой мыши и в меню выберите команду «Конструктор запроса с обработкой
результата…»
На вопрос «Создать новый запрос?» ответьте положительно.
В окне «Конструктора запроса с обработкой результата» перейдите на вкладку
«Таблицы и поля». Выберите поле «Ссылка» из справочника
«ДоговорыКонтрагентов».
На вкладке «Условия» двойным щелчком левой кнопкой мыши поместите поле
«Владелец».
На вкладке «Дополнительно» установите переключатель «Первые».
При нажатии на кнопку «ОК» появиться окно на добавление используемых
объектов в расширение. Ответьте положительно.
В результате в коде функции сформируется текст запроса.
В строке, где передаются параметры в запрос измените значение параметра, по
которому необходимо выбрать договора. Замените обходе результата запроса цикл
«Пока» на условную конструкцию и продолжите писать код процедуры, который
осуществляет создание нового договора при отсутствии существующих и заполняет
обязательные реквизиты договора.
После основных процедур создайте серверную функцию
«ПолучитьИлиСоздатьКалендарь», напишите код и ознакомьтесь с комментариями.
После основных процедур создайте серверную процедуру
«ЗаполнитьИСохранитьВсеОбъекты», напишите код и ознакомьтесь с
комментариями.
После основных процедур создайте серверную процедуру
«ЗаполнитьДокументЗаданиеНаРаботу», напишите код и ознакомьтесь с
комментариями.
После основных процедур создайте заготовку серверной функции
«СоздатьИлиОбновитьЗаписьКалендаря» в скобках укажите входные параметры
«ЗаданиеНаРаботу» - объект документа, для которого создается запись календаря,
«ТекущаяСтрока» - структура с исходными данными, включая статус задачи,
«Календарь» - объект календаря для привязки записи, «Данные» - структура с
подготовленными общими данными и кэшами.
Для поиска существующей записи календаря для задания на работу необходимо
построить запрос. Для этого нажмите правой кнопкой мыши и в меню выберите
команду «Конструктор запроса с обработкой результата…»
На вопрос «Создать новый запрос?» ответьте положительно.
В окне «Конструктора запроса с обработкой результата» перейдите на вкладку
«Таблицы и поля». Выберите поле «Ссылка» из справочника
«ЗаписиКалендаряСотрудника».
На вкладке «Условия» задайте условие.
На вкладке «Объединения/Псевдонимы» задайте псевдоним полю.
На вкладке «Дополнительно» установите переключатель «Первые».
При нажатии на кнопку «ОК» появиться окно на добавление используемых
объектов в расширение. Ответьте положительно.
В результате в коде процедуры сформируется текст запроса.
Откорректируйте полученный код с помощью конструктора и продолжите
писать код функции, который обеспечивает создание новой записи календаря при
отсутствии существующей, организует получение или создание колонки календаря
на основе статуса задачи, выполняет привязку колонки календаря к записи для
визуального размещения, обеспечивает возврат готовой записи календаря с
установленными связями, гарантирует обновление существующих записей при
повторной обработке данных.
После основных процедур создайте серверную функцию
«ПолучитьИлиСоздатьКолонкуКалендаря» и напишите код, который реализует
подход гарантированного получения колонки календаря по статусу задачи и
выполняет формирование уникального ключа кэширования на основе календаря и
статуса.
Для поиска колонки календаря необходимо построить запрос. Для этого
нажмите правой кнопкой мыши и в меню выберите команду «Конструктор запроса с
обработкой результата…». На вопрос «Создать новый запрос?» ответьте
положительно.
В окне «Конструктора запроса с обработкой результата» перейдите на вкладку
«Таблицы и поля». Выберите поле «Ссылка» из справочника
«КолонкиКалендарейСотрудников».
На вкладке «Условия» задайте два условия.
На вкладке «Дополнительно» установите переключатель «Первые».
При нажатии на кнопку «ОК» появиться окно на добавление используемых
объектов в расширение. Ответьте положительно. В результате в коде процедуры
сформируется текст запроса. Откорректируйте полученный код и продолжите писать
код функции, который связывает задачи с календарем сотрудников, создавая
недостающие элементы, и финализирует загрузку данных.
После основных процедур создайте серверную процедуру
«ОбработатьОшибку», напишите код и ознакомьтесь с комментариями.
---------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
Запустите режим пользователя и откройте подсистему «Работы». В разделе
«Сервис» нажмите на строку «Загрузка списка задач».
В обработке нажмите на кнопку «Просмотреть данные». В диалоговом окне
выбора файла выберите файл «Список задач.xlsx» и нажмите кнопку «Открыть».
Если связанные данные не будут найдены, то в таблице ячейки выделятся
красным цветом, будут видны сообщения о не найденных данных. В этом случае
данные не загрузятся.
По условию задачи предполагается, что информация по сотрудникам на момент
загрузки уже введена в базу 1С. В связи с этим добавьте вручную не найденных
сотрудников. После добавления всех сотрудников будет доступна кнопка «Загрузить
данные».
Нажмите на кнопку «Загрузить данные». После того как данные будут
загружены появиться сообщение «Данные загружены».
Проверьте загрузились ли данные.
Откройте справочник «Контрагенты» из подсистемы «CRM». Откройте форму
элемента контрагента. Должно быть заполнено поле «Наименование». Далее
перейдите по ссылке «Договоры» и проверьте, что создался договор с контрагентом.
Откройте справочник «Проекты» из подсистемы «Работы». Откройте форму
элемента проекта. Должны быть заполнены поля «Наименование», «Контрагент»,
«Договор», «Календарь сотрудника».
Откройте документы «Задания на работу» из подсистемы «Работы» и
убедитесь, что все данные загрузились и документы проведены.
Откройте форму «Контакт-центр» из подсистемы «CRM» и нажмите на кнопку
«Доски».
Откройте доску и проверьте что создалась колонка календаря и в ней
отображаются задания на работу.
Задача 1.5 Анализ механизма распределения расходов на финансовый результат
Откройте типовую базу УНФ и изучите механизм распределения расходов на
финансовый результат.
Заготовка для проведения исследования представлена в общей папке задания.
Вам необходимо описать алгоритм операции. Рассчитать финансовый результат в
Закрытии месяца.
Решение
Создайте текстовый документ, следующего содержания.
Название работы: Описание архитектуры решения: Расчет финансового
результата.
Раздел 1: Поиск алгоритма и ключевые объекты
1.1. Ключевой объект метаданных
Вопрос: Какой объект метаданных (документ, справочник, обработка и т.д.) в
конечном итоге выполняет расчет и формирует движения в регистрах при расчете
финансового результата?
[ОТВЕТ]:
Тип объекта: Документ
Имя объекта: ЗакрытиеМесяца
1.2. Основные методы
Вопрос: Какие процедуры/функции отвечают за необходимый алгоритм?
[ОТВЕТ]:
Процедура РассчитатьФинансовыйРезультат
Функция
СформироватьТаблицуБазыРаспределенияФинансовогоРезультата
Раздел 2: Общее описание алгоритма
2.1. Назначение процедуры
Вопрос: Теперь, когда вы нашли основную процедуру, опишите в 1-2
предложениях: какую главную бизнес-задачу она решает?
[ОТВЕТ]:
Главная бизнес-задача процедуры — выполнить закрытие счетов доходов
и расходов за отчетный период. Алгоритм рассчитывает итоговый финансовый
результат (прибыль или убыток), перенося обороты с временных счетов (90, 91
и т.д.) на счет учета прибыли и убытков (99).
2.2. Основные этапы
Вопрос: На какие два больших логических этапа можно разделить основную
процедуру?
[ОТВЕТ]:
Этап 1: Прямое отнесение. На этом этапе обрабатываются доходы и
расходы, которые можно однозначно и напрямую отнести на финансовый
результат конкретного направления деятельности без дополнительных расчетов.
Этап 2: Распределение косвенных расходов. На этом этапе
обрабатываются расходы (как правило, общехозяйственные), которые нельзя
отнести напрямую. Они распределяются пропорционально между различными
аналитиками (направлениями деятельности, проектами и т.д.) согласно
заданным правилам.
Раздел 3: Работа с данными (Регистры)
3.1. Источники данных (Чтение)
Вопрос: Перечислите, из каких регистров алгоритм читает информацию для
проведения расчетов.
[ОТВЕТ]:
РегистрНакопления.ДоходыИРасходы – основной источник данных, из
него читаются обороты по всем доходам и расходам, подлежащим закрытию.
РегистрНакопления.Продажи – используется для получения данных
(выручка, себестоимость, количество) при расчете базы для распределения
косвенных расходов.
3.2. Результаты (Запись)
Вопрос: Перечислите, в какие регистры алгоритм записывает результаты своей
работы.
[ОТВЕТ]:
РегистрыНакопления.ФинансовыйРезультат – сюда записываются
итоговые суммы доходов и расходов в разрезе аналитик для последующего
анализа и построения отчетов.
РегистрыБухгалтерии.Управленческий – в этот регистр записываются
непосредственно бухгалтерские проводки, которые формируют финансовый
результат на счетах управленческого учета.
Раздел 4: Детальный анализ алгоритма
4.1. Какие управленческие проводки (Дт/Кт) формируются?
Вопрос: Проанализируйте блок кода, обрабатывающий данные. Какие
управленческие проводки (Дт/Кт) формируются?
[ОТВЕТ]:
Алгоритм формирует два типа стандартных закрывающих проводок:
Для доходов: Дт [Счет учета доходов] Кт [Счет учета
прибыли/убытков]
Для расходов: Дт [Счет учета прибыли/убытков] Кт [Счет учета
расходов]
4.2. Какие есть главные ветки выполнения
Вопрос: Проанализируйте какие есть главные ветки выполнения (их 2), чем они
отличаются, почему нужны 2 ветки.
[ОТВЕТ]:
Алгоритм содержит две ключевые ветки (этапа), которые обрабатывают
разные типы доходов и расходов:
1) Первая ветка (прямое отнесение):
Чем отличается: Она отбирает записи, у которых в счете учета указан
способ распределения "Не распределять", либо счет учета напрямую
соответствует счету выручки/себестоимости из настроек направления
деятельности.
Почему нужна: Эта ветка нужна для быстрой и простой обработки тех
сумм, которые уже содержат всю необходимую аналитику. Например, выручка
от продажи конкретного товара по конкретному заказу — ее можно сразу
отнести на финансовый результат этого направления/заказа.
2) Вторая ветка (распределение):
Чем отличается: Она отбирает записи, у которых способ
распределения НЕ равен "Не распределять". Это косвенные расходы, такие как
аренда офиса, зарплата администрации и т.п., которые относятся ко всей
деятельности компании.
Почему нужна: Эта ветка необходима, так как косвенные расходы
нельзя отнести на какое-то одно направление. Их нужно справедливо
"размазать" по всем направлениям, которые приносили доход. Для этого
рассчитывается специальная "база распределения" (например, выручка или
валовая прибыль), и расход делится пропорционально этой базе. Без этого
механизма невозможно было бы корректно рассчитать рентабельность каждого
направления деятельности.
Сохраните документ указав имя «Алгоритм расчета финансового
результата при Закрытии месяца».
Глава 3. Развитие финансового учета расходов по проектам
Решение
Для переноса плана счетов «Управленческий» из типовой конфигурации в
расширение выполните следующие действия:
1) В дереве конфигурации типовой базы данных найдите объект План счетов
«Управленческий».
2) Щёлкните по нему правой кнопкой мыши.
3) В открывшемся контекстном меню выберите команду «Добавить в
расширение».
В результате план счетов «Управленческий» отобразиться в расширении.
Заимствуйте подсистему «Компания» из типовой конфигурации в расширение.
Заимствуйте справочник «СтруктурныеЕдиницы» из типовой конфигурации в
расширение.
Заимствуйте перечисление «БазыРаспределенияРасходов» из типовой
конфигурации в расширение.
В перечисление «БазыРаспределенияРасходов» добавьте новое значение
«пр_ПоСпискуПроектов» (синоним «По списку проектов»).
Создайте в расширении документ «пр_ПравилаРаспределения» (синоним
«Правила распределения») с реквизитами и табличной частью, свойства реквизитов
представлены в таблице.
Имя Тип
ДатаРаспределенияРасходов Дата
Состав даты: Дата
СпособРаспределения ПеречислениеСсылка.БазыРаспределенияРасходов
Табличная часть «ПроектыДляРаспределенияРасходов»
Проект СправочникСсылка.Проекты
Переключитесь на вкладку «Подсистемы» и включите документ
«пр_ПравилаРаспределения» в подсистему «Компания».
Переключитесь на вкладку «Формы» и создайте форму документа.
В результате откроется окно формы документа. Щелкните на элемент «Форма»
правой кнопкой мыши и в контекстном меню выберите пункт «События». Среди
предложенных событий выберите «ПриСозданииНаСервере».
Откроется модуль формы, в котором будет представлен шаблон процедуры. В
теле процедуры «ПриСозданииНаСервере» напишите код, который позволяет
включить для документа историю изменений.
Заимствуйте перечисление «ТипыХраненияФайлов»,
«СтатусыИзвлеченияТекстаФайлов» из типовой конфигурации в расширение.
Заимствуйте справочники «ИдентификаторыОбъектовМетаданных»,
«ТомаХраненияФайлов», «ИдентификаторыОбъектовРасширений» из типовой
конфигурации в расширение.
Скопируйте любой справочник из типовой конфигурации с окончанием в имени
«ПрисоединенныеФайлы» и вставьте в расширение.
Откройте скопированный справочник из расширения, задайте имя
«пр_ПравилаРаспределенияПрисоединенныеФайлы» синоним «Присоединенные
файлы (Правила распределения)» комментарий пустой, представление объекта пусто.
У реквизита «ВладелецФайла» справочника
«пр_ПравилаРаспределенияПрисоединенныеФайлы» установите тип
«ДокументСсылка.пр_ПравилаРаспределения».
Перейдите на вкладку «Поле ввода» с свойств «ВводПоСтроке» нажмите на
кнопку с многоточием и в окне «Поля ввода по строке» оставьте в разделе
«Выбранные поля» только реквизит «Наименование».
Нажмите на кнопку «ОК» в результате ввод по строке будет работать только по
наименованию справочника.
Заимствуйте из ветки «Общие» из раздела «Подписки на события» подписки
«ПереопределитьПолучаемуюФормуПрисоединенногоФайла» и
«ЗаписатьВерсиюДокумента» из типовой конфигурации в расширение.
У заимствованной подписки
«ПереопределитьПолучаемуюФормуПрисоединенногоФайла» установите источник
«СправочникМенеджер.пр_ПравилаРаспределенияПрисоединенныеФайлы».
У заимствованной подписки «ЗаписатьВерсиюДокумента» установите
источник «ДокументОбъект.пр_ПравилаРаспределения».
Заимствуйте определяемый тип «ВладелецЗначенийКлючейДоступа» из
типовой конфигурации в расширение.
При заимствовании составного типа, в котором присутствует ссылочный тип,
тип не заимствуется, поэтому необходимо указать тип самостоятельно.
Подробнее о типах вызова можно прочитать в руководстве разработчика раздел
5.5.11. Определяемые типы (https://its.1c.ru/db/v8327doc#bookmark:dev:TI000000236).
Установите тип «ДокументСсылка.пр_ПравилаРаспределения».
Заимствуйте определяемый тип «ВладелецЗначенийКлючейДоступаОбъект» из
типовой конфигурации в расширение. Установите тип
«СправочникОбъект.пр_ПравилаРаспределенияПрисоединенныеФайлы».
Заимствуйте определяемый тип «ВладелецПрисоединенныхФайлов» из
типовой конфигурации в расширение. Установите тип
«ДокументСсылка.пр_ПравилаРаспределения».
Заимствуйте определяемый тип «ВладелецПрисоединенныхФайловОбъект» из
типовой конфигурации в расширение. Установите тип
«ДокументОбъект.пр_ПравилаРаспределения».
Заимствуйте определяемый тип «ПрисоединенныйФайл» из типовой
конфигурации в расширение. Установите тип
«СправочникСсылка.пр_ПравилаРаспределенияПрисоединенныеФайлы».
Заимствуйте определяемый тип «ПрисоединенныйФайлОбъект» из типовой
конфигурации в расширение. Установите тип
«СправочникОбъект.пр_ПравилаРаспределенияПрисоединенныеФайлы».
Заимствуйте определяемый тип «ВерсионируемыеДанные» из типовой
конфигурации в расширение. Установите тип
«ДокументСсылка.пр_ПравилаРаспределения».
В типовой конфигурации найдите в ветке «Общие» – «Общие модули» модуль
«ОбщегоНазначения» и откройте его.
Для включения функции «ИдентификаторОбъектаМетаданных» в расширение
выполните следующие действия:
в общем модуле «ОбщегоНазначения» найдите в дереве методов функцию
«ИдентификаторОбъектаМетаданных»;
щелкните по названию функции правой кнопкой мыши;
в появившемся контекстном меню выберите пункт «Добавить в
расширение».
В окне «Тип вызова» установите переключатель «Вызвать вместо (с
контролем)». Подробнее о типах вызова можно прочитать в руководстве
разработчика раздел 30.4.2.2.5. Точечная модификация метода (аннотация
ИзменениеИКонтроль) – (https://its.1c.ru/db/v8327doc#bookmark:dev:TI000002149).
&ИзменениеИКонтроль("ИдентификаторОбъектаМетаданных")
Функция пр_ИдентификаторОбъектаМетаданных(ОписаниеОбъектаМетаданных, ВызыватьИсключение)
#Вставка
Если ТипЗнч(ОписаниеОбъектаМетаданных) = Тип("Строка") Тогда
ИдентификаторРасширения = Справочники.ИдентификаторыОбъектовРасширений.НайтиПоНаименованию(ОписаниеОбъектаМетаданных, Истина);
Если ЗначениеЗаполнено(ИдентификаторРасширения) Тогда
Возврат ИдентификаторРасширения;
КонецЕсли;
КонецЕсли;
#КонецВставки
Возврат Справочники.ИдентификаторыОбъектовМетаданных.ИдентификаторОбъектаМетаданных(
ОписаниеОбъектаМетаданных, ВызыватьИсключение);
КонецФункции
После добавления функции «ИдентификаторОбъектаМетаданных» в
расширение, необходимо модифицировать её код, чтобы добавить дополнительный
функционал. Для этого следует использовать директивы предпроцессора, которые
позволяют организовать вставку нового кода в строго определённое место
существующей функции.
Требуется реализовать следующую логику:
если в функцию передана строка с именем объекта метаданных, выполнить
поиск соответствующего идентификатора в справочнике
«ИдентификаторыОбъектовРасширений»;
при успешном нахождении записи вернуть найденный идентификатор;
если поиск не дал результатов или тип параметра не является строкой,
продолжить выполнение оригинальной логики функции.
Директивы #Вставка и #КонецВставки определяют блок кода, который будет
добавлен в оригинальную функцию. Новый код проверяет тип параметра и выполняет
поиск в справочнике расширений. Если поиск успешен, функция возвращает
найденное значение, не выполняя оригинальный код. В противном случае
выполняется стандартная логика исходной функции.
Такой подход позволяет расширить функциональность без нарушения
существующей логики работы системы.
Задание 3.2. Реализация основной бизнес-логики
Механизм распределения расходов:
Система должна поддерживать два сценария распределения косвенных
расходов пропорционально выручке:
Типовой сценарий: Расход распределяется на все проекты.
Новый сценарий: Расход распределяется только на определенный список
проектов, заданный пользователем.
Для реализации нового сценария вам необходимо:
Создать новый способ распределения в системе.
Разработать гибкий механизм, в котором пользователь сможет создавать и
настраивать правила распределения и выбирать новый способ для нужных расходов
Новый механизм должен быть бесшовно встроен в типовой документ
«Закрытие месяца».
Решение
Для того чтобы добавить в список выбора на форме счета «Управленческий»
новый вид распределения расходов «пр_ПоСпискуПроектов» необходимо:
в конфигураторе найдите план счетов «Управленческий»;
откройте форму счета;
в модуле формы найдите процедуру «УправлениеФормой»;
вызовите контекстное меню на названии процедуры;
выберите пункт «Добавить в расширение»;
укажите тип вызова: «Вызвать вместо (с контролем)».
В результате в расширении будет создана процедура-замещение, которая
позволит модифицировать стандартное поведение формы.
Добавьте код для включения нового вида распределения расходов в интерфейс
формы с помощью директив #Вставка и #КонецВставки.
&НаКлиенте
&ИзменениеИКонтроль("УправлениеФормой")
Процедура пр_УправлениеФормой()
// Прочие расчеты
Элементы.АналитикаДоходовИРасходов.Видимость = Ложь;
// Конец Прочие расчеты
Если Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.КосвенныеЗатраты") Тогда
Элементы.СчетЗакрытия.Видимость = Истина;
Элементы.СпособРаспределения.Видимость = Истина;
Элементы.СпособРаспределения.СписокВыбора.Очистить();
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.ОбъемВыпуска"));
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.ПрямыеЗатраты"));
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.НеРаспределять"));
Элементы.СчетЗакрытия.Подсказка = ?(
ИспользоватьБюджетирование,
НСтр("ru='Счет автоматического закрытия при закрытии месяца и бюджетировании'"),
НСтр("ru='Счет автоматического закрытия при закрытии месяца'"));
Элементы.СпособРаспределения.Подсказка = НСтр(
"ru='Способ автоматического распределения на себестоимость выпущенной продукции при закрытии месяца'");
ИначеЕсли Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.НезавершенноеПроизводство") Тогда
Элементы.СчетЗакрытия.Видимость = Истина;
Элементы.СпособРаспределения.Видимость = Истина;
Элементы.СпособРаспределения.СписокВыбора.Очистить();
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.ОбъемВыпуска"));
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.ПрямыеЗатраты"));
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.НеРаспределять"));
Элементы.СчетЗакрытия.Подсказка = ?(
ИспользоватьБюджетирование,
НСтр("ru='Счет автоматического закрытия при закрытии месяца и бюджетировании'"),
НСтр("ru='Счет автоматического закрытия при закрытии месяца'"));
Элементы.СпособРаспределения.Подсказка = НСтр(
"ru='Способ автоматического распределения на себестоимость выпущенной продукции при закрытии месяца для нематериальных затрат'");
ИначеЕсли (ТипСчета <> ПредопределенноеЗначение("Перечисление.ТипыСчетов.ПрочиеДоходы")
ИЛИ ТипСчета <> ПредопределенноеЗначение("Перечисление.ТипыСчетов.ПрочиеРасходы")
ИЛИ ТипСчета <> ПредопределенноеЗначение("Перечисление.ТипыСчетов.Расходы")
ИЛИ ТипСчета <> ПредопределенноеЗначение("Перечисление.ТипыСчетов.ПроцентыПоКредитам")
ИЛИ ТипСчета <> ПредопределенноеЗначение("Перечисление.ТипыСчетов.Доходы"))
И (Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.ПрочиеДоходы")
ИЛИ Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.ПрочиеРасходы")
ИЛИ Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.Расходы")
ИЛИ Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.ПроцентыПоКредитам")
ИЛИ Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.Доходы")) Тогда
Элементы.СчетЗакрытия.Видимость = Ложь;
Элементы.СпособРаспределения.Видимость = Истина;
Элементы.СпособРаспределения.СписокВыбора.Очистить();
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.ОбъемПродаж"));
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.ВыручкаОтПродаж"));
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.СебестоимостьПродаж"));
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.ВаловаяПрибыль"));
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.НеРаспределять"), НСтр("ru = 'Прямое распределение'"));
#Вставка
Элементы.СпособРаспределения.СписокВыбора.Добавить(ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.пр_ПоСпискуПроектов"));
#КонецВставки
Элементы.СпособРаспределения.Подсказка = ?(
ИспользоватьБюджетирование,
НСтр("ru='Способ автоматического распределения на финансовый результат при закрытии месяца и бюджетировании'"),
НСтр("ru='Способ автоматического распределения на финансовый результат при закрытии месяца'"));
// Прочие расчеты
Если Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.ПрочиеДоходы")
ИЛИ Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.ПрочиеРасходы")
ИЛИ Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.КосвенныеЗатраты")
ИЛИ Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.НезавершенноеПроизводство")
ИЛИ Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.Расходы")
ИЛИ Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.ПроцентыПоКредитам")
ИЛИ Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.НераспределеннаяПрибыль") Тогда
Элементы.АналитикаДоходовИРасходов.Видимость = Истина;
Иначе
Элементы.АналитикаДоходовИРасходов.Видимость = Ложь;
КонецЕсли;
// Конец Прочие расчеты
// Прочие расчеты
ИначеЕсли Объект.ТипСчета = ПредопределенноеЗначение("Перечисление.ТипыСчетов.ПрочиеОборотныеАктивы") Тогда
Элементы.АналитикаДоходовИРасходов.Видимость = Истина;
Элементы.СпособРаспределения.Видимость = Ложь;
Элементы.СчетЗакрытия.Видимость = Ложь;
// Конец Прочие расчеты
Иначе
Элементы.СпособРаспределения.Видимость = Ложь;
Элементы.СчетЗакрытия.Видимость = Ложь;
КонецЕсли;
Элементы.Фильтр.Видимость = Объект.СпособРаспределения = ПредопределенноеЗначение("Перечисление.БазыРаспределенияРасходов.ПрямыеЗатраты");
КонецПроцедуры
Для того чтобы добавить распределение расходов в механизм закрытие месяца
необходимо внести модификацию в функцию
«СформироватьТаблицуБазыРаспределенияФинансовогоРезультата» необходимо:
в конфигураторе откройте документ «ЗакрытиеМесяца»;
откройте вкладку «Прочие»;
нажмите на кнопку «Модуль объекта»;
в модуле объекта найдите процедуру
«СформироватьТаблицуБазыРаспределенияФинансовогоРезультата»;
вызовите контекстное меню на названии процедуры;
выберите пункт «Добавить в расширение»;
укажите тип вызова: «Вызвать вместо (с контролем)».
Добавьте код с помощью директив #Вставка и #КонецВставки, который
выполняет поиск действующих правил распределения расходов на конец месяца и
формирует фильтр по проектам в соответствии с выбранным способом
распределения.
&ИзменениеИКонтроль("СформироватьТаблицуБазыРаспределенияФинансовогоРезультата")
Функция пр_СформироватьТаблицуБазыРаспределенияФинансовогоРезультата(БазаРаспределения, ФильтрПоСтруктурнаяЕдиница, ФильтрПоНаправлениеДеятельности, ФильтрПоЗаказ, ФильтрПоПроект)
#Вставка
ТекущиеПравилаРаспределения = ДОкументы.пр_ПравилаРаспределения.НайтиПоРеквизиту("ДатаРаспределенияРасходов", НачалоДня(КонецМесяца(Дата)));
Если Не ТекущиеПравилаРаспределения.Пустая() И ТекущиеПравилаРаспределения <> Неопределено Тогда
Если БазаРаспределения = ТекущиеПравилаРаспределения.СпособРаспределения Тогда
ФильтрПоПроект = Новый Массив;
Для Каждого ТекущаяСтрока Из ТекущиеПравилаРаспределения.ПроектыДляРаспределенияРасходов Цикл
ФильтрПоПроект.Добавить(ТекущаяСтрока.Проект);
КонецЦикла;
КонецЕсли;
КонецЕсли;
#КонецВставки
ТаблицаРезультата = Новый ТаблицаЗначений;
Запрос = Новый Запрос;
#Удаление
Если БазаРаспределения = Перечисления.БазыРаспределенияРасходов.ВыручкаОтПродаж
ИЛИ БазаРаспределения = Перечисления.БазыРаспределенияРасходов.СебестоимостьПродаж
ИЛИ БазаРаспределения = Перечисления.БазыРаспределенияРасходов.ОбъемПродаж
ИЛИ БазаРаспределения = Перечисления.БазыРаспределенияРасходов.ВаловаяПрибыль Тогда
Если БазаРаспределения = Перечисления.БазыРаспределенияРасходов.ВыручкаОтПродаж Тогда
ТекстБазы = "СУММА(ПродажиОбороты.СуммаОборот)";
ИначеЕсли БазаРаспределения = Перечисления.БазыРаспределенияРасходов.СебестоимостьПродаж Тогда
ТекстБазы = "СУММА(ПродажиОбороты.СебестоимостьОборот)";
ИначеЕсли БазаРаспределения = Перечисления.БазыРаспределенияРасходов.ВаловаяПрибыль Тогда
ТекстБазы = "СУММА(ПродажиОбороты.СуммаОборот - ПродажиОбороты.СебестоимостьОборот)";
Иначе
ТекстБазы = "СУММА(ПродажиОбороты.КоличествоОборот)";
КонецЕсли;
#КонецУдаления
#Вставка
Если БазаРаспределения = Перечисления.БазыРаспределенияРасходов.ВыручкаОтПродаж
ИЛИ БазаРаспределения = Перечисления.БазыРаспределенияРасходов.СебестоимостьПродаж
ИЛИ БазаРаспределения = Перечисления.БазыРаспределенияРасходов.ОбъемПродаж
ИЛИ БазаРаспределения = Перечисления.БазыРаспределенияРасходов.ВаловаяПрибыль
ИЛИ БазаРаспределения = Перечисления.БазыРаспределенияРасходов.пр_ПоСпискуПроектов Тогда
Если БазаРаспределения = Перечисления.БазыРаспределенияРасходов.ВыручкаОтПродаж ИЛИ
БазаРаспределения = Перечисления.БазыРаспределенияРасходов.пр_ПоСпискуПроектов Тогда
ТекстБазы = "СУММА(ПродажиОбороты.СуммаОборот)";
ИначеЕсли БазаРаспределения = Перечисления.БазыРаспределенияРасходов.СебестоимостьПродаж Тогда
ТекстБазы = "СУММА(ПродажиОбороты.СебестоимостьОборот)";
ИначеЕсли БазаРаспределения = Перечисления.БазыРаспределенияРасходов.ВаловаяПрибыль Тогда
ТекстБазы = "СУММА(ПродажиОбороты.СуммаОборот - ПродажиОбороты.СебестоимостьОборот)";
Иначе
ТекстБазы = "СУММА(ПродажиОбороты.КоличествоОборот)";
КонецЕсли;
#КонецВставки
ТекстЗапроса =
"ВЫБРАТЬ
| ПродажиОбороты.Организация КАК Организация,
| ПродажиОбороты.Номенклатура.НаправлениеДеятельности КАК НаправлениеДеятельности,
| ПродажиОбороты.ЗаказПокупателя КАК Заказ,
| ПродажиОбороты.Номенклатура.НаправлениеДеятельности.СчетУчетаВыручкиОтПродаж КАК СчетУчетаВыручкиОтПродаж,
| ПродажиОбороты.Номенклатура.НаправлениеДеятельности.СчетУчетаСебестоимостиПродаж КАК СчетУчетаСебестоимостиПродаж,
| ПродажиОбороты.Номенклатура.НаправлениеДеятельности.СчетУчетаПрибыли КАК СчетУчетаПрибыли,
| // ТекстБазы КАК База,
| ПродажиОбороты.Подразделение КАК СтруктурнаяЕдиница,
| ПродажиОбороты.Проект КАК Проект
|ИЗ
| РегистрНакопления.Продажи.Обороты(
| &НачДата,
| &КонДата,
| Авто,
| Организация = &Организация
| // ФильтрПоСтруктурнаяЕдиница
| // ФильтрПоПроект
| // ФильтрПоНаправлениеДеятельности
| // ФильтрПоЗаказ
| ) КАК ПродажиОбороты
|ГДЕ
| ПродажиОбороты.Номенклатура.НаправлениеДеятельности <> ЗНАЧЕНИЕ(Справочник.НаправленияДеятельности.Прочее)
|СГРУППИРОВАТЬ ПО
| ПродажиОбороты.Организация,
| ПродажиОбороты.Номенклатура.НаправлениеДеятельности,
| ПродажиОбороты.ЗаказПокупателя,
| ПродажиОбороты.Номенклатура.НаправлениеДеятельности.СчетУчетаВыручкиОтПродаж,
| ПродажиОбороты.Номенклатура.НаправлениеДеятельности.СчетУчетаСебестоимостиПродаж,
| ПродажиОбороты.Номенклатура.НаправлениеДеятельности.СчетУчетаПрибыли,
| ПродажиОбороты.Подразделение,
| ПродажиОбороты.Проект";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "// ФильтрПоСтруктурнаяЕдиница", ?(ЗначениеЗаполнено(ФильтрПоСтруктурнаяЕдиница), "И Подразделение В (&МассивСтруктурныхЕдиниц)", ""));
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "// ФильтрПоПроект", ?(ЗначениеЗаполнено(ФильтрПоПроект), "И Проект В (&МассивПроектов)", ""));
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "// ФильтрПоНаправлениеДеятельности", ?(ЗначениеЗаполнено(ФильтрПоНаправлениеДеятельности), "И Номенклатура.НаправлениеДеятельности В (&МассивНаправленийДеятельности)", ""));
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "// ФильтрПоЗаказ", ?(ЗначениеЗаполнено(ФильтрПоЗаказ), "И ЗаказПокупателя В (&МассивЗаказов)", ""));
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "// ТекстБазы", ТекстБазы);
Иначе
Возврат ТаблицаРезультата;
КонецЕсли;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("НачДата" , ДополнительныеСвойства.ДляПроведения.НачальнаяДатаПериода);
Запрос.УстановитьПараметр("КонДата" , ДополнительныеСвойства.ДляПроведения.КонечнаяДатаПериода);
Запрос.УстановитьПараметр("Организация", ДополнительныеСвойства.ДляПроведения.Организация);
Если ЗначениеЗаполнено(ФильтрПоЗаказ) Тогда
Если ТипЗнч(ФильтрПоЗаказ) = Тип("Массив") Тогда
Запрос.УстановитьПараметр("МассивЗаказов", ФильтрПоЗаказ);
Иначе
МассивДляОтбора = Новый Массив;
МассивДляОтбора.Добавить(ФильтрПоЗаказ);
Запрос.УстановитьПараметр("МассивЗаказов", МассивДляОтбора);
КонецЕсли;
КонецЕсли;
Если ЗначениеЗаполнено(ФильтрПоСтруктурнаяЕдиница) Тогда
Если ТипЗнч(ФильтрПоСтруктурнаяЕдиница) = Тип("Массив") Тогда
Запрос.УстановитьПараметр("МассивСтруктурныхЕдиниц", ФильтрПоСтруктурнаяЕдиница);
Иначе
МассивДляОтбора = Новый Массив;
МассивДляОтбора.Добавить(ФильтрПоСтруктурнаяЕдиница);
Запрос.УстановитьПараметр("МассивСтруктурныхЕдиниц", МассивДляОтбора);
КонецЕсли;
КонецЕсли;
Если ЗначениеЗаполнено(ФильтрПоПроект) Тогда
Если ТипЗнч(ФильтрПоПроект) = Тип("Массив") Тогда
Запрос.УстановитьПараметр("МассивПроектов", ФильтрПоПроект);
Иначе
МассивДляОтбора = Новый Массив;
МассивДляОтбора.Добавить(ФильтрПоПроект);
Запрос.УстановитьПараметр("МассивПроектов", МассивДляОтбора);
КонецЕсли;
КонецЕсли;
Если ЗначениеЗаполнено(ФильтрПоНаправлениеДеятельности) Тогда
Если ТипЗнч(ФильтрПоНаправлениеДеятельности) = Тип("Массив") Тогда
Запрос.УстановитьПараметр("МассивНаправленийДеятельности", ФильтрПоНаправлениеДеятельности);
Иначе
МассивДляОтбора = Новый Массив;
МассивДляОтбора.Добавить(ФильтрПоНаправлениеДеятельности);
Запрос.УстановитьПараметр("МассивНаправленийДеятельности", ФильтрПоНаправлениеДеятельности);
КонецЕсли;
КонецЕсли;
ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
Возврат ТаблицаРезультата;
КонецФункции
Удалите фрагмент кода с помощью директив #Удаление, #КонецУдаления и
добавьте код с помощью директив #Вставка и #КонецВставки так чтобы система
корректно обрабатывала как стандартные, так и новый пользовательский тип
распределения расходов.
Задание 3.3. Подготовка данных и настройка системы
В каркасной базе за февраль 2025 года введите все необходимые недостающие
данные (номенклатуру, статьи затрат, первичные документы) для воспроизведения
«Контрольного примера».
Решение
Запустите режим пользователя.
Перейдите в подсистему «Работы» в раздел «Справочники». Откройте записи
справочника «Номенклатура».
В панели справа сделайте активным категорию «Работы и услуги» и нажмите
на кнопку «Создать».
Заполните данные новой номенклатуры «Поддержка DevOps»: наименование,
ед. измерения, поставщик, тип, направление деятельности.
Укажите счет учета для данной номенклатуры. Для этого в правом верхнем углу
нажмите на ссылку «Ещё» пункт «Счета учета».
В появившемся окне с предупреждением о записи данных нажмите кнопку
«ОК».
При выборе счета учета нажмите на ссылку «Показать все».
В окне «Счет» выберите тип счета «Расходы, распределяемые на финансовый
результат (Косвенный)» и нажмите кнопку «Создать».
Заполните данный нового счета учета и нажмите кнопку «Записать и закрыть».
Выберите созданный счет учета, перейдите на вкладку «Основное» и нажмите
на кнопку «Записать и закрыть».
В панели справа сделайте активным категорию «Прочие» и нажмите на кнопку
«Создать».
Заполните данные новой номенклатуры «Аренда серверов»: наименование, ед.
измерения, поставщик, тип, направление деятельности.
Укажите счет учета для данной номенклатуры. Для этого в правом верхнем углу
нажмите на ссылку «Ещё» пункт «Счета учета». В появившемся окне с
предупреждением о записи данных нажмите кнопку «ОК».
При выборе счета учета нажмите на ссылку «Показать все».
В окне «Счет» выберите тип счета «Расходы, распределяемые на финансовый
результат (Косвенный)» и нажмите кнопку «Создать».
Заполните данный нового счета учета и нажмите кнопку «Записать и закрыть».
Выберите созданный счет учета, перейдите на вкладку «Основное» и нажмите
на кнопку «Записать и закрыть».
В подсистеме «Закупки» откройте записи документа «Приходные накладные».
Нажмите кнопку «Создать».
Заполните данные новой приходной накладной за 13 февраля 2025 года и
нажмите кнопку «Провести и закрыть».
В подсистеме «Продажи» откройте записи документа «Расходные накладные».
Нажмите кнопку «Создать».
Заполните данные новой расходной накладной за 13 февраля 2025 года указав
«Разработку по часам» в количестве 71 час по проекту «Зед» и нажмите кнопку
«Провести и закрыть».
Создайте ещё расходную накладную за 8 февраля 2025 года указав «Разработку
по часам» в количестве 42 часа по проекту «Икс» и «Разработку по часам» в
количестве 109 часов по проекту «Игрек». Нажмите кнопку «Провести и закрыть».
Создайте ещё расходную накладную за 16 февраля 2025 года указав
«Разработку по часам» в количестве 105 часов по проекту «Вай». Нажмите кнопку
«Провести и закрыть».
В подсистеме «Настройки» в разделе «Администрирование» откройте «Общие
настройки».
В разделе «История изменений» установите переключатель «Хранить историю
изменений» и нажмите на ссылку «Настроить».
В окне «Настройки хранения истории изменений» найдите документ «Правила
распределения» и установите сохранение версий при проведении сроком бессрочно.
В подсистеме «Компания» откройте записи документа «Правила
распределения». Нажмите кнопку «Создать».
Заполните данные нового плана распределения и нажмите кнопку «Провести и
закрыть».
В командной панели нажмите кнопку с изображением зелёного карандаша.
В результате откроется окно, в котором фиксируется все изменения данного
документа.
В подсистеме «Персонал» откройте записи документа «Начисления зарплаты».
Откройте документ начисление зарплаты номер АСФР-00001 от февраля 2024
года на 265000,00 руб. Измените дату документа на 01 февраля 2025 года и нажмите
на кнопку «Провести и закрыть».
В подсистеме «Компания» откройте документы «Закрытие месяца».
Перейдите в раздел «Документы» и нажмите на кнопку «Создать».
Заполните документ «Закрытие месяца» от 28.02.2025 и установите
переключатель в расчет финансового результата. Нажмите кнопку «Провести и
закрыть».
Задание 3.4. Подготовка отчета
С помощью стандартных отчетов УНФ сформируйте итоговый отчет,
демонстрирующий корректность распределения, и сохраните его в формате Excel в
папке проекта. Структура отчета должна соответствовать контрольному примеру.
Допустимы расхождения в копейках между вашим расчетом и контрольным
примером.
Решение
В подсистеме «Компания» откройте из раздела «Аналитика» «Отчеты».
В разделе «Финансовые операции» щелкните по ссылке «Отчет для
руководителя (Анализ прибыльности проектов)».
В отчёте выберите период февраль 2025 и нажмите на кнопку «Сформировать».
В результате в отчете можно увидеть, что расходы по номенклатуре «Поддержка
DevOps» и «Затраты на сервера» распределилась по проектам.
В правой части окна нажмите на кнопку «Ещё» пункт меню «Сохранить в
файл».
Сохраните отчёт в excel файл.
В подсистеме «Компания» откройте записи документа «Правила
распределения». Откройте созданный ранее документ «Правила распределения».
Нажмите на ссылку «Файлы».
В открывшейся вкладке «Файлы» нажмите на кнопку «Добавить» – «Файл с
компьютера».
Выберите сохраненный файл «Финансовый результат по проектам на февраль
2025.xlsx» и нажмите кнопку «Открыть».
Таким образом файл прикрепился к документу.
Задание 3.5. Описание архитектуры
Подготовьте документ с описанием архитектуры в формате .docx и сохраните
его в папке проекта.
Описание функциональности правил распределения расходов
1. Используемые и созданные объекты метаданных
Документ "пр.ПравилаРаспределения"
Вид объекта: Документ
Назначение: Хранение правил распределения расходов по проектам на определенный месяц
Реквизиты:
- СпособРаспределения — ПеречислениеСсылкаБазыРаспределенияРасходов
Определяет метод распределения расходов
- ДатаРаспределенияРасходов — Дата
Указывает месяц, к которому применяется правило распределения
Табличная часть:
- ПроектыДляРаспределенияРасходов — Таблица значений
Проект — СправочникСсылкаПроект
Содержит список проектов, участвующих в распределении расходов
---
Справочник "пр.ПравилаРаспределенияПрисоединенныеФайлы"
Вид объекта: Справочник
Назначение: Хранение файлов, прикрепленных к документам правил распределения
Перечисление "БазыРаспределенияРасходов"
Вид объекта: Перечисление
Назначение: Определение способов распределения расходов
Добавлен новый элемент:
- пр.ПоСпискуПроектов — новый способ распределения по списку проектов
# 2. Модифицируемые методы типового решения
**Объект модификации:** Документ "ЗакрытиеМесяца"
**Модуль:** Модуль объекта
**Способ вмешательства:** Расширение с типом вызова "ИзменениеИКонтроль"
**Модифицируемый метод:**
- **Процедура "СформироватьТаблицуБазыРаспределенияФинансовогоРезультата"**
**Изменения в методе:**
- Добавлена логика проверки наличия активного правила распределения на конец закрываемого месяца
- Реализована фильтрация запроса по списку проектов из правила распределения
- Обеспечено определение базы проекта как общей выручки проекта
- Добавлена проверка соответствия способа распределения
---
3. Краткая логика работы
Шаг 1: Получение правила распределения
При запуске процедуры закрытия месяца система выполняет поиск документа "пр.ПравилаРаспределения" с датой распределения, соответствующей концу закрываемого месяца. Если документ найден, правило считается активным для данного периода.
Шаг 2: Проверка способа распределения
Система проверяет соответствие между:
- Способом распределения, переданным в функцию формирования таблицы базы
- Способом распределения, указанным в найденном правиле
Важное условие: Новая логика активируется только когда оба условия выполняются:
- Найдено активное правило распределения на закрываемый месяц
- Способ распределения в правиле соответствует новому значению "пр.ПоСпискуПроектов"
Шаг 3: Модификация запроса базы распределения
Если условия выполнены, система модифицирует стандартный запрос получения базы распределения:
Основная задача: В запрос добавляется дополнительное условие фильтрации:
Выбираются только те проекты, которые входят в массив проектов из табличной части документа правил распределения
База проекта рассчитывается как общая выручка по проекту
Шаг 4: Пропорциональное распределение расходов
После формирования отфильтрованной таблицы базы распределения система выполняет стандартное распределение расходов:
Расходы распределяются между проектами пропорционально их выручке
Используется стандартный алгоритм типового решения
Обеспечивается корректное закрытие финансового результата месяца
Шаг 5: Стандартная обработка
Если правило распределения не найдено или способ распределения не соответствует "пр.ПоСпискуПроектов", система продолжает работу по стандартному алгоритму типового решения без изменений.