Ранее я описывал способы формирования файлов в Fiori. Однако программирование в SAP не стоит на месте и развивается. В последних релизах SAP добавил новые технологии и сейчас я опишу способ, который позволяет скачивать генерируемые файлы с помощью модели RAP.
ABAP RAP (RESTful Application Programming Model) это модель разработки приложений на языке ABAP для облачных решений, однако она доступна и в локальных системах актуальных версий (на 7.54 еще не работает).
За основу я взял пост Streams in RAP : Uploading PDF , Excel and Other Files in RAP Application, однако там файлы сохранялись в таблице. Я же сделаю возможность формирования документов (например авансового отчета) для командировок из Fiori-приложения на лету.
Прежде всего сделаем CDS, которая будет отображать все записи из таблицы ZTRV_C_TRV
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 |
@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Travel request' @Metadata.allowExtensions: true define root view entity ZTRV_C_TRV as select from ptrv_head association [0..1] to ztrv_c_pernr as _pernr on $projection.Pernr = _pernr.Pernr association [0..1] to ztrv_t_attach as _attach on $projection.Pernr = _attach.pernr { key pernr as Pernr, key reinr as Reinr, datv1 as Datv1, datb1 as Datb1, _pernr.Ename as Ename, _pernr.Bukrs as Bukrs, _pernr.Vdsk1 as Vdsk1, _pernr.orgtx, _pernr.stltx, @Semantics.largeObject: { mimeType: 'MimeType', fileName: 'Filename', contentDispositionPreference: #INLINE } @ObjectModel.virtualElement: true @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_TRV_REQUEST_VF' _attach.attachment as Attachment, @Semantics.mimeType: true @ObjectModel.virtualElement: true @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_TRV_REQUEST_VF' cast('' as abap.char( 30 ) ) as MimeType, @ObjectModel.virtualElement: true @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_TRV_REQUEST_VF' cast('' as abap.char( 60 ) ) as Filename } |
Здесь ztrv_c_pernr это CDS с данными сотрудников, а ztrv_t_attach это пустая таблица с полем pernr и attachment типа RAWSTRING. Благодаря этой таблице у нас появилось поле Attachment нужного нам типа. Без этого не получилось создать виртуальное поле типа RAWSTRING.
Далее все как в оригинальной статье — создаем Metadata Extension, Provider, Behavior Definition, Service Definition и Service Bindings.
Metadata Extension:
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 |
@Metadata.layer: #CORE annotate view ZTRV_C_TRV with { @UI.facet: [{ purpose: #STANDARD, type: #FIELDGROUP_REFERENCE, importance: #HIGH, position: 10, label: 'Основные данные', targetQualifier: 'MainData' }, { purpose: #STANDARD, type: #FIELDGROUP_REFERENCE, importance: #HIGH, position: 20, label: 'Командируемый', targetQualifier: 'Employee' } ] @UI.selectionField: [{ position: 10 }] @UI.textArrangement: #TEXT_LAST @UI.fieldGroup: [ { qualifier: 'Employee', position: 10, importance: #HIGH } ] @UI.lineItem: [ { position: 10, importance: #MEDIUM } ] @Search.defaultSearchElement: true Pernr; @Search.defaultSearchElement: true @UI.selectionField: [{ position: 20 }] @UI.textArrangement: #TEXT_LAST @UI.fieldGroup: [ { qualifier: 'MainData', position: 20, importance: #HIGH } ] @UI.lineItem: [ { position: 20, importance: #MEDIUM } // ,{ type: #FOR_ACTION, position: 1, dataAction: 'sendmail', label: 'Send mail' } ] @UI.identification: [{ type: #FOR_ACTION, position: 1, dataAction: 'sendmail', label: 'Отправить документы' }] Reinr; @Search.defaultSearchElement: true @UI.selectionField: [{ position: 30 }] @UI.textArrangement: #TEXT_LAST @UI.fieldGroup: [ { qualifier: 'MainData', position: 30, importance: #HIGH } ] @UI.lineItem: [ { position: 30, importance: #MEDIUM } ] Datv1; @Search.defaultSearchElement: true @UI.selectionField: [{ position: 40 }] @UI.textArrangement: #TEXT_LAST @UI.fieldGroup: [ { qualifier: 'MainData', position: 40, importance: #HIGH } ] @UI.lineItem: [ { position: 40, importance: #MEDIUM } ] Datb1; @UI: { fieldGroup: [ { position: 100, qualifier: 'MainData', label: 'Attachment' } ], identification: [ { position: 100, label: 'Документы' } ] } Attachment; @UI.hidden: true MimeType; @UI.hidden: true Filename; @Search.defaultSearchElement: true @UI.selectionField: [{ position: 200 }] @UI.textArrangement: #TEXT_LAST @UI.fieldGroup: [ { qualifier: 'Employee', position: 200, importance: #HIGH } ] @UI.lineItem: [ { position: 200, importance: #MEDIUM }] Ename; @Search.defaultSearchElement: true @UI.selectionField: [{ position: 210 }] @UI.textArrangement: #TEXT_LAST @UI.fieldGroup: [ { qualifier: 'Employee', position: 210, importance: #HIGH } ] orgtx; @Search.defaultSearchElement: true @UI.selectionField: [{ position: 220 }] @UI.textArrangement: #TEXT_LAST @UI.fieldGroup: [ { qualifier: 'Employee', position: 220, importance: #HIGH } ] stltx; @Search.defaultSearchElement: true @UI.selectionField: [{ position: 250 }] @UI.textArrangement: #TEXT_LAST @UI.fieldGroup: [ { qualifier: 'Employee', position: 250, importance: #HIGH } ] @UI.lineItem: [ { position: 250, importance: #MEDIUM }] Bukrs; @Search.defaultSearchElement: true @UI.selectionField: [{ position: 250 }] @UI.textArrangement: #TEXT_LAST @UI.fieldGroup: [ { qualifier: 'Employee', position: 250, importance: #HIGH } ] @UI.lineItem: [ { position: 250, importance: #MEDIUM }] Vdsk1; } |
Provider
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Provider' define root view entity ZTRV_P_TRV provider contract transactional_query as projection on ZTRV_C_TRV { key Pernr, key Reinr, Datv1, Datb1, Ename, Bukrs, Vdsk1, orgtx, stltx, Attachment, MimeType, Filename } |
Behavior Definitions
1 2 3 4 5 6 7 8 9 10 11 12 13 |
managed implementation in class zbp_trv_c_trv unique; //strict ( 2 ); define behavior for ZTRV_C_TRV alias Trv persistent table ptrv_head lock master //authorization master ( instance ) //etag master <field_name> { field ( readonly ) Attachment, MimeType, filename; action sendmail result [1] $self; } |
Service Definitions
1 2 3 4 |
@EndUserText.label: 'Travel request' define service ZTRV_SD_TRV { expose ZTRV_C_TRV; } |
Service Bindings типа OData V4 — UI
И класс Behavior
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 |
CLASS lhc_trv DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS modify FOR BEHAVIOR IMPORTING it_sendmail FOR ACTION trv~sendmail RESULT et_sendmail. ENDCLASS. CLASS lhc_trv IMPLEMENTATION. METHOD modify. GET TIME STAMP FIELD DATA(lv_timestamp). LOG-POINT ID ztrv SUBKEY |Sendfile { lv_timestamp }| FIELDS it_sendmail. LOOP AT it_sendmail ASSIGNING FIELD-SYMBOL(<ls_sendmail>). TRY. zcl_trv_request=>get_instance( iv_pernr = <ls_sendmail>-pernr iv_tripno = <ls_sendmail>-reinr )->send_mail( ). CATCH zcx_trv_request INTO DATA(lx_request). DATA(lo_log) = cf_reca_message_list=>create( id_object = zif_trv_c=>gc_s_log-object id_subobject = zif_trv_c=>gc_s_log-request id_extnumber = |{ <ls_sendmail>-pernr }_{ <ls_sendmail>-reinr }| ). lo_log->add_from_exception( lx_request ). lo_log->store( ). ENDTRY. ENDLOOP. " Return result to UI READ ENTITIES OF ztrv_c_trv IN LOCAL MODE ENTITY Trv ALL FIELDS WITH CORRESPONDING #( it_sendmail ) RESULT DATA(lt_trv). et_sendmail = VALUE #( FOR <ls_trv> IN lt_trv ( %tky = <ls_trv>-%tky %param = <ls_trv> ) ). ENDMETHOD. ENDCLASS. |
Осталось в класс zcl_trv_request добавить нужный функционал формирования файлов и отправки аналогичного файла на почту.