forum.bitel.ru
http://forum.bitel.ru/

[5.2] Генерация документов по шаблону
http://forum.bitel.ru/viewtopic.php?f=23&t=7608
Страница 1 из 3

Автор:  barguzin2 [ 15 янв 2013, 14:47 ]
Заголовок сообщения:  [5.2] Генерация документов по шаблону

А что за шаблоны и как они делаются? В документации что-то ничего нет про это. New ?

Автор:  skn [ 15 янв 2013, 15:21 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

да, новое, но не совсем доделано (работает, но не все что планировалось)
можно ODF файлы в качестве шаблонов и на их основе генерить документы
напрмер у нас так генерятся договора и дополнительные соглашения.

в конфиге плагина прописывается
Код:
document.patterns=1:Заявка на доработку,2:Договор
document.pattern.1.file.path=/home/bill/BGBillingServer/contracts/dogovor.odt
document.pattern.2.file.path=/home/bill/BGBillingServer/contracts/zayvka.odt


и на договор сажается скрипт обработки события из плагина "Генерация документа"

Автор:  skyb [ 15 янв 2013, 18:15 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

так так так...поподробней, это можно карточки конвертить?

Автор:  skn [ 15 янв 2013, 19:57 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

генерировать, можно.

Автор:  skyb [ 15 янв 2013, 20:18 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

тоесть стоит плагин документс, есть документ в odt, и из odt конверт в шаблоны карточек? с сохранием форматирования? в xls?

Автор:  barguzin2 [ 15 янв 2013, 20:46 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

Да-да, поподробнее, пожалуйста. чего писать в файлах(шаблонах) и чего писать в скриптах. Плиз-плиз, хорошая весчь, очень хочется.

Автор:  skn [ 15 янв 2013, 20:54 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

рисуете документ в OpenOffice в нужные места вставляете переменные например в таком виде (можно и в другом, зависит от реализации скрипта)
на скрине пример вставки даты с форматированием и параметров из договора (по их кодам и значением по умолчанию если параметр пустой)

Вложения:
1.png
1.png [ 135.48 КБ | Просмотров: 15695 ]

Автор:  skn [ 15 янв 2013, 21:10 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

Наш обратотчик события "Генерация документа"
Код:
package generateDocument;

import generateDocument.GenerateTableForDocument;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.sql.Connection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import ru.bitel.bgbilling.kernel.filestorage.common.bean.BGServerFile;
import ru.bitel.bgbilling.kernel.filestorage.server.FileStorage;
import ru.bitel.bgbilling.kernel.plugin.server.BGPluginManagerServer;
import ru.bitel.bgbilling.kernel.plugin.server.BGPluginServer;
import ru.bitel.bgbilling.kernel.script.server.dev.EventScriptBase;
import ru.bitel.bgbilling.plugins.documents.server.bean.Document;
import ru.bitel.bgbilling.plugins.documents.server.bean.DocumentManager;
import ru.bitel.bgbilling.plugins.documents.server.bean.GenerateDocumentManager;
import ru.bitel.bgbilling.plugins.documents.server.bean.event.GenerateDocumentEvent;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.io.Base64;
import ru.bitel.common.sql.ConnectionSet;
import bitel.billing.server.util.ZipUtils;

public class GenerateDocument
    extends EventScriptBase<GenerateDocumentEvent>
{
   private GenerateDocumentEvent event = null;
   private BGPluginServer plugin = null;
   private Connection con = null;
   private Map<String, Object> paramsMap = null;

   @Override
   public void onEvent( GenerateDocumentEvent event, Setup setup, ConnectionSet set )
       throws Exception
   {
      this.event = event;
      plugin = BGPluginManagerServer.getManager().getPluginByUID( event.getPluginId() );
      con = set.getConnection();
      paramsMap = event.getParamsMap();
      if( paramsMap == null )
      {
         paramsMap = new HashMap<String, Object>();
      }
      // создаем новый документ у договора
      Document document = createDocument();
      // генерируем новый файл документа по шаблону
      String filePath = generateDocument();
      // загружаем файл документа
      uploadFile( document.getId(), filePath );
      event.setIdDocument( document.getId() );
   }

   private Document createDocument()
       throws Exception
   {
      // создаем новый документ у договора
      Document document = new Document();
      DocumentManager documentManager = new DocumentManager( con, plugin );
      document.setCid( event.getContractId() );
      document.setUser( event.getUserId() );
      document.setDate( new Date() );
      document.setType( event.getDocumentTypeId() );
      document.setJournal( event.getJournalId() );
      document.setTitle( getTitleDocument() ); // берется название шаблона
      document.setComment( "" );
      documentManager.updateDocument( "new", document );
      return document;
   }

   private String generateDocument()
       throws Exception
   {
      // разархивировали в память.
      Map<String, byte[]> docMap = ZipUtils.unZip( event.getPatternDirectory() );
      /*
       * нужные нам файлы:
       *  content.xml - содержит тело документа
       *  style.xml - содержит header и footer документа
       */
      // можно заменить данный класс, своим динамическим классом
      //В этом классе происходит генерация header'a, conten'a и footer'a
      GenerateDocumentManager generateDocumentManager = new GenerateDocumentManager( con, plugin, event.getContractId(), docMap );
      //отдельно вынесена генерация таблиц
      org.w3c.dom.Document doc = generateDocumentManager.getDocument( "content.xml" );
      GenerateTableForDocument generateTableForDocument = new GenerateTableForDocument( con, plugin, event.getContractId() );
      doc = generateTableForDocument.generateTables( doc, paramsMap );
      generateDocumentManager.setDocument( "content.xml", doc );
      //
      for ( String key : paramsMap.keySet() )
{
         System.out.println( key + " = " + paramsMap.get( key ) );
}
      generateDocumentManager.generateContent( paramsMap );
      generateDocumentManager.generateHeader( paramsMap );
      generateDocumentManager.generateFooter( paramsMap );
      //
      // заархивировали обратно в .odt
      String filePath = ZipUtils.doZip( docMap, event.getRootDirectorySave(), event.getPatternTitle() );
      return filePath;
   }

   private void uploadFile( int documentId, String filePath )
       throws Exception
   {
      // сам файл документа
      File file = new File( filePath );
      // добавляем строку
      FileStorage fileStorage = new FileStorage( event.getRootDirectorySave(), String.valueOf( plugin.getPluginUID() ), con );
      BGServerFile documentFile = new BGServerFile();
      documentFile.setOwnerId( documentId );
      documentFile.setTitle( event.getPatternTitle() );
      documentFile.setSize( file.length() );
      documentFile.setComment( "" );
      documentFile.setDate( new Date() );
      documentFile.setUserId( event.getUserId() );
      fileStorage.updateFile( documentFile );
      //
      if( documentFile.getId() > 0 )
      {
         try
         {
            // открываем поток куда писать
            FileOutputStream out = fileStorage.save( documentFile.getId() );
            // и декодируем туда
            String filedata = Base64.encode( new FileInputStream( file ) );
            Base64.decode( new ByteArrayInputStream( filedata.getBytes() ), out );
            // закрываем стрим
            out.close();
            // удаляем временный файл
            file.delete();
         }
         catch( Exception e )
         {
            // и удаляем зазря только добавленную строчку
            fileStorage.deleteFile( documentFile.getId() );
            print( "Ошибка сохранения файла.\nИли пришли битые данные файла.\n" + e.getMessage() );
         }
      }
   }
   
   private String getTitleDocument()
   {
      StringBuilder result = new StringBuilder( event.getPatternTitle() );
        String string = result.reverse().toString();
        result = new StringBuilder( string.substring( string.indexOf( "." ) + 1, string.length() ) );
        return result.reverse().toString();
   }
}


Код:
package generateDocument;

import java.sql.Connection;
import java.util.List;
import java.util.Map;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import ru.bitel.bgbilling.kernel.plugin.server.BGPluginServer;
import ru.bitel.bgbilling.plugins.documents.server.bean.GenerateDocumentManager;
import ru.bitel.common.XMLUtils;

public class GenerateTableForDocument
{
   private int contractId = -1;
   private Connection con = null;
   private BGPluginServer plugin = null;
   
   public GenerateTableForDocument( Connection con, BGPluginServer plugin, int contractId )
    {
      this.con = con;
      this.plugin = plugin;
      this.contractId = contractId;
    }
   
   //генерация одной таблицы
   public Document generateTable( List<Map<String, Object>> list, Document doc, String tableName )
   {
      GenerateDocumentManager generateDocumentManager = new GenerateDocumentManager( con, plugin, contractId );
      //получаем нужную нам таблицу
      Element table = getTableElement( doc, tableName );
      //получаем 2 строки. первая это шапка таблицы, вторая это строка с переменными
      NodeList childs = table.getChildNodes();
      boolean flag = false;
      for( int i = 0; i < childs.getLength(); i++ )
      {
         Node node = childs.item( i );
         if( node.getNodeName().equals( "table:table-row" ) )
         {
            if( flag )
            {
               //генерируем нужное кол-во строк в таблице.
               for( int j = 0; j < list.size() - 2; j ++ )
               {
                  table.appendChild( node.cloneNode( true ) );
               }
               flag = false;
               break;
            }
            else
            {
               flag = true;
            }
         }
      }
      int count = 1;
      childs = table.getChildNodes();
      for( int i = 0; i < childs.getLength(); i++ )
      {
         Node node = childs.item( i );
         if( node.getNodeName().equals( "table:table-row" ) )
         {
            // так мы пропускаем первую строку с шапкой таблицы.
            if( flag )
            {
               NodeList nodeList = node.getChildNodes(); // получили ячейки cell
               for( int k = 0; k < nodeList.getLength(); k++ )
               {
                  NodeList nL = nodeList.item( k ).getChildNodes();
                  for( int j = 0; j < nL.getLength(); j++ )
                  {
                     Node nodeItem = nL.item( j );
                     generateDocumentManager.searchVariable( nodeItem, list.get( count ) );
                  }
               }
               count++;
            }
            else
            {
               //тут смотрим есть ли в шапке таблицы переменные
               generateDocumentManager.searchTableVariable( (Element)node, list.get( 0 ) );
               flag = true;
            }
         }
      }
      return doc;
   }
   
   private Element getTableElement( Document doc, String tableName  )
   {
      Iterable<Element> iterable = XMLUtils.selectElements( doc, "//table:table" );
      for( Element element : iterable )
      {
         String name = element.getAttribute( "table:name" );
         if( name.equals( tableName ) )
         {
            return element;
         }
      }
      return null;
   }
   
   //генераця всех таблиц в документе
   public Document generateTables( Document doc, Map<String, Object> paramsMap )
   {
      for( Element element : XMLUtils.selectElements( doc, "//table:table" ) )
      {
         String name = element.getAttribute( "table:name" );
         if( paramsMap.containsKey( name ) )
         {
            doc = generateTable( (List<Map<String, Object>>)paramsMap.get( name ), doc, name );
         }
      }
      return doc;
   }
}

Автор:  skn [ 15 янв 2013, 21:16 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

skyb писал(а):
тоесть стоит плагин документс, есть документ в odt, и из odt конверт в шаблоны карточек? с сохранием форматирования? в xls?


по шаблону генериться документ и сохраняется в плагине документ или в другом месте (зависит от скрипта обработчика события)

Автор:  Phricker [ 15 янв 2013, 21:17 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

Т.е. таким образом можно полностью отказаться от карточек договора?
Сгенерировали документ - он сохранился на договоре - вуаля. печатай всегда когда влезет.

Автор:  barguzin2 [ 15 янв 2013, 21:55 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

Идея, конечно, хорошая, но я себе представлял это несколько проще - в скрипте формируется например HashMap, а уже в шаблоне пишешь просто $PARAM(ParamName,DefaultValue), где ParamName-ключ хеша. Ну и дальше вызывается метод класса, формирующий файл - в документ, на диск или что-то еще.Или лучше $PARAM оставить для параметров договора и плюс сделать еще один макрос для пользовательских данных, чтобы в скрипте не писать код выборки параметров. Ну и еще добавить несколько каких-нибудь часто востребованных макросов, типа как вижу $DATE_NOW. Кстати, какие макросы вообще доступны ?

Какие планы по доработке этого функционала ? Я думаю это будет многим интересно.

Автор:  barguzin2 [ 15 янв 2013, 22:10 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

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

Автор:  skn [ 16 янв 2013, 00:46 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

barguzin2 писал(а):
А еще лучше не через функции скриптов поведения, а через дин.код. Делаем класс и привязываем его к соответствующему типу документа. Тогда еще и не надо будет на договор скрипт поведения добавлять.


в принципе как то так и задумылось, но пока сделали так как есть.

Автор:  skn [ 16 янв 2013, 00:58 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

barguzin2 писал(а):
Идея, конечно, хорошая, но я себе представлял это несколько проще - в скрипте формируется например HashMap, а уже в шаблоне пишешь просто $PARAM(ParamName,DefaultValue), где ParamName-ключ хеша. Ну и дальше вызывается метод класса, формирующий файл - в документ, на диск или что-то еще.Или лучше $PARAM оставить для параметров договора и плюс сделать еще один макрос для пользовательских данных, чтобы в скрипте не писать код выборки параметров. Ну и еще добавить несколько каких-нибудь часто востребованных макросов, типа как вижу $DATE_NOW. Кстати, какие макросы вообще доступны ?

Какие планы по доработке этого функционала ? Я думаю это будет многим интересно.


ну вобще сейчас и используется мап
Код:
paramsMap = event.getParamsMap();

он заполняется при генерации события и передается в скрипт

в принципе задумка была такая:
делается некий гуи конструктор в котором можно настраивать формирование документа
1) вбиваем название
2) выбираем файл с шаблоном
3) задаем набор переменных которые прописаны в шаблоне, при этом для каждой переменной задаем что то типа экстрактора, напрмер
- "константа" (+ значение констатнты)
- "параметр договора" (+ код параметра)
- "sql запрос" (+ сам запрос и куда посылать)
- "URL" (+ адрес)
- "FILE" ( + путь)
и т.д.
4) формирование данных для заполнение таблиц
5) название(шаблон) результирующего документа
6) куда его сохранить (в плагин, на диск в папку, отправить на мыло и т.д.)

вот такое было ТЗ, а текущий результат ... :-(

Автор:  Phricker [ 16 янв 2013, 01:04 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

skn писал(а):
вот такое было ТЗ, а текущий результат ... :-(

Не заплатили? :D

Автор:  skn [ 16 янв 2013, 01:06 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

Phricker писал(а):
skn писал(а):
вот такое было ТЗ, а текущий результат ... :-(

Не заплатили? :D


не совсем так, ТЗ ставил один, делал второй, курировал третий....

Автор:  Phricker [ 16 янв 2013, 01:11 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

skn писал(а):
а если так
Код:
document.patterns=1:Договор
document.pattern.1.file.path=/opt/BG/BGBillingServer/contracts/dogovor_ul.odt

Заработало. Сгенерировало по крайней мере :)
Чтобы подставляло правильные параметры придется поковыряться значит. что то так с лету не взяло. или я не допонял как делать. ничо. метод тыка он спасает и не из таких ситуаций

Автор:  skn [ 16 янв 2013, 01:21 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

там очень акуратно надо быть при составление шаблона
сам только сегодня мучился... с одной переменной
вообщем рецепты такие
1) выделяем всю переменную и удалям с нее все форматирование (не знаю как в WORDе, а в Libre есть в контестном меню такой пунктик "Очистить форматирование"), а затем если нужно как то отформатировать вставляемую переменную, форматируем ТОЛЬКО выделеив ее ЦЕЛИКОМ иначе в исходниках ODF текст переменной разбивается xml тегами на несколько частей и прога не может их найти
2) или переименовываем файл *.odt в *.zip распаковываем и правим в тектовом редакторе context.xml, запаковываем обратно, переименовываем в odt
3) или можно попробовать так, выделяем переменную, вырезаем в буфер, затем вставляем через меню, как специальная вставка, неформатированный текст
4) или так выделяем, вырезаем, вставляем в блокнот, выделяем в блокноте, вырезаем, вставляем обратно в шаблон документа

Автор:  Phricker [ 16 янв 2013, 01:44 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

Да. Помогло действительно :D Параметры договора вставились
Очень и очень неплохая замена карточкам договора.
А то пришлось карточки делать без картинок (ЕМНИМС была проблема с доступом к файлу картинки из разных мест. кто то заходил только по локалке, кто то через pppoe. Плюс это делалось еще в 5.1 а там FOP из картинки делал такое убожество что хотелось плакать :D), а тут в шаблоне все прекрасно вставляется. Заебися :idea:

Автор:  skyb [ 16 янв 2013, 05:18 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

А обязательно плагин ставить? или без него генерить можно?

Автор:  skn [ 16 янв 2013, 11:06 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

skyb писал(а):
А обязательно плагин ставить? или без него генерить можно?

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

Автор:  Phricker [ 16 янв 2013, 11:13 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

И открытие документов в WEB кабинете, в клиенте биллинга и т.п. :D

Автор:  barguzin2 [ 17 янв 2013, 13:42 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

Код:
paramsMap = event.getParamsMap();


Этот paramsMap пустой. Как мне передать в шаблон данные, отличные от параметров договора (например ТП) и в какой макрос писать в шаблоне чтобы эти данные вставились?

Автор:  skn [ 17 янв 2013, 16:38 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

или при генерации события заполнить или в обработчике дозаполнить

например если в обработчике, то добавляете блок кода с проверкой типа если шаблон == такой, то
через DAO или SQL достаете что надо и толкает в мап, под любым ключом, например CTP, потом в шаблоне где надо вставляете
$CTP

Вложения:
1.png
1.png [ 138.35 КБ | Просмотров: 15641 ]

Автор:  barguzin2 [ 17 янв 2013, 20:51 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

Ага, разобрался. Спасибо. Эх, конечно не хватает формы заполнения параметров дополнительных (вводимых вручную перед генерированием документа), которые в биллинге не фигурируют. Да еще привязку разных классов к разным шаблонам и было бы совсем здорово. Планируется ?

Автор:  skn [ 18 янв 2013, 01:39 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

да

Автор:  skyb [ 18 янв 2013, 05:24 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

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

Автор:  barguzin2 [ 18 янв 2013, 08:54 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

Как я думаю имя файла и название документа тоже будут(?) вручную задаваться как параметры при формировании документа.

Автор:  skyb [ 22 янв 2013, 06:02 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

и ещё вопрос, а нельзя как то сделать чтоб с клиента биллинга документы загружались на сервер и потом уже с ними происходили манипуляции? просто получается такая картина
1. Админ составляет скелет документа, где должны быть автоподстановки, и отсылает манагерам которые потом правят сам документ.
2. Манагеры правят документ как им нада, отсылают админу
3. Админ заливает на на сервак.

Понятно что первый пункт по большей части сделать нада тока 1 раз. Но ведь можно и убрать и 3-ий пунк, оставить работу с документами полностью манагерам.

И все ещё мучают имена

Автор:  skn [ 22 янв 2013, 13:10 ]
Заголовок сообщения:  Re: [5.2] Генерация документов по шаблону

skyb писал(а):
и ещё вопрос, а нельзя как то сделать чтоб с клиента биллинга документы загружались на сервер и потом уже с ними происходили манипуляции? просто получается такая картина
1. Админ составляет скелет документа, где должны быть автоподстановки, и отсылает манагерам которые потом правят сам документ.
2. Манагеры правят документ как им нада, отсылают админу
3. Админ заливает на на сервак.

Понятно что первый пункт по большей части сделать нада тока 1 раз. Но ведь можно и убрать и 3-ий пунк, оставить работу с документами полностью манагерам.


не совсем понял зачем нужен первый пункт...
у вас админ секретарем и юристом подрабатывает?

Страница 1 из 3 Часовой пояс: UTC + 5 часов [ Летнее время ]
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/