Транзакционная печать на примере БП3 и УТ10

13.10.17

Разработка - Механизмы платформы 1С

Рассмотрим недостатки типовой подсистемы печати и один из вариантов её обхода – запись в транзакции модифицированного объекта, его печать и откат назад в исходное состояние на примерах для БП3 и УТ10.

Недостатки типовой подсистемы печати

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

Очень жаль, что методисты из 1С не могут придумать рациональные и удобные подходы и алгоритмы к печати. 

Основные недостатки подсистемы печати:

  1. В БП3 (и прочих конфигурациях на УФ) система почему-то заточена на быстродействие. Хотя любой принтер печатает медленнее, чем формируется форма. Зачем собирать несколько объектов в одном запросе, непонятно. Ведь код печати одного объекта был бы намного проще.
    Зачем эти сэкономленные миллисекунды исполнения, когда за ними стоят долгие часы разбирательств программистов в полученных сложных запросах?
    Подстановка в макеты используется перебором объекта ВыборкаИзРезультатаЗаброса, а его изменить нельзя, т.е. если нужно поставить небольшую заплатку, заменив типовое значение на свое, не получится, приходится чрезмерно усложнять код.
  2. В УТ10 нет единой точки в процедуру печати объекта, соответственно, если стоит задача перехватывать любую печать любого документа, не получится.

Транзакционная печать в БП3

Была поставлена задача – каждая строчка накладной реализации могла быть разбита на поставки несколькими машинами.

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

 

 

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

Вот образцы полученных печатных форм.

Вся накладная, 20 брусов:

Первая машина, 18 брусов:

Вторая машина, 2 бруса (с маслом тут ошибка, потом она была исправлена):

 

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

Дело в том, что печать реализации в БП3 может происходить в менеджере документа и в обработках типа «Печать ТТН».

В модуль УправлениеПечатьюСлужебныйКлиент в процедуру ВыполнитьПодключаемуюКомандуПечатиЗавершение, перед выполнением команды печати вставить код, определяющий, нужно использовать транзакционную печать или нет:

 

//ИЗМ Осипов 2016-03-20 ТранзакционнаяПечать чтобы выбрать текущую машину при печати накладной +
    Попытка
        ОписаниеКоманды.ДополнительныеПараметры.Вставить("ТекущаяМашина", ДополнительныеПараметры.Форма._ТекущаяМашина);
    Исключение
    КонецПопытки;
    //ИЗМ Осипов 2016-03-20 чтобы выбрать текущую машину при печати накладной -


…
Обработчик = ИмяОбработчика + "(ОписаниеКоманды)";
    Результат = Вычислить(Обработчик);

В процедуре СформироватьПечатныеФормы модуля УправлениеПечатью добавить в самом начале:

 //ИЗМ Осипов 2016-03-30 ТранзакционнаяПечать меняем объекты, соответственно номеру машины +
    Если ПараметрыПечати.Свойство("_ТекущаяМашина") И ПараметрыПечати._ТекущаяМашина <> 0 Тогда
        НачатьТранзакцию();
        Для Каждого Элемент Из МассивОбъектов Цикл
            Если ТипЗнч(Элемент) = Тип("ДокументСсылка._ЗаявкаПокупателя") Тогда
                ДО = Элемент.ПолучитьОбъект();
                Если ИмяМенеджераПечати = "Обработка.ПечатьТТН" Тогда
                    ДО.Номер = "66666666";
                КонецЕсли;
                _ДопСервер.ОбработатьДокументЗаявкиПокупателяДляПечати(ДО, ПараметрыПечати._ТекущаяМашина);
                ДО.ОбменДанными.Загрузка = истина;
                ДО.Записать();
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    //ИЗМ Осипов 2016-03-30 ТранзакционнаяПечать меняем объекты, соответственно номеру машины -

И в самом конце этого модуля, перед возвратом результата, код по откату транзакции:

//ИЗМ Осипов Откатываем 2016-03-20 ТранзакционнаяПечать +
    Если ПараметрыПечати.Свойство("_ТекущаяМашина") И ПараметрыПечати._ТекущаяМашина <> 0 Тогда
        ОтменитьТранзакцию();
        Сч = 0;
        Для Каждого ТекПечатнаяФорма ИЗ КоллекцияПечатныхФорм Цикл
            Сч = СЧ + 1;
            Если Сч > ОбъектыПечати.Количество() Тогда Продолжить; КонецЕсли;
            ТекОбъект = ОбъектыПечати[Сч - 1];

            ПравильныйНомер = ПрефиксацияОбъектовКлиентСервер.ПолучитьНомерНаПечать(ТекОбъект.Значение.Номер, Истина, Ложь);
            ПравильныйНомер = ПравильныйНомер + "/" + ПараметрыПечати._ТекущаяМашина;

            ТекОбласть = ТекПечатнаяФорма.ТабличныйДокумент.НайтиТекст("66666666", , , );
            Если ТекОбласть <> Неопределено Тогда
                ТекОбласть.Текст = ПравильныйНомер;
            КонецЕсли;

        КонецЦикла;

    КонецЕсли;
    //ИЗМ Осипов 2016-03-20 ТранзакционнаяПечать -

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

Ну и соответственно, код, который обрабатывает документ перед печатью в случае, когда требуется вывести данные только по одной машине, а не в целом по документу:

Функция ОбработатьДокументЗаявкиПокупателяДляПечати(ДО, НомерМашины) Экспорт
    Всего = ДО.Товары.Количество();
    Для Инд = 1 ПО Всего Цикл
        Строка = ДО.Товары[Всего-Инд];
        ИскСтрокиМашин = ДО._Машины.НайтиСтроки(Новый Структура("_КлючСтроки", Строка._КлючСтроки));
        ОбщееКоличествоПоМашинам = 0;
        РезКоличество = 0;
        Для Каждого ИскСтрокаМашин ИЗ ИскСтрокиМашин Цикл
            ОбщееКоличествоПоМашинам = ОбщееКоличествоПоМашинам + ИскСтрокаМашин.Количество;
            Если ИскСтрокаМашин.НомерМашины = НомерМашины Тогда
                РезКоличество = ИскСтрокаМашин.Количество;
            КонецЕсли;
        КонецЦикла;
        //Если по машинам не распределено
        Если ОбщееКоличествоПоМашинам = 0 Тогда
            РезКоличество = Строка.Количество;
        КонецЕсли;
        ИсходноеКоличество = Строка.Количество;
        Строка.Количество = РезКоличество;
        Если Строка.Количество = 0 ИЛИ ИсходноеКоличество = 0 Тогда
        Иначе
            //Делим суммы пропорционально количеству
            Строка.Сумма = Строка.Сумма * Строка.Количество / ИсходноеКоличество;
            Строка.СуммаНДС = Строка.СуммаНДС * Строка.Количество / ИсходноеКоличество;
        КонецЕсли;

    КонецЦикла;
КонецФункции

Обратите внимание, как обработана замена номера, чтобы печатался номер машины через слэш.

Транзакционная печать в УТ10

В УТ10 мне понадобилась транзакционная печать в других целях. Заказчик поставил задачу заменять при печати наименование товара во всех торговых документах. Если бы это происходило всегда, можно было бы поменять полное наименование, но нужно было чтобы старые документы перепечатывались бы без изменения.

Соответственно, перед печатью документа нужно изменять наименование товара:

Функция НужнаТранзакционнаяПечать(Объект)Экспорт
    //Осипов 2016-03-24 Замена наименования... +++
    Если Объект.Дата >= '20160323' И НЕ Объект.Модифицированность() Тогда
        ТранзакцияОткрыта = ложь;
        ТекСсылка = Объект.Ссылка;
        Если ТипЗнч(ТекСсылка) = Тип("ДокументСсылка.СчетФактураВыданный")  Тогда
            ТекСсылка = ТекСсылка.ДокументОснование;
        КонецЕсли;      Если ТекСсылка.Метаданные().ТабличныеЧасти.Найти("Товары") <> Неопределено Тогда
            Маркер = "Палка "; ДлинаМаркера = СтрДлина(Маркер);
            НовыйМаркер = "Палка для коррекции ";
            ДлинаНовогоМаркера = СтрДлина(НовыйМаркер);
            Для Каждого ТекСтрока Из ТекСсылка.Товары Цикл
                ТекНаименование = ТекСтрока.Номенклатура.НаименованиеПолное;
                Если
                    Лев(ТекНаименование, ДлинаМаркера) = Маркер И
                    Лев(ТекНаименование, ДлинаНовогоМаркера) <> НовыйМаркер
                Тогда
                    Если НЕ ТранзакцияОткрыта Тогда
                        НачатьТранзакцию();
                        ТранзакцияОткрыта = истина;
                    КонецЕсли;
                    О = ТекСтрока.Номенклатура.ПолучитьОбъект();
                    О.НаименованиеПолное = СтрЗаменить(О.НаименованиеПолное, Маркер, НовыйМаркер);
                    О.ОбменДанными.Загрузка = истина;
                    О.Записать();;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
    КонецЕсли;
    //Осипов 2016-03-24 Замена наименования... --

    Возврат ТранзакцияОткрыта;
КонецФункции

Осталось выяснить, где вставить вызов этой процедуры.

Печать происходит методами Объект.Печать и НапечататьВнешнююФорму.

Эти методы вызываются в модуле УниверсальныеМеханизмы в двух  местах - в процедуре ОткрытьФормуВыбораПечатныхФормОбъекта и ПечатьПоДополнительнойКнопке. Да, программистам 1С не хватило ума вынести одинаковый код в отдельную функцию, мы наблюдаем обычный копи-паст.

Если ... Тогда
    ТабДокумент = НапечататьВнешнююФорму(Объект.Ссылка, Расшифровка);
    НапечататьДокумент(ТабДокумент,  ....);
Иначе
    Объект.Печать(...);
КонецЕсли;

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

В случае ошибки может долго висеть предупреждение, и транзакция будет открыта, это недостатки решения, но такое бывает редко. В УФ отказались от модальности, такое не грозит.

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

Транзакция сама откатывается, массовых печатей нет. Но даже если будет массовая печать, не страшно - замена пройдет нормально, дважды маркер меняться не будет.

Вот как вставлять вызов процедуры:

печать транзакции

См. также

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Обмен между базами 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    4543    dsdred    53    

72

Как готовить и есть массивы

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

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

24.01.2024    5296    YA_418728146    25    

63

Планы обмена VS История данных

Обмен между базами 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    6411    dsdred    36    

112

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    18479    SeiOkami    46    

118

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    12090    human_new    27    

74

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    8828    YA_418728146    6    

141

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6281    sebekerga    54    

94

Все скопируем и вставим! (Буфер обмена в 1С 8.3.24)

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Рассмотрим новую возможность 8.3.24 и как её можно эффективно использовать

27.06.2023    15988    SeiOkami    31    

103
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. shard 279 18.10.17 13:16 Сейчас в теме
я в подобных ситуациях (когда требуется изменить результат запроса, текст которого очень не хочется ковырять) применяю врезку:
1) выгружаю результат типового запроса в таблицу
2) обрабатываю таблицу как необходимо
3) получившуюся таблицу передаю параметров в свой запрос, результат которого записываю в переменную выборки или результата типового запроса
Оставьте свое сообщение