gifts2017

Изящная доработка движений и проводок документов ERP 2

Опубликовал Анатолий Ситников (acsent) в раздел Программирование - Практика программирования

Доработка движений и проводок документов в ERP с минимальным количеством изменений типового кода, на примере добавления в документ "Акт выполненных работ" подразделения в ТЧ "Услуги"

Перед нами стоит следующая задача:

В документе "Акт выполненных работ" добавить возможность указания подразделения в ТЧ "Услги".

И нужно ее сделать так, чтобы потом не было мучительно больно обновлять ERP.

Разобьем нашу задачу на несколько этапов:

0. Добавление реквизита "Подразделение" в ТЧ "Услуги"
1. Вывод данного реквизита на форму документа
2. Исправление движений по регистрам
3. Исправление движений по проводкам

Надеюсь, п.0 не вызывает ни у кого вопросов, поэтому сразу перейдем к п.1

Вывод реквизита на форму документа

В отличие от предыдущих конфигураций, в этот раз 1С реально постаралась упростить работу доработчикам конфигураций. И чтобы было проще дорабатывать формы, в практически в каждую форму добавлены вызовы общих процедур

  • ПриСозданииНаСервере
  • ПриЧтенииНаСервере

ведущие к вызову процедур из модуля МодификацияКонфигурацииПереопределяемый, который и предназначен для доработки.
Добавим на форму вывод реквизита

Процедура ПриСозданииНаСервере(Форма, Отказ, СтандартнаяОбработка) Экспорт
    Если Форма.ИмяФормы = "Документ.АктВыполненныхРабот.Форма.ФормаДокумента" Тогда
        еус_МодификацияКонфигурации_АктВыполненныхРабот.ПриСозданииНаСервере_ФормаДокумента(Форма, Отказ, СтандартнаяОбработка);
    КонецЕсли;
КонецПроцедуры

Тут мы применим небольшую хитрость. Все изменения формы будем проводить в выделенном модуле. Для чего? Можно, конечно, писать доработки прямо в этом модуле. Но что будет, когда несколько разработчиков захотят доработать свои документы, а все доработки лежат в одном модуле? Конечно же, кто первый захватил модуль в хранилище, тот и работает. Остальные ждут.

Вот для того, чтобы и избежать этого,  выделяем для каждого документа свой модуль.

В реальной жизни, конечно же, в этом документе была не 1 доработка, поэтому такой метод вполне оправдан.

Процедура ПриСозданииНаСервере_ФормаДокумента(Форма, Отказ, СтандартнаяОбработка) Экспорт
    НовыйЭлемент = Форма.Элементы.Вставить("еус_Подразделение", Тип("ПолеФормы"), Форма.Элементы.Услуги,);
    НовыйЭлемент.Вид         = ВидПоляФормы.ПолеВвода;
    НовыйЭлемент.ПутьКДанным = "Объект.Услуги.еус_Подразделение";
КонецПроцедуры	

Исправление движений по регистрам

Формирование движений документов происходит следующим образом:

  1. Инициализация данных проведения
  2. Запись движений
  3. Контроль регистров


Тут нас интересует пункт "Инициализация данных проведения". Данная инициализция происходит путем вызова процедуры модуля менеджера

Документы.АктВыполненныхРабот.ИнициализироватьДанныеДокумента(Ссылка, ДополнительныеСвойства);

Инициализация сотосит из пунктов
1. Инициализация шапки документа

Запрос = Новый Запрос;
ЗаполнитьПараметрыИнициализации(Запрос, ДокументСсылка)

2. Формирование списка с текстами запросов

//...
ТекстыЗапроса = Новый СписокЗначений;
ТекстЗапросаТаблицаЗаказыКлиентов(Запрос, ТекстыЗапроса, Регистры);
//...

3. Выполнение запросов

ПроведениеСервер.ИницализироватьТаблицыДляДвижений(Запрос, ТекстыЗапроса, ДополнительныеСвойства.ТаблицыДляДвижений, Истина);

Т.к. последняя процедура вызывается для каждого документа, то логичным вариантом будет модифицировать только ее

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

Прменим тот же прием, что и для доработки форм: каждому документу свой модуль.

Процедура ДополнитьТекстыЗапросов(Запрос, ТекстыЗапроса, Таблицы, ДобавитьРазделитель, ДобавлятьСловоТаблица, ТолькоОтмеченные) Экспорт
	
    // Дорабатываем тексты запросов перед выполнением
    // в функции  ПроведениеСервер.ИницализироватьТаблицыДляДвижений
    Ссылка = Неопределено;
    Если НЕ Запрос.Параметры.Свойство("Ссылка", Ссылка) Тогда
        Возврат;
    КонецЕсли;	
	
    ТипСсылки = ТипЗнч(Ссылка) ;
    Если ТипСсылки = Тип("ДокументСсылка.АктВыполненныхРабот") Тогда	
        еус_ОбработчикиПроведенияСервер_АктВыполненныхРабот.ТекстЗапроса(Запрос, ТекстыЗапроса, "");
    КонецЕсли;	
	
КонецПроцедуры

Перейдем непосредственно к доработке движений по регистрам

Функция ТекстЗапроса(Запрос, ТекстыЗапроса, Регистры) Экспорт

    ТекстЗапроса_ВтРаботыУслуги(Запрос, ТекстыЗапроса, Регистры);
    ТекстЗапроса_СебестоимостьТоваров(Запрос, ТекстыЗапроса, Регистры);
    ТекстЗапроса_ВыручкаИСебестоимостьПродаж(Запрос, ТекстыЗапроса, Регистры);
    ТекстЗапроса_МатериалыИРаботыВПроизводстве(Запрос, ТекстыЗапроса, Регистры);
    Возврат "";

КонецФункции

Рассмотрим только вариант с доработкой движений по себестоимости. Для исправления запросов будем использовать объектную модель, которую дает нам СхемаЗапроса

Функция ТекстЗапроса_СебестоимостьТоваров(Запрос, ТекстыЗапроса, Регистры) Экспорт
    
    // Подразденение берем из ТЧ
    ЭлементТекстЗапроса = еус_ОбработчикиПроведенияСервер.НайтиЭлементСписка(ТекстыЗапроса, "СебестоимостьТоваров");
    ТекстЗапроса = ЭлементТекстЗапроса.Значение;
	
    СхемаЗапроса = Новый СхемаЗапроса;
    СхемаЗапроса.УстановитьТекстЗапроса(ТекстЗапроса);
	
    ТекстПодразделение = 
    "ВЫБОР 
    |	КОГДА ТаблицаУслуги.Подразделение = ЗНАЧЕНИЕ(Справочник.СтруктураПредприятия.ПустаяСсылка)
    |		ТОГДА &Подразделение
    |	ИНАЧЕ
    |		ТаблицаУслуги.Подразделение
    |КОНЕЦ";
	
    ЗапросВыбораСхемыЗапроса = СхемаЗапроса.ПакетЗапросов[0];
    ОператорВыбратьСхемыЗапроса =    ЗапросВыбораСхемыЗапроса.Операторы[0];
    еус_ОбработчикиПроведенияСервер.ДобавитьДоступноеПолеВТаблицу(ОператорВыбратьСхемыЗапроса, "ТаблицаУслуги", "Подразделение");

    еус_ОбработчикиПроведенияСервер.УстановитьПолеЗапроса(ЗапросВыбораСхемыЗапроса, ОператорВыбратьСхемыЗапроса, "Подразделение", "ТаблицаУслуги.Подразделение"); 
    //|	ЛЕВОЕ СОЕДИНЕНИЕ
    //|		ВтАналитика КАК ВтАналитика
    //|	ПО
    //|		ТаблицаУслуги.Номенклатура = ВтАналитика.Номенклатура
    //|		И ТаблицаУслуги.Характеристика = ВтАналитика.Характеристика
    // Не хватает соединения по подразделению
	
    еус_ОбработчикиПроведенияСервер.ДобавитьДоступноеПолеВТаблицу(ОператорВыбратьСхемыЗапроса, "ВтАналитика", "Склад");
    еус_ОбработчикиПроведенияСервер.ДобавитьУсловиеСоединения(ОператорВыбратьСхемыЗапроса, "ТаблицаУслуги", "ВтАналитика", "ТаблицаУслуги.Подразделение = ВтАналитика.Склад");
    ТекстЗапроса = СхемаЗапроса.ПолучитьТекстЗапроса();

КонецФункции

В данном коде используются функции, упрощающие работу со схемой запроса. Эти функции можно посмотреть в приложенном файле

Исправление движений по проводкам

Порядок формирования проводок из формы документа

1. Кнопка "Дт-Кт"  - Обоработка.ОтражениеДокументовВРеглУчете, команда ПроводкиРеглУчета
2. Кнопка "Отразить в регл. учете" вызыввает следующую процедуру

Процедура ОтразитьДокументВРеглУчетеСервер()

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

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

Если мы потом захотим отразить програмно в рег. учете какой либо документ, то достаточно будет вызвать эту функцию.

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

Функция ТекстЗапросаВТОтраженияВРеглУчете() Экспорт
Функция ТекстОтраженияВРеглУчете() Экспорт

Эти функции вызываются из функции

РеглУчетВыборкиСерверПовтИсп.ЗапросДанных(ДокументИмя, ЭтоОбъектРасчетов = Истина)

Добавим в эту функцию перехват и добработку текста запросов
Добавим в функцию ЗапросДанных наш текс для перехватя текста запроса

Функция ЗапросДанных(ДокументИмя, ЭтоОбъектРасчетов = Истина) Экспорт
    
    //....
    ТекстВТОтраженияДокумента = ТекстВТОтраженияДокумента(ДокументИмя);
    
    // НАЧАЛО ВСТАВКИ
    еус_ОбработчикиПроведенияСервер.ТекстОтраженияДокумента(ДокументИмя, ТекстОтраженияДокумента); 
    еус_ОбработчикиПроведенияСервер.ТекстВТОтраженияДокумента(ДокументИмя, ТекстВТОтраженияДокумента); 
    //КОНЕЦ ВСТАВКИ
        
    Если ТекстОтраженияДокумента <> "" Тогда
        ТекстОтраженияДокумента = " ОБЪЕДИНИТЬ ВСЕ " + ТекстОтраженияДокумента; 
    КонецЕсли;
    
    Если ДокументИмя = "РасчетСебестоимостиТоваров" Тогда
        Возврат Новый Запрос(""
            + ТекстПустыеВТ()
            + ТекстВТОтраженияДокумента
            + ТекстИнициализации
            + ТекстОтраженияДокумента);
    Иначе
        Возврат Новый Запрос(""
            + ТекстСебестоимость()
            + ТекстПартии()
            + ТекстЗаписиНДС()
            + ТекстУчетнаяПолитика()
            + ТекстВТОтраженияДокумента
            + ТекстИнициализации
            + ТекстЗачетАвансов
            + ТекстРаспределениеРасходов
            + " ОБЪЕДИНИТЬ ВСЕ " + ТекстНДСПоДаннымФинпартий()
            + ТекстОтраженияДокумента);
    КонецЕсли;
КонецФункции

Разобьем доработку проводок на 2 части:

  1. Изменение уже существующего текста запроса
  2. Добавление нового текста запроса

В нашем случае добавления текста не будет, а только изменение существующего

Функция ТекстОтраженияДокумента(ДокументИмя, Текст) Экспорт
	
    Если ДокументИмя = "АктВыполненныхРабот" Тогда
	еус_ОбработчикиПроведенияСервер_АктВыполненныхРабот.ОбработатьТекстЗапросаОтражениеВРегУчете(Текст);
        ДобавочныйТекст = еус_ОбработчикиПроведенияСервер_АктВыполненныхРабот.ТекстЗапросаОтражениеВРегУчете();
        Если ЗначениеЗаполнено(ДобавочныйТекст) Тогда
            Текст = Текст + " ОБЪЕДИНИТЬ ВСЕ " + ДобавочныйТекст;
        КонцеЕсли;
    КонецЕсли;	
	
КонецФункции

Рассмотрим наши функции по доработке текста запроса бух. проводок. В отличие от запросов движений по регистрам, в данном случае мы имеем 1 большой запрос, состоящий из отдельных запросов по каждой проводке, соединенных через "ОБЪЕДИНИТЬ ВСЕ". Это немного усложняет нам работу, а также приносит потенциальную ошибку смены порядка запросов.

Процедура ОбработатьТекстЗапросаОтражениеВРегУчете(Текст) Экспорт
	
    СхемаЗапроса = Новый СхемаЗапроса;
    СхемаЗапроса.УстановитьТекстЗапроса(Текст);
	
    //Чтобы не запутаться в порядке запросов - пронумеруем их
    Таблицы = Новый Соответствие;
    Таблицы.Вставить("ТекстЗадолженностьПокупателяЗаУслуги",  0);
    Таблицы.Вставить("ТекстНачислениеНДСЗаУслуги",            1);
    Таблицы.Вставить("ТекстОказаниеРабот",                    2);
    Таблицы.Вставить("ТекстНеПодтверждениеНулевойСтавкиНДС",  3);
    Таблицы.Вставить("ТекстПродажаАгентскихУслуг",            4);
    Таблицы.Вставить("ТекстВключениеИсключениеНДСВСтоимость", 5);
	
    ЗапросВыбораСхемыЗапроса = СхемаЗапроса.ПакетЗапросов[0];
	
    //ТекстЗадолженностьПокупателяЗаУслуги
    Оператор = ЗапросВыбораСхемыЗапроса.Операторы[Таблицы["ТекстЗадолженностьПокупателяЗаУслуги"]];

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

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

Итак, с минимальными врезками в типовой код мы выполнили нашу задачу по доработке документа.

 

P.S. Можете посмотреть другие мои статьи по доработке ERP

Набор тестов xUnit для ERP2, блок Производство

Скачать файлы

Наименование Файл Версия Размер
ОбщийМодуль.zip 2
.zip 1,01Kb
05.04.16
2
.zip 1,01Kb Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Андрей Карпов (karpik666) 05.04.16 13:49
Такая ситуация не только в Erp, но и в Ут 11, даже где-то была статья по доработке Ут с такими же переопределяемыми обработчиками
2. Владислав Рожевский (vvr908) 05.04.16 15:20
Коллеги, а сейчас нет возможности реализовать такие доработки через механизм расширений конфигурации?
3. Артём Шарипов (borodatii) 05.04.16 15:59
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа