После 10000 часов SAP — это просто :) Так как я окончательно ушел из скучного консалтинга, в основном буду писать о веселом SAP HighTech :)
Многие пользователи любят получать данные из SAP удаленно. Пришел на работу, а в почте XLS отчетик лежит со всей необходимой информацией, который заботливо подготовил SAP сервер ночью в фоновом режиме.
Пока в памяти свежа потеря пары часов разработки, опишу как избежать некоторых трудностей при решении такой простой интеграционной задачи.
Существует много велосипедов для генерации XLS. Правда большинство из них сделаны на технологии OLE, поэтому не запустятся в фоне на сервере . Остается всего 2 варианта: CL_FDT_XL_SPREADSHEET или XLST
1. Надо сохранить свой XLS шаблон в формате XML2003, создать и осознанно перенести часть файла в тр. STRANS по инструкции. (Имя трансформации в примере XSLT_REPORT1)
Важно не забыть удалить тег ExpandedRowCount или добавить ему количества побольше. Можно 99999. Иначе вложенный файлик не захочет открываться, ссылаясь на то, что «файл поврежден, его невозможно открыть». Более свежие версии Excel сжалятся и укажут, что лог ошибки можно прочитать в текстовом файлике в папке disk:\Users\You\AppData\Local\Microsoft\Windows\INetCache\Content.MSO\
Ошибка XML в «Настройка листа»
Причина: Ошибочное значение
Файл: C:\Users\Utilisateur\Desktop\Отчет.XLS
Группа: Worksheet
Тег: Table
Атрибут: ExpandedRowCount
Значение: 5
Не попадайтесь :)
Дальше проще, так как приказы можно раздавать на родном ABAP
2. Собираем необходимую информацию в структуры и таблицы произвольного формата.
3. Запускаем XSLT трансформацию, которая на выходе вернет бинарный файл в табличке.
CONSTANTS: lc_encoding TYPE string VALUE 'utf-8'.
DATA: lt_xml type SOLIX_TAB,
lref_ixml TYPE REF TO if_ixml,
lref_stream_factory TYPE REF TO if_ixml_stream_factory,
lref_resstream TYPE REF TO if_ixml_ostream,
lref_encoding TYPE REF TO if_ixml_encoding,
ressize TYPE i VALUE 0,
lv_xsltdesc TYPE o2xsltdesc-xsltdesc.
lref_ixml = cl_ixml=>create( ).
lref_stream_factory = lref_ixml->create_stream_factory( ). " создаем поток
lref_encoding = lref_ixml->create_encoding( character_set = lc_encoding byte_order = 0 ). " "создаем" кодировку (сущность)
REFRESH lt_xml.
lref_resstream = lref_stream_factory->create_ostream_itable( table = lt_xml ). " поток на выход для нашей таблицы
lref_resstream->set_encoding( encoding = lref_encoding ). " задаем кодировку
CALL TRANSFORMATION XSLT_REPORT1
SOURCE
table01 = lt_report[]
RESULT XML lref_resstream.
4. Отсылаем E-Mail с помощью самого удобного и современного класса CL_BCS
DATA: lr_bcs TYPE REF TO cl_bcs,
lr_document_bcs TYPE REF TO cl_document_bcs,
lr_sapuser_bcs TYPE REF TO cl_sapuser_bcs,
lr_recipient_bcs TYPE REF TO if_recipient_bcs,
lo_sender TYPE REF TO if_sender_bcs,
lv_subject TYPE so_obj_des,
lt_body TYPE bcsy_text,
ls_body TYPE soli.
* Creates persistent send request
lr_bcs = cl_bcs=>create_persistent( ).
lv_subject = 'Morning Sap News'.
"Some text
ls_body = 'Hello!'.
Append ls_body to lt_body.
ls_body = 'Your report has done!'.
Append ls_body to lt_body.
* Create document for mail body
lr_document_bcs = cl_document_bcs=>create_document(
i_type = 'RAW'
i_text = lt_body
i_subject = lv_subject ).
lr_document_bcs->add_attachment(
i_attachment_subject = 'Report'
i_attachment_type = 'XLS'
i_att_content_hex = lt_xml ).
lr_bcs->set_document( lr_document_bcs ).
* Sender addess
lo_sender = cl_cam_address_bcs=>create_internet_address( 'noreply@mail.com' ).
lr_bcs->set_sender( EXPORTING i_sender = lo_sender ).
* Recipient address
lr_recipient_bcs = cl_cam_address_bcs=>create_internet_address( 'SomeHRman@dot.com' ).
lr_bcs->add_recipient(
i_recipient = lr_recipient_bcs
i_express = abap_true
).
* E-Mail is placed into queue for sending. In case of very important alerts
* use the following parameter to initiate an 'immediate sending'; but notice that
* this will trigger a dedicated send process for every single message - which is
* very costly for system performance
lr_bcs->set_send_immediately( 'X' ).
* Send mail
CALL METHOD lr_bcs->send( ).
COMMIT WORK.
А если отчет жирный получился и его надо архивировать перед отправкой?
«В SAP есть все».
5. Архивируем с помощью класса cl_abap_zip
На вход подаем название файла и его содержимое с типом solix_tab
Так как solix_tab — таблица, а архиватор работает с типом XSTRING, перед архивацией надо сконвертировать таблицу в строку, после — строку в таблицу с помощью фм-ов группы функций SCMS_CONV.
FORM zip USING pv_name TYPE so_obj_des
CHANGING pt_xml TYPE solix_tab.
DATA: l_xstring_data TYPE xstring,
l_name TYPE string.
DATA: go_zip TYPE REF TO cl_abap_zip,
lv_size TYPE i,
lv_zip_file TYPE xstring.
DATA: ct_raw TYPE solix_tab.
DESCRIBE TABLE pt_xml LINES lv_size.
lv_size = lv_size * 255.
CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'
EXPORTING
input_length = lv_size
IMPORTING
buffer = l_xstring_data
TABLES
binary_tab = pt_xml
EXCEPTIONS
failed = 1
OTHERS = 2.
IF sy-subrc = 0.
EXIT.
ENDIF.
CREATE OBJECT go_zip.
CONCATENATE pv_name '.xls' INTO l_name.
go_zip->add( name = l_name
content = l_xstring_data ).
lv_zip_file = go_zip->save( ).
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING
buffer = lv_zip_file
IMPORTING
output_length = lv_size
TABLES
binary_tab = ct_raw.
pt_xml = ct_raw.
ENDFORM. "zip
6. Win-Win PROFIT :)
Автор статьи: Сычев Юрий, SAP HR консультант/разработчик. Источник здесь