Без предисловий, сразу код в начальной итерации:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
DATA: lv_template TYPE string VALUE 'ZR_CA001.DOCX'. DATA: lv_file TYPE xstring. DATA: lt_data TYPE STANDARD TABLE OF tbl1024. DATA: lv_len TYPE i. zcl_text_tools=>read_mimeobject( EXPORTING iv_mimeobject = conv #( lv_template ) IMPORTING ev_bin = lv_file ). * ... some magic happens here ... lv_len = xstrlen( lv_file ). CALL METHOD cl_bcs_convert=>xstring_to_xtab EXPORTING iv_xstring = lv_file IMPORTING et_xtab = lt_data[]. cl_gui_frontend_services=>show_document( EXPORTING document_name = lv_template mime_type = '' data_length = lv_len CHANGING document_data = lt_data[] EXCEPTIONS OTHERS = 1 ). |
А теперь можно его покритиковать.
Во-первых, имя файла.
Пользователю должно быть удобно и понятно.
Техническое имя — непонятно, значит от него надо избавиться. В некоторых подходах можно встретить запрос имени файла (и пути к нему заодно):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
lc_def_fname = 'ZR_CA001'. CALL METHOD cl_gui_frontend_services=>file_save_dialog EXPORTING file_filter = zcl_excel_common=>c_xlsx_file_filter default_file_name = lc_def_fname prompt_on_overwrite = 'X' CHANGING filename = lv_filename path = lv_path fullpath = lv_fullpath user_action = lv_user_action EXCEPTIONS cntl_error = 1 error_no_gui = 2 not_supported_by_gui = 3 invalid_default_file_name = 4 OTHERS = 5. CHECK lv_user_action NE cl_gui_frontend_services=>action_cancel. |
Это не всегда удобно. Спрашивать — это дополнительное движение. Оно критично, если пользователю надо проконтролировать место хранения файла. В моём типичном случае файл всегда выгружается во временную папку, пользователь контролирует его содержимое, отправляет на печать, закрывает и забывает. Поэтому место хранения контролировать не надо.
А имя файла можно задать понятное до деталей:
1 |
lv_filename = |Order AA { ls_order-ordnu } { ls_order-orddt DATE = USER } { ls_order-ename }|. |
Это совсем не сложно, не стоит этого бояться.
Во-вторых, полномочия на стороне пользователя.
Тыкать в дополнительные нудные предупреждения — неудобно.
В моём случае show_document встречает две проверки:
А) Проверка на выгрузку файла в папку:
Б) Проверка на открытие файла:
Первую проверку можно и «запомнить» и обосновать по корпоративной политике.
А вот вторую проверку «запомнить» нельзя. Варианта два — копать или обходить. Нормальные герои всегда идут в обход.
Если метод cl_gui_frontend_services=>show_document заставляет SAP GUI искать программу, ассоциированную с данным типом файлов, то метод cl_gui_frontend_services=>execute работает хитрее. Он просто предоставляет операционной системе самой разобраться что к чему.
Вот такой маленький proof-of-concept:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
DATA: lv_template TYPE string VALUE 'ZR_CA001.DOCX'. DATA: lv_file TYPE xstring. zcl_text_tools=>read_mimeobject( EXPORTING iv_mimeobject = CONV #( lv_template ) IMPORTING ev_bin = lv_file ). * ... some magic happens here ... DATA: lv_filename TYPE string. lv_filename = 'Order AA 123 15.06.2018 Ivanov Ivan'. zcl_file=>show( EXPORTING iv_file = lv_file iv_filename = lv_filename iv_ext = '.docx' ). |
Метод SHOW реализован отдельно:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
METHOD show. *IV_FILENAME = Order AA 123 15.06.2018 Ivanov Ivan *IV_EXT = .docx *[TODO] если WDA = использовать другой метод *[TODO] если ITS = использовать другой метод DATA: lv_filename TYPE string. lv_filename = iv_filename. CONDENSE lv_filename. DATA: lt_data TYPE STANDARD TABLE OF tbl1024. DATA: lv_len TYPE i. lv_len = xstrlen( iv_file ). CALL METHOD cl_bcs_convert=>xstring_to_xtab EXPORTING iv_xstring = iv_file IMPORTING et_xtab = lt_data[]. DATA: lv_temp_dir TYPE string. cl_gui_frontend_services=>get_temp_directory( CHANGING temp_dir = lv_temp_dir "D:\Users\<username>\AppData\Local\SAP\SAP GUI\tmp EXCEPTIONS cntl_error = 1 error_no_gui = 2 not_supported_by_gui = 3 OTHERS = 4 ). IF sy-subrc <> 0. * [TODO] обработка ошибок * MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno * WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. CALL METHOD cl_gui_cfw=>flush EXCEPTIONS OTHERS = 0. DATA: lv_fullname TYPE string. DATA: lv_try TYPE i value 1. "D:\Users\<username>\AppData\Local\SAP\SAP GUI\tmp\Order AA 123 15.06.2018 Ivanov Ivan.docx lv_fullname = |{ lv_temp_dir }\\{ lv_filename }{ iv_ext }|. DO. cl_gui_frontend_services=>gui_download( EXPORTING bin_filesize = lv_len filename = lv_fullname filetype = 'BIN' no_auth_check = 'X' CHANGING data_tab = lt_data[] EXCEPTIONS file_write_error = 1 no_batch = 2 gui_refuse_filetransfer = 3 invalid_type = 4 no_authority = 5 unknown_error = 6 header_not_allowed = 7 separator_not_allowed = 8 filesize_not_allowed = 9 header_too_long = 10 dp_error_create = 11 dp_error_send = 12 dp_error_write = 13 unknown_dp_error = 14 access_denied = 15 dp_out_of_memory = 16 disk_full = 17 dp_timeout = 18 file_not_found = 19 dataprovider_exception = 20 control_flush_error = 21 not_supported_by_gui = 22 error_no_gui = 23 OTHERS = 24 ). IF sy-subrc = 0. cl_gui_frontend_services=>execute( EXPORTING document = lv_fullname ). EXIT. ELSEIF sy-subrc = 15. lv_try = lv_try + 1. "access_denied = файл уже открыт в приложении, дописываем счетчик пока не достигнем успеха "D:\Users\<username>\AppData\Local\SAP\SAP GUI\tmp\Order AA 123 15.06.2018 Ivanov Ivan (2).docx lv_fullname = |{ lv_temp_dir }\\{ lv_filename } ({ lv_try }){ iv_ext }|. IF lv_try > 100. "[TODO] Panic! EXIT. ENDIF. ELSE. EXIT. "[TODO] Other error! ENDIF. ENDDO. ENDMETHOD. |
Профит.
PS. И это не конец истории. Не забыть бы про мусор во временной папке, а то мало ли что.
Есть варианты:
- C:\Users\<username>\AppData\Local\Temp — системная временная папка; не common way
- C:\Users\<username>\AppData\Local\SAP\SAP GUI\tmp\ — временная папка самого SAP GUI; my way
- C:\Users\<username>\Documents\SAP\SAP GUI — папка по-умолчанию для работы с документами; не в этот раз
- [включите воображение]
Метод SHOW_DOCUMENT выгружает файл во вторую папку и там есть параметр KEEP_FILE. Очевидно тогда, что если флаг специально не выставить, то файл будет подчищен автоматически; вопрос только в какой момент.
В нашем новом методе EXECUTE данный параметр отсутствует. Что это значит? Интересно, чистит ли папку кто-нибудь и когда-нибудь?
Документация говорит:
Documents in the temporary directory will be deleted, when SAP GUI is closed. You can configure the deletion of files also in other directories. For information on this, refer to the security guide.
Это успокаивает, значит хорошо что мы выгружаем именно в эту папку.
А к третьей папке есть настройка: