Перед нами стоит следующая задача:
В документе "Акт выполненных работ" добавить возможность указания подразделения в ТЧ "Услги".
И нужно ее сделать так, чтобы потом не было мучительно больно обновлять ERP.
Разобьем нашу задачу на несколько этапов:
0. Добавление реквизита "Подразделение" в ТЧ "Услуги"
1. Вывод данного реквизита на форму документа
2. Исправление движений по регистрам
3. Исправление движений по проводкам
Надеюсь, п.0 не вызывает ни у кого вопросов, поэтому сразу перейдем к п.1
Вывод реквизита на форму документа
В отличие от предыдущих конфигураций, в этот раз 1С реально постаралась упростить работу доработчикам конфигураций. И чтобы было проще дорабатывать формы, в практически в каждую форму добавлены вызовы общих процедур
- ПриСозданииНаСервере
- ПриЧтенииНаСервере
ведущие к вызову процедур из модуля МодификацияКонфигурацииПереопределяемый, который и предназначен для доработки.
Добавим на форму вывод реквизита
Процедура ПриСозданииНаСервере(Форма, Отказ, СтандартнаяОбработка) Экспорт
Если Форма.ИмяФормы = "Документ.АктВыполненныхРабот.Форма.ФормаДокумента" Тогда
еус_МодификацияКонфигурации_АктВыполненныхРабот.ПриСозданииНаСервере_ФормаДокумента(Форма, Отказ, СтандартнаяОбработка);
КонецЕсли;
КонецПроцедуры
Тут мы применим небольшую хитрость. Все изменения формы будем проводить в выделенном модуле. Для чего? Можно, конечно, писать доработки прямо в этом модуле. Но что будет, когда несколько разработчиков захотят доработать свои документы, а все доработки лежат в одном модуле? Конечно же, кто первый захватил модуль в хранилище, тот и работает. Остальные ждут.
Вот для того, чтобы и избежать этого, выделяем для каждого документа свой модуль.
В реальной жизни, конечно же, в этом документе была не 1 доработка, поэтому такой метод вполне оправдан.
Процедура ПриСозданииНаСервере_ФормаДокумента(Форма, Отказ, СтандартнаяОбработка) Экспорт
НовыйЭлемент = Форма.Элементы.Вставить("еус_Подразделение", Тип("ПолеФормы"), Форма.Элементы.Услуги,);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.ПутьКДанным = "Объект.Услуги.еус_Подразделение";
КонецПроцедуры
Исправление движений по регистрам
Формирование движений документов происходит следующим образом:
- Инициализация данных проведения
- Запись движений
- Контроль регистров
Тут нас интересует пункт "Инициализация данных проведения". Данная инициализция происходит путем вызова процедуры модуля менеджера
Документы.АктВыполненныхРабот.ИнициализироватьДанныеДокумента(Ссылка, ДополнительныеСвойства);
Инициализация сотосит из пунктов
1. Инициализация шапки документа
Запрос = Новый Запрос;
ЗаполнитьПараметрыИнициализации(Запрос, ДокументСсылка)
2. Формирование списка с текстами запросов
//...
ТекстыЗапроса = Новый СписокЗначений;
ТекстЗапросаТаблицаЗаказыКлиентов(Запрос, ТекстыЗапроса, Регистры);
//...
3. Выполнение запросов
ПроведениеСервер.ИницализироватьТаблицыДляДвижений(Запрос, ТекстыЗапроса, ДополнительныеСвойства.ТаблицыДляДвижений, Истина);
Т.к. последняя процедура вызывается для каждого документа, то логичным вариантом будет модифицировать только ее
Процедура ИницализироватьТаблицыДляДвижений(Запрос, ТекстыЗапроса, Таблицы, ДобавитьРазделитель = Ложь, ДобавлятьСловоТаблица = Истина, ТолькоОтмеченные=Ложь) Экспорт
//НАЧАЛО ВСТАВКИ
еус_ОбработчикиПроведенияСервер.ДополнитьТекстыЗапросов(Запрос, ТекстыЗапроса, Таблицы, ДобавитьРазделитель, ДобавлятьСловоТаблица, ТолькоОтмеченные);
//КОНЕЦ ВСТАВКИ
ТаблицыЗапроса = ОбщегоНазначенияУТ.ВыгрузитьРезультатыЗапроса(Запрос, ТекстыЗапроса,, ДобавитьРазделитель);
//...
КонецПроцедуры
Прменим тот же прием, что и для доработки форм: каждому документу свой модуль.
Процедура ДополнитьТекстыЗапросов(Запрос, ТекстыЗапроса, Таблицы, ДобавитьРазделитель, ДобавлятьСловоТаблица, ТолькоОтмеченные) Экспорт
// Дорабатываем тексты запросов перед выполнением
// в функции ПроведениеСервер.ИницализироватьТаблицыДляДвижений
Ссылка = Неопределено;
Если НЕ Запрос.Параметры.Свойство("Ссылка", Ссылка) Тогда
Возврат;
КонецЕсли;
ТипСсылки = ТипЗнч(Ссылка) ;
Если ТипСсылки = Тип("ДокументСсылка.АктВыполненныхРабот") Тогда
еус_ОбработчикиПроведенияСервер_АктВыполненныхРабот.ТекстЗапроса(Запрос, ТекстыЗапроса, "");
КонецЕсли;
КонецПроцедуры
Перейдем непосредственно к доработке движений по регистрам
Функция ТекстЗапроса(Запрос, ТекстыЗапроса, Регистры) Экспорт
ТекстЗапроса_ВтРаботыУслуги(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапроса_СебестоимостьТоваров(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапроса_ВыручкаИСебестоимостьПродаж(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапроса_МатериалыИРаботыВПроизводстве(Запрос, ТекстыЗапроса, Регистры);
Возврат "";
КонецФункции
Рассмотрим только вариант с доработкой движений по себестоимости. Для исправления запросов будем использовать объектную модель, которую дает нам СхемаЗапроса
Функция ТекстЗапроса_СебестоимостьТоваров(Запрос, ТекстыЗапроса, Регистры) Экспорт
// Подразденение берем из ТЧ
ЭлементТекстЗапроса = еус_ОбработчикиПроведенияСервер.НайтиЭлементСписка(ТекстыЗапроса, "СебестоимостьТоваров");
ТекстЗапроса = ЭлементТекстЗапроса.Значение;
СхемаЗапроса = Новый СхемаЗапроса;
СхемаЗапроса.УстановитьТекстЗапроса(ТекстЗапроса);
ТекстПодразделение =
"ВЫБОР
| КОГДА ТаблицаУслуги.Подразделение = ЗНАЧЕНИЕ(Справочник.СтруктураПредприятия.ПустаяСсылка)
| ТОГДА &Подразделение
| ИНАЧЕ
| ТаблицаУслуги.Подразделение
|КОНЕЦ";
ЗапросВыбораСхемыЗапроса = СхемаЗапроса.ПакетЗапросов[0];
ОператорВыбратьСхемыЗапроса = ЗапросВыбораСхемыЗапроса.Операторы[0];
еус_ОбработчикиПроведенияСервер.ДобавитьДоступноеПолеВТаблицу(ОператорВыбратьСхемыЗапроса, "ТаблицаУслуги", "Подразделение");
еус_ОбработчикиПроведенияСервер.УстановитьПолеЗапроса(ЗапросВыбораСхемыЗапроса, ОператорВыбратьСхемыЗапроса, "Подразделение", "ТаблицаУслуги.Подразделение");
//| ЛЕВОЕ СОЕДИНЕНИЕ
//| ВтАналитика КАК ВтАналитика
//| ПО
//| ТаблицаУслуги.Номенклатура = ВтАналитика.Номенклатура
//| И ТаблицаУслуги.Характеристика = ВтАналитика.Характеристика
// Не хватает соединения по подразделению
еус_ОбработчикиПроведенияСервер.ДобавитьДоступноеПолеВТаблицу(ОператорВыбратьСхемыЗапроса, "ВтАналитика", "Склад");
еус_ОбработчикиПроведенияСервер.ДобавитьУсловиеСоединения(ОператорВыбратьСхемыЗапроса, "ТаблицаУслуги", "ВтАналитика", "ТаблицаУслуги.Подразделение = ВтАналитика.Склад");
ТекстЗапроса = СхемаЗапроса.ПолучитьТекстЗапроса();
КонецФункции
В данном коде используются функции, упрощающие работу со схемой запроса. Эти функции можно посмотреть в приложенном файле
Исправление движений по проводкам
Порядок формирования проводок из формы документа
1. Кнопка "Дт-Кт" - Обоработка.ОтражениеДокументовВРеглУчете, команда ПроводкиРеглУчета
2. Кнопка "Отразить в регл. учете" вызыввает следующую процедуру
Процедура ОтразитьДокументВРеглУчетеСервер()
СтруктураРеквизиты = Новый Структура("Ссылка, Дата, Организация", Документ, Дата, Неопределено);
РеглУчетПроведениеСервер.ОтразитьДокумент(СтруктураРеквизиты, Истина);
ПовторноеОткрытиеСервер();
КонецПроцедуры
Если мы потом захотим отразить програмно в рег. учете какой либо документ, то достаточно будет вызвать эту функцию.
В конечном итоге вызываются две функции модуля менеджера, первая возвращает текст запроса формирования временных таблиц, а вторая - проводок
Функция ТекстЗапросаВТОтраженияВРеглУчете() Экспорт
Функция ТекстОтраженияВРеглУчете() Экспорт
Эти функции вызываются из функции
РеглУчетВыборкиСерверПовтИсп.ЗапросДанных(ДокументИмя, ЭтоОбъектРасчетов = Истина)
Добавим в эту функцию перехват и добработку текста запросов
Добавим в функцию ЗапросДанных наш текс для перехватя текста запроса
Функция ЗапросДанных(ДокументИмя, ЭтоОбъектРасчетов = Истина) Экспорт
//....
ТекстВТОтраженияДокумента = ТекстВТОтраженияДокумента(ДокументИмя);
// НАЧАЛО ВСТАВКИ
еус_ОбработчикиПроведенияСервер.ТекстОтраженияДокумента(ДокументИмя, ТекстОтраженияДокумента);
еус_ОбработчикиПроведенияСервер.ТекстВТОтраженияДокумента(ДокументИмя, ТекстВТОтраженияДокумента);
//КОНЕЦ ВСТАВКИ
Если ТекстОтраженияДокумента <> "" Тогда
ТекстОтраженияДокумента = " ОБЪЕДИНИТЬ ВСЕ " + ТекстОтраженияДокумента;
КонецЕсли;
Если ДокументИмя = "РасчетСебестоимостиТоваров" Тогда
Возврат Новый Запрос(""
+ ТекстПустыеВТ()
+ ТекстВТОтраженияДокумента
+ ТекстИнициализации
+ ТекстОтраженияДокумента);
Иначе
Возврат Новый Запрос(""
+ ТекстСебестоимость()
+ ТекстПартии()
+ ТекстЗаписиНДС()
+ ТекстУчетнаяПолитика()
+ ТекстВТОтраженияДокумента
+ ТекстИнициализации
+ ТекстЗачетАвансов
+ ТекстРаспределениеРасходов
+ " ОБЪЕДИНИТЬ ВСЕ " + ТекстНДСПоДаннымФинпартий()
+ ТекстОтраженияДокумента);
КонецЕсли;
КонецФункции
Разобьем доработку проводок на 2 части:
- Изменение уже существующего текста запроса
- Добавление нового текста запроса
В нашем случае добавления текста не будет, а только изменение существующего
Функция ТекстОтраженияДокумента(ДокументИмя, Текст) Экспорт
Если ДокументИмя = "АктВыполненныхРабот" Тогда
еус_ОбработчикиПроведенияСервер_АктВыполненныхРабот.ОбработатьТекстЗапросаОтражениеВРегУчете(Текст);
ДобавочныйТекст = еус_ОбработчикиПроведенияСервер_АктВыполненныхРабот.ТекстЗапросаОтражениеВРегУчете();
Если ЗначениеЗаполнено(ДобавочныйТекст) Тогда
Текст = Текст + " ОБЪЕДИНИТЬ ВСЕ " + ДобавочныйТекст;
КонцеЕсли;
КонецЕсли;
КонецФункции
Рассмотрим наши функции по доработке текста запроса бух. проводок. В отличие от запросов движений по регистрам, в данном случае мы имеем 1 большой запрос, состоящий из отдельных запросов по каждой проводке, соединенных через "ОБЪЕДИНИТЬ ВСЕ". Это немного усложняет нам работу, а также приносит потенциальную ошибку смены порядка запросов.
Процедура ОбработатьТекстЗапросаОтражениеВРегУчете(Текст) Экспорт
СхемаЗапроса = Новый СхемаЗапроса;
СхемаЗапроса.УстановитьТекстЗапроса(Текст);
//Чтобы не запутаться в порядке запросов - пронумеруем их
Таблицы = Новый Соответствие;
Таблицы.Вставить("ТекстЗадолженностьПокупателяЗаУслуги", 0);
Таблицы.Вставить("ТекстНачислениеНДСЗаУслуги", 1);
Таблицы.Вставить("ТекстОказаниеРабот", 2);
Таблицы.Вставить("ТекстНеПодтверждениеНулевойСтавкиНДС", 3);
Таблицы.Вставить("ТекстПродажаАгентскихУслуг", 4);
Таблицы.Вставить("ТекстВключениеИсключениеНДСВСтоимость", 5);
ЗапросВыбораСхемыЗапроса = СхемаЗапроса.ПакетЗапросов[0];
//ТекстЗадолженностьПокупателяЗаУслуги
Оператор = ЗапросВыбораСхемыЗапроса.Операторы[Таблицы["ТекстЗадолженностьПокупателяЗаУслуги"]];
//Заменим Поле пдразделение на получение из табличной части
ТекстПодразделение =
"ВЫБОР
| КОГДА Строки.еус_Подразделение = ЗНАЧЕНИЕ(Справочник.СтруктураПредприятия.ПустаяСсылка)
| ТОГДА Операция.Подразделение
| ИНАЧЕ
| Строки.еус_Подразделение
|КОНЕЦ";
еус_ОбработчикиПроведенияСервер.УстановитьПолеЗапроса(ЗапросВыбораСхемыЗапроса, Оператор, "ПодразделениеДт", "ЕСТЬNULL(Расчеты.Подразделение, " + ТекстПодразделение + ")");
еус_ОбработчикиПроведенияСервер.УстановитьПолеЗапроса(ЗапросВыбораСхемыЗапроса, Оператор, "ПодразделениеКт", ТекстПодразделение);
//ТекстНачислениеНДСЗаУслуги
Оператор = ЗапросВыбораСхемыЗапроса.Операторы[Таблицы["ТекстНачислениеНДСЗаУслуги"]];
еус_ОбработчикиПроведенияСервер.УстановитьПолеЗапроса(ЗапросВыбораСхемыЗапроса, Оператор, "ПодразделениеДт", ТекстПодразделение);
//ТекстОказаниеРабот
Оператор = ЗапросВыбораСхемыЗапроса.Операторы[Таблицы["ТекстОказаниеРабот"]];
ТекстПодразделение =
"ВЫБОР
| КОГДА Строки.Подразделение = ЗНАЧЕНИЕ(Справочник.СтруктураПредприятия.ПустаяСсылка)
| ТОГДА Операция.Подразделение
| ИНАЧЕ
| Строки.Подразделение
|КОНЕЦ";
еус_ОбработчикиПроведенияСервер.ДобавитьДоступноеПолеВТаблицу(Оператор, "Строки", "Подразделение");
еус_ОбработчикиПроведенияСервер.УстановитьПолеЗапроса(ЗапросВыбораСхемыЗапроса, Оператор, "ПодразделениеДт", ТекстПодразделение);
еус_ОбработчикиПроведенияСервер.УстановитьПолеЗапроса(ЗапросВыбораСхемыЗапроса, Оператор, "ПодразделениеКт", ТекстПодразделение);
//| ЛЕВОЕ СОЕДИНЕНИЕ
//| ВтСтоимости КАК Стоимости
//| ПО
//| Строки.Ссылка = Стоимости.Ссылка
//| И Строки.Номенклатура = Стоимости.Номенклатура
//| И Строки.ГруппаФинансовогоУчета = Стоимости.ГруппаФинансовогоУчета
//Не хватает соединения по складу
еус_ОбработчикиПроведенияСервер.ДобавитьДоступноеПолеВТаблицу(Оператор, "Строки", "Склад");
еус_ОбработчикиПроведенияСервер.ДобавитьДоступноеПолеВТаблицу(Оператор, "Стоимости", "Склад");
//Все соединения идут на первую таблицу в запросе
еус_ОбработчикиПроведенияСервер.ДобавитьУсловиеСоединения(Оператор, "ДокументыКОтражению", "Стоимости", "Строки.Склад = Стоимости.Склад");
Текст = СхемаЗапроса.ПолучитьТекстЗапроса();
КонецПроцедуры
Итак, с минимальными врезками в типовой код мы выполнили нашу задачу по доработке документа.
P.S. Можете посмотреть другие мои статьи по доработке ERP