16 февраля 2016 г.

1С 8.2 Счет на оплату с печатями и подписями


Многим рассказываю про такую штуку, и многие хотят, реализуя под каждого я нашел несколько вариантов у каждого есть свои плюсы и минусы.

Конфигурации и задачи:

  1. УТ 10.3.31.3
    СнаОПок с печатью и подписями. Подписи варьируются в зависимости от ответственного лица. Работа выполняется на терминальном сервере
  2. БП 2.0.64.20
    СнаОПок с печатью и подписями. Работа выполняется в расшаренной базе
  3. УПП 1.3.35.2
    СнаОПок с печатью и подписями. Печати и подписи варьируются в зависимости от организации. Работа выполняется с терминала на сервере 1С.

Сначала создадим внешнюю печатную форму "Счет на оплату покупателю". Далее берем печати, подписи и сканируем в самом лучшем качестве. Каким либо инструментом удаляем белый фон, должен остаться прозрачный (я в Ps использую Волшебную палочку с разными уровнями допуска, ножницы и Затемнитель для контраста). Итоговый размер печатей должен быть одинаковым вплоть до пикселя, лучше ориентироваться на миллиметровый реальный размер. Размер подписей подгоняем под один (берем самую большую подпись, ставим ей минимальные отступы от края, все остальные подписи должны размещаться на подложке тех же размеров что и большая).
Расширение файла PNG!
Приступаем к реализации.

УТ

Данную задачу я решил просто:
  1. Печать добавлена из пункта "Выбор картинки"-"Из файла" в макете

    Выбираем файл, масштабируем его и располагаем как надо
  2. Далее также устанавливаем подписи главбуха и директора
  3. Вот и дошли до вкусненького, необходимо вставлять подписи ответственного по условию:
    Создаем реквизиты обработки:
      ОтветственныйИванов
      ОтветственныйПупкин
      ОтветственныйГраждов
    В блоке определения ответственных лиц и подстановки расшифровки добавляем (выделено комментарием):
    
    Если Тип = "Счет" Тогда
      Руководители = РегламентированнаяОтчетность.ОтветственныеЛицаОрганизации(Шапка.Руководители, Шапка.Дата,);
      Руководитель = Руководители.Руководитель;
      ДолжностьРуководителя = Руководители.РуководительДолжность;
      Бухгалтер    = Руководители.ГлавныйБухгалтер;
      
      ПараметрыПечати.Вставить("ФИОРуководителя",   Руководитель);
      ПараметрыПечати.Вставить("ДолжностьРуководителя",  ДолжностьРуководителя);
      ПараметрыПечати.Вставить("ФИОБухгалтера",    Бухгалтер);
      
      Если НЕ ЗначениеЗаполнено(Ответственный.ФизЛицо) Тогда
       ФИООтветственный = СокрЛП(Ответственный);
      Иначе
       ФамилияИмяОтчествоФизЛица        = ФормированиеПечатныхФорм.ФамилияИмяОтчество(Ответственный.ФизЛицо, Шапка.Дата);
       ФамилияИмяОтчествоОтветственного = ФамилияИмяОтчествоФизЛица.Фамилия + " " + ФамилияИмяОтчествоФизЛица.Имя + " " + ФамилияИмяОтчествоФизЛица.Отчество;
       ФИООтветственный            = ОбщегоНазначения.ФамилияИнициалыФизЛица(ФамилияИмяОтчествоОтветственного);
      КонецЕсли;
      ПараметрыПечати.Вставить("ФИООтветственный", ФИООтветственный);
      //Для ПОДПИСИ ОТВЕТСТВЕННОГО ЛИЦА
      ЭтотОбъект.ОтветственныйИванов="D:\Обработчики\pict\ивнов.png";
      ЭтотОбъект.ОтветственныйГраждов="D:\Обработчики\pict\граждов.png";
      ЭтотОбъект.ОтветственныйПупкин="D:\Обработчики\pict\пупкин.png";
      //Для ПОДПИСИ ОТВЕТСТВЕННОГО ЛИЦА
     КонецЕсли;
    
    В выводе макета поле вывода СуммаПрописью выводим наши картинки (прошу обратить внимание, по глупости размеры подписей у меня были разные, поэтому пришлось настраивать каждую картинку в отдельности):
    
    // Вывести подписи
    Если Тип = "Счет" Тогда
     ОбластьМакета = Макет.ПолучитьОбласть("ПодвалСчета");
      //ПОДПИСЬ ОТВЕТСТВЕННОГО НАЧАЛО
     Если ПараметрыПечати.ФИООтветственный="Иванов С.С." ИЛИ
       ПараметрыПечати.ФИООтветственный="Пупкин А.А." ИЛИ
       ПараметрыПечати.ФИООтветственный="Граждов В.В."
       ТОГДА
      Рисунок = ОбластьМакета.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка); 
      Если  ПараметрыПечати.ФИООтветственный="Иванов С.С." Тогда
       Картинка=ЭтотОбъект.ОтветственныйИванов;
       Рисунок.Высота = 15; 
       Рисунок.Ширина = 15; 
       Рисунок.Верх = 25;
       Рисунок.Лево = 105;
      ИначеЕсли  ПараметрыПечати.ФИООтветственный="Пупкин А.А." Тогда
       Картинка=ЭтотОбъект.ОтветственныйПупкин;
       Рисунок.Высота = 25; 
       Рисунок.Ширина = 40; 
       Рисунок.Верх = 22;
       Рисунок.Лево = 105;
      ИначеЕсли ПараметрыПечати.ФИООтветственный="Граждов В.В." Тогда
       Картинка=ЭтотОбъект.ОтветственныйГраждов;
       Рисунок.Высота = 25; 
       Рисунок.Ширина = 40; 
       Рисунок.Верх = 20;
       Рисунок.Лево = 105;
      КонецЕсли;
      Рисунок.Линия=новый линия(типлиниирисункатабличногодокумента.НетЛинии);
      Рисунок.ГраницаСверху=Ложь;
      Рисунок.ГраницаСлева=Ложь;
      Рисунок.ГраницаСнизу=Ложь;
      Рисунок.ГраницаСправа=Ложь;
      Рисунок.ВыводитьНаПечать=Истина;
      Рисунок.Картинка= Новый Картинка(Картинка,Истина) ;
      Рисунок.РазмерКартинки = РазмерКартинки.Растянуть;
      Рисунок.Узор=ТипУзораТабличногоДокумента.БезУзора;
     Иначе        
    КонецЕсли;
    //ПОДПИСЬ ОТВЕТСТВЕННОГО Конец
    
    
  4. Подстраиваем размеры и положение параметрами (параметры в 1С измеряются в мм) рисунка. 
Мои ошибки, создание реквизитов не обязательно, зачем лишний код?
Минусы данного решения:
  1. Программист должен заранее знать ФИО сотрудника
  2. Такую обработку нельзя использовать на расшаренных базах, так как местоположение картинок локальное
  3. Перенести без изменения кода или эмуляции пути не получится
  4. Кадровые перемещения будут требовать вмешательства программиста
Плюсы данного решения:
  1. Картинки можно подменить без программиста

БП

Здесь я столкнулся как раз с проблемой расшаренных ресурсов, но по задаче нужно было одну подпись на главбуха и директора и одну печать.
Я решил встроить изображения прямо в обработку.
  1. В нашей обработке добавляем макет с типом "Двоичные данные", и загружаем туда картинку :-). Имена лучше использовать ЧеловекоПонимаемые. У меня это печать и подпись
  2. Теперь кодом вытаскиваем картинки из макетов, как обычно располагаемся в Если Тип="Счет" в самом конце.
    
    //Вытаскиваем рисунок
    ПечатьМакет=ЭтотОбъект.ПолучитьМакет("Печать");
    ПечатьХранилище=Новый ХранилищеЗначения(ПечатьМакет);
    ПечатьКартинка=ПечатьХранилище.Получить();
    Рисунок = ОбластьМакета.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка); 
    //играем с размерами объекта
    Рисунок.Высота = 45; 
    Рисунок.Ширина = 45; 
    Рисунок.Верх = 0;
    Рисунок.Лево = 45;
    Рисунок.Линия=новый линия(ТипЛинииРисункаТабличногоДокумента.НетЛинии);
    Рисунок.ГраницаСверху=Ложь;
    Рисунок.ГраницаСлева=Ложь;
    Рисунок.ГраницаСнизу=Ложь;
    Рисунок.ГраницаСправа=Ложь;
    Рисунок.ВыводитьНаПечать=Истина;
    Рисунок.Картинка= Новый Картинка(ПечатьКартинка,Истина) ; //Заталкиваем картинку в объект
    Рисунок.РазмерКартинки = РазмерКартинки.Растянуть;
    Рисунок.Узор=ТипУзораТабличногоДокумента.БезУзора;
    
    
    ПодписьМакет=ЭтотОбъект.ПолучитьМакет("Подпись");
    ПодписьХранилище=Новый ХранилищеЗначения(ПодписьМакет);
    ПодписьКартинка=ПодписьХранилище.Получить();
    РисунокПодпись = ОбластьМакета.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка); 
    
    РисунокПодпись.Высота = 18; 
    РисунокПодпись.Ширина = 45; 
    РисунокПодпись.Верх = 10;
    РисунокПодпись.Лево = 24;
    РисунокПодпись.Линия=новый линия(ТипЛинииРисункаТабличногоДокумента.НетЛинии);
    РисунокПодпись.ГраницаСверху=Ложь;
    РисунокПодпись.ГраницаСлева=Ложь;
    РисунокПодпись.ГраницаСнизу=Ложь;
    РисунокПодпись.ГраницаСправа=Ложь;
    РисунокПодпись.ВыводитьНаПечать=Истина;
    РисунокПодпись.Картинка= Новый Картинка(ПодписьКартинка,Истина) ;
    РисунокПодпись.РазмерКартинки = РазмерКартинки.Растянуть;
    РисунокПодпись.Узор=ТипУзораТабличногоДокумента.БезУзора;
    
В принципе все, обработка работает
Минусы данного решения:
  1. Для редактирования нужно звать программиста
Плюсы данного решения:
  1. Нет привязки к определенному ПК
Поправка 27.04.2017:
Можно воспользоваться функцией СтрокаСоединенияИнформационнойБазы(); она вернет путь до базы, т.о. мы сможем обратится к папке с картинками из любого места.

УПП

Вот здесь задача сложнее. В базе ведется несколько фирм с разными бухами и директорами.
  1. Здесь я решил использовать "Хранилище дополнительной информации":

    Соответственно для нужных организаций и физлиц я создал изображения Печать и Подпись. Здесь я уже четко соблюдал размеры
  2. Вставляем печать:
    
    ПустаяСсылкаОбСпр=Справочники.ХранилищеДополнительнойИнформации.ПустаяСсылка();
    СсылкаНаФайл=ЗапросФайла(СсылкаНаОбъект.Организация.Ссылка,"Печать",ПустаяСсылкаОбСпр);
    Если НЕ СсылкаНаФайл=ПустаяСсылкаОбСпр Тогда
     ПечатьКартинка=СсылкаНаФайл.Хранилище.Получить();
     Рисунок = ОбластьМакета.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
     Рисунок.Высота = 40; 
     Рисунок.Ширина = 40; 
     Рисунок.Верх = 0;
     Рисунок.Лево = 110;
     Рисунок.Линия=новый линия(ТипЛинииРисункаТабличногоДокумента.НетЛинии);
     Рисунок.ГраницаСверху=Ложь;
     Рисунок.ГраницаСлева=Ложь;
     Рисунок.ГраницаСнизу=Ложь;
     Рисунок.ГраницаСправа=Ложь;
     Рисунок.ВыводитьНаПечать=Истина;
     Рисунок.Картинка= ПечатьКартинка;
     Рисунок.РазмерКартинки = РазмерКартинки.Растянуть;
     Рисунок.Узор=ТипУзораТабличногоДокумента.БезУзора;
    КонецЕсли;
    
    Ниже функция ЗапросФайла:
    
    //Запрашиваем файл в ХранилищеДополнительнойИнформации
    //Объект <Ссылка> на кого ищем (в этом случае Организации/ФизЛица)
    //Название <Строка> Название файла в БД (конктретно ищем печать/подпись)
    //
    Функция ЗапросФайла(Объект,Название,ПустаяСсылкаОбСпр) Экспорт
      
      ЗапросНаФайл=Новый Запрос;
      ЗапросНаФайл.Текст="ВЫБРАТЬ
                         | ХранилищеДополнительнойИнформации.Ссылка
                         |ИЗ
                         | Справочник.ХранилищеДополнительнойИнформации КАК ХранилищеДополнительнойИнформации
                         |ГДЕ
                         | ХранилищеДополнительнойИнформации.Объект = &Объект
                         | И ХранилищеДополнительнойИнформации.Наименование = &Наименование";
      ЗапросНаФайл.Параметры.Вставить("Объект",Объект);
      ЗапросНаФайл.Параметры.Вставить("Наименование",Название);
      ЗапросНаФайлВыполнить=ЗапросНаФайл.Выполнить();
      Если ЗапросНаФайлВыполнить.Пустой() Тогда
       Возврат(ПУстаяСсылкаОбСпр);
      Иначе
       Результат=ЗапросНаФайлВыполнить.Выбрать();
       Пока Результат.Следующий() Цикл
        Возврат(Результат.Ссылка);
       КонецЦикла;
      КонецЕсли; 
    КонецФункции
    
    
  3. Далее у нас проблема, как получить ответственных лиц? Для себя я решил эту проблему так:
    
    ЗапросПоЛицам = Новый Запрос();
    ЗапросПоЛицам.УстановитьПараметр("Организация", Шапка.Руководители);
    ЗапросПоЛицам.УстановитьПараметр("ДатаСреза",   Шапка.Дата);
    ЗапросПоЛицам.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
                          | ОтветственныеЛицаОрганизацийСрезПоследних.ОтветственноеЛицо,
                          | ОтветственныеЛицаОрганизацийСрезПоследних.Должность.Наименование КАК Должность,
                          | ОтветственныеЛицаОрганизацийСрезПоследних.ФизическоеЛицо.Ссылка
                          |ИЗ
                          | РегистрСведений.ОтветственныеЛицаОрганизаций.СрезПоследних(&ДатаСреза, СтруктурнаяЕдиница = &Организация) КАК ОтветственныеЛицаОрганизацийСрезПоследних
                          |  ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ФИОФизЛиц.СрезПоследних(&ДатаСреза, ФизЛицо ССЫЛКА Справочник.ФизическиеЛица) КАК ФИОФизЛицСрезПоследних
                          |  ПО ОтветственныеЛицаОрганизацийСрезПоследних.ФизическоеЛицо = ФИОФизЛицСрезПоследних.ФизЛицо";
    
    
    Т.е. запросом получаем ответственных лиц с отбором по организации.
  4. Далее обходим результат запроса, ищем в Должности "Главный бухгалтер" или "Генеральный директор":
    
    Рез=ЗапросПоЛицам.Выполнить().Выбрать();
    Пока Рез.Следующий() Цикл
    //Получаем ссылку на физлицо
     СсылкаНаСпрФизЛица=?(Рез.Должность="Главный бухгалтер",Рез.ФизическоеЛицоСсылка,?(Рез.Должность="Генеральный директор",Рез.ФизическоеЛицоСсылка,Ложь));
    //Пропускаем итерацию, если ссылка не получена
     Если СсылкаНаСпрФизЛица=Ложь Тогда Продолжить КонецЕсли;
    //Получаем ссылку на картинку
     СсылкаНаФайл=ЗапросФайла(СсылкаНаСпрФизЛица,"Подпись",ПустаяСсылкаОбСпр);
     Если НЕ СсылкаНаФайл=ПустаяСсылкаОбСпр Тогда
      ПечатьКартинка=СсылкаНаФайл.Хранилище.Получить();
      Рисунок = ОбластьМакета.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
      Рисунок.Высота = 20; 
      Рисунок.Ширина = 22; 
      Рисунок.Верх = ?(Рез.Должность="Главный бухгалтер",12,?(Рез.Должность="Генеральный директор",0,0));
      Рисунок.Лево = 100;
      Рисунок.Линия=новый линия(ТипЛинииРисункаТабличногоДокумента.НетЛинии);
      Рисунок.ГраницаСверху=Ложь;
      Рисунок.ГраницаСлева=Ложь;
      Рисунок.ГраницаСнизу=Ложь;
      Рисунок.ГраницаСправа=Ложь;
      Рисунок.ВыводитьНаПечать=Истина;
      Рисунок.Картинка= ПечатьКартинка;
      Рисунок.РазмерКартинки = РазмерКартинки.Растянуть;
      Рисунок.Узор=ТипУзораТабличногоДокумента.БезУзора;
     КонецЕсли;
    
    КонецЦикла;  
    
    
Если все правильно, то оно должно работать. Если обратили внимание, тернарным оператором подгоняем положение по-вертикали подписи. В этой реализации мне не понравилось то, что изначально при формировании счета не выгребаются ссылки на ответственных лиц, поэтому приходится придумывать вот такой костыль.

Минусы данного решения:
  1. Не нужно звать программиста, если бухгалтер сообразителен
Плюсы данного решения:
  1. Нет привязки к ПК
  2. Легко перенести в другую базу (конф-ция должна быть идентична)/компьютер
  3. Настраивается без программиста ("Просто добавь картинки")
На этом все, теперь Вы можете выбрать как решить поставленную задачу.

У кого есть свои решения, предлагайте.

Комментариев нет:

Отправка комментария