Универсальная обработка формирования движений в 1С 7.7


Пример программного кода, позволяющего «вывести» настройку функционала конфигурации информационной базы 1С:Предприятие, версии 7.7 из под ответственности программиста и передать его аналитику бизнес процессов.

В данной статье, позвольте «покуситься на святое» и вывести огромный блок задач из под ответственности программиста в ответственность пользователя, ну, или его консультанта по информационной системе. Я говорю о конфигурировании движений документов в системе управленческого учета. И если раньше, мы это делали в конфигураторе, редактированием, непосредственно, модуля каждого документа, то сейчас, с учетом [ссылка], мы можем определить внешний для системы 1С:Предприятие файл, где хранить параметры проведения в удобном для анализа и настройки виде.

Перед чтением данной статьи, также рекомендую посмотреть статью [ссылка] где продемонстрирована возможность создания универсальной выгрузки данных информационной базы в xml-файл и статью [ссылка], где, в рамках задачи обмена между базами разных конфигураций, приводится пример трансформации xml-файла.

В конфигурации из статьи [ссылка] зададим справочник «Товары», в документе «Продажа» определим табличную часть с реквизитами «Товар» — тип «Справочник.Товары», «Количество» — тип «Число». Добавим регистр «ОстаткиТоваров», в котором определим ресурс «Товар» — тип «Справочник.Товары» и измерение «Количество».

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

//*******************************************
// вызов процедуры проведения документа
 
Процедура ОбработкаПроведения(Параметр)
 
    // передача управления в глобальный модуль
 
    глОбработкаПроведения(Контекст, ?(ПустоеЗначение(Параметр) = 0, Параметр,
        СформироватьДвиженияДокумента(Контекст)));
 
КонецПроцедуры
… заданной в глобальном модуле:

//*******************************************
// универсальная обработка проведения
 
Функция СформироватьДвиженияДокумента(Конт) Экспорт
 
    хмлИсходныйФайл = ХМЛПредставлениеДокумента(Конт);
 
    Преобразование = "<?xml version=""1.0"" encoding=""WINDOWS-1251""?>
 
                    |<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:myType=""http://my.org/buh"">
                    |<xsl:template match=""/"">
                    |<ДвиженияДокумента>
                    |<xsl:for-each select=""Документ_Продажа"">
                    |<Продажи>
                    |<п>
                    |<Направление>0</Направление>
                    |<Клиент><xsl:value-of select=""Клиент""/></Клиент>
                    |<Сумма><xsl:value-of select=""СуммаДокумента""/></Сумма>
                    |</п>
                    |</Продажи>
                    |</xsl:for-each>
                    |<xsl:for-each select=""Документ_Продажа/ТабЧасть"">
                    |<ОстаткиТоваров>
                    |<п>
                    |<Направление>-1</Направление>
                    |<Товар><xsl:value-of select=""Товар""/></Товар>
                    |<Количество><xsl:value-of select=""Количество""/></Количество>
                    |</п>
                    |</ОстаткиТоваров>
                    |</xsl:for-each>
                    |</ДвиженияДокумента>
                    |</xsl:template>
                    |</xsl:stylesheet>
                    |";            
 
    хмлПреобразование = СоздатьОбъект("Msxml2.DOMDocument.6.0");
 
    хмлПреобразование.async = 0;
 
    хмлПреобразование.loadXML(Преобразование);
 
    хмлРезультат = СоздатьОбъект("Msxml2.DOMDocument.6.0");
 
    хмлРезультат.async = 0;
 
    хмлИсходныйФайл.transformNodeToObject(хмлПреобразование, хмлРезультат);
 
    Возврат хмлРезультат;
 
КонецФункции

Как видим, результат формирования — набор движений, представленный в xml-формате [ссылка], получен xslt-преобразованием данных документа, сформированных процедурой «ХМЛПредставлениеДокумента»-аналогом соответствующей процедуры для справочника в статье [ссылка] и представленной ниже:

//*******************************************
// универсальная обработка проведения
 
Функция ХМЛПредставлениеДокумента(Конт) Экспорт
 
    хмлПарсер = СоздатьОбъект("Msxml2.DOMDocument.6.0");
 
    хмлУзел = хмлПарсер.appendChild(хмлПарсер
        .createElement("Документ_" + Конт.Вид()));
 
    Для й = 1 По Метаданные.Документ(Конт.Вид()).РеквизитШапки() Цикл
 
        ИмяРек = Метаданные.Документ(Конт.Вид())
            .РеквизитШапки(й).Идентификатор;
 
        хмлРек = хмлУзел.appendChild(хмлПарсер.createElement(ИмяРек));
 
        Значение = Конт.ПолучитьАтрибут(ИмяРек);
 
        Если ТипЗначения(Значение) < 10 Тогда
 
            хмлРек.text = СокрЛП(Значение);
 
        Иначе
 
            хмлРек.text = ЗначениеВСтрокуВнутр(Значение);
 
        КонецЕсли;
 
    КонецЦикла;   
 
    Конт.ВыбратьСтроки();
 
    Пока Конт.ПолучитьСтроку() = 1 Цикл
 
        хмлТЧ = хмлУзел.appendChild(хмлПарсер
            .createElement("ТабЧасть"));
 
        Для й = 1 По Метаданные.Документ(Конт.Вид()).РеквизитТабличнойЧасти() Цикл
 
            ИмяРек = Метаданные.Документ(Конт.Вид())
                .РеквизитТабличнойЧасти(й).Идентификатор;
 
            хмлРек = хмлТЧ.appendChild(хмлПарсер.createElement(ИмяРек));
 
            Значение = Конт.ПолучитьАтрибут(ИмяРек);
 
            Если ТипЗначения(Значение) < 10 Тогда
 
                хмлРек.text = СокрЛП(Значение);
 
            Иначе
 
                хмлРек.text = ЗначениеВСтрокуВнутр(Значение);
 
            КонецЕсли;
 
        КонецЦикла;
  
    КонецЦикла;
  
    Возврат хмлПарсер;
 
КонецФункции

После проведения документа, будут записаны движения как для регистра «Продажи», так и для регистра «ОстаткиТоваров» с соответствующим знаком. Как видим, всю подсистему оперативного учета, все процедуры формирования движений документов этой [и других] подсистемы можно уместить в одном xslt-шаблоне в наглядном виде.

Примечание
Конечно, в данной процедуре нет места процедурам контроля остатка на складе и размера товарного кредита клиента после выполнения операции. Также нет места вычислениям себестоимости списанной продукции, определение партии и других «полезных» вещей. Эта методика хорошо работает там, где всего этого нет. Скажем так, если мы собираемся строить эффективную [«быструю»] конфигурацию, тогда все эти вычисления должны быть вынесены в фоновый режим. Там их проще оптимизировать.