Eine viel nachgefragte Funktion im FI ist die Möglichkeit, Belege in Excel aufzubereiten und unter SAP hochzuladen, z.B. für Sachkonten-Umbuchungen im Rahmen von Abschlusstätigkeiten. Unter S/4 (ab Rel. 1511) gibt es hierfür eine Fiori-App zum Upload von Hauptbuchbelegen via Excel-Template, ab Release 1809 gibt es diese auch für kreditorische Belege...
Bis dahin hilft meines Wissens tatsächlich nur eine selbstgebaute Upload-Funktion oder ggf. ein 3rd Party-Produkt.
Ein einfaches Programm inkl. Testlauf-/Prüffunktion findet sich in diesem Artikel. Hinweise zur Installation und zum Format der Quell-Datei finden sich am Ende des Codings...
*&---------------------------------------------------------------------*
*& Report ZFI_UPLOAD_DOCUMENT
*----------------------------------------------------------------------*
* Funktion : Upload Belege aus Excel *
*----------------------------------------------------------------------*
* Beschreibung : Upload von Belegen und Verbuchung via Excel *
* (Ausweichtool für Fiori-App) *
*----------------------------------------------------------------------*
REPORT zfi_upload_document.
***********************************************************************
******************** GLOBAL DATA **************************************
***********************************************************************
CONSTANTS: gc_delimiter(1) TYPE c VALUE '~'.
SET EXTENDED CHECK OFF.
INCLUDE:
sbal_constants,
<icon>.
SET EXTENDED CHECK ON.
DATA:
g_s_log TYPE bal_s_log,
g_log_handle TYPE balloghndl,
g_t_log_handle TYPE bal_t_logh,
g_s_display_profile TYPE bal_s_prof.
DATA: g_dummy TYPE c.
DATA: data_tab TYPE TABLE OF string.
TYPES: BEGIN OF tax_item,
mwskz TYPE mwskz,
direct_tax TYPE abap_bool,
basis TYPE fwbas,
steuer TYPE fwste,
END OF tax_item.
DATA: git_taxitems TYPE TABLE OF tax_item,
gs_taxitem TYPE tax_item.
TYPES: BEGIN OF doc_header,
bukrs TYPE bukrs,
blart TYPE blart,
bldat(10) TYPE c,
budat(10) TYPE c,
bumon TYPE bumon,
bktxt TYPE bktxt,
waers TYPE waers,
ldgrp TYPE fagl_ldgrp,
ukurs(12) TYPE c,
umdat(10) TYPE c,
xblnr TYPE xblnr,
pargb TYPE pargb,
END OF doc_header.
TYPES: BEGIN OF doc_item,
bukrs TYPE bukrs,
hkont TYPE hkont,
sgtxt TYPE sgtxt,
wrsol(15) TYPE c,
wrhab(15) TYPE c,
dmbtr(15) TYPE c,
dmbe2(15) TYPE c,
mwskz TYPE mwskz,
txjcd TYPE txjcd,
kostl TYPE kostl,
prctr TYPE prctr,
aufnr TYPE aufnr,
ps_posid TYPE ps_posid,
valut(10) TYPE c,
hbkid TYPE hbkid,
hktid TYPE hktid,
zuonr TYPE dzuonr,
vbund TYPE vbund,
END OF doc_item.
DATA: gs_doc TYPE doc_header,
gs_item TYPE doc_item,
git_items TYPE TABLE OF doc_item.
* Schnittstellendaten für Verbuchungs-BAPI
DATA:
* Returnparameter des BAPIs
g_obj_type TYPE bapiache09-obj_type, "Objekttyp
* Objejktschlüssel erhält vom BAPI die Belegidentifikation:
* NNNNNNNNNNYYYYBBBB N = Belegnummer, Y = GJahr, B = Buchungskreis
g_obj_key TYPE bapiache09-obj_key, "Objektschlüssel
g_obj_sys TYPE bapiache09-obj_sys, "log. System
* Belegkopf
gs_documentheader TYPE bapiache09,
* Sachkontenpositionen
git_accountgl TYPE TABLE OF bapiacgl09,
gs_accountgl TYPE bapiacgl09,
* Steuerzeilen
git_accounttax TYPE TABLE OF bapiactx09,
gs_accounttax TYPE bapiactx09,
* Betragsinformationen
git_currencyamount TYPE TABLE OF bapiaccr09,
gs_currencyamount TYPE bapiaccr09,
* Meldungen des BAPI's
git_return TYPE TABLE OF bapiret2,
gs_return TYPE bapiret2.
DATA:
g_itemno TYPE posnr_acc. "Postionsnummer
*&---------------------------------------------------------------------*
*& SELECTION-SCREEN
*&---------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME TITLE TEXT-b01.
PARAMETERS: pa_fnam LIKE rlgrap-filename OBLIGATORY.
SELECTION-SCREEN END OF BLOCK b01.
SELECTION-SCREEN BEGIN OF BLOCK b02 WITH FRAME TITLE TEXT-b02.
PARAMETERS: pa_test AS CHECKBOX DEFAULT 'X'.
SELECTION-SCREEN END OF BLOCK b02.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR pa_fnam.
PERFORM f4_filename.
*-----------------------------------------------------------------------
START-OF-SELECTION.
*-----------------------------------------------------------------------
PERFORM init.
PERFORM upload_data.
PERFORM map_data.
IF pa_test IS INITIAL.
PERFORM post_document.
ELSE.
PERFORM check_document.
ENDIF.
PERFORM add_msg_to_prot.
PERFORM log_display.
*&---------------------------------------------------------------------*
*& Form F4_FILENAME
*&---------------------------------------------------------------------*
*& F4 Hilfe Excel-Datei
*&---------------------------------------------------------------------*
FORM f4_filename .
CALL FUNCTION 'FAA_FILE_F4'
EXPORTING
i_default_extension = 'XLS'
IMPORTING
e_filename = pa_fnam
EXCEPTIONS
interface_error = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
PERFORM msg_add USING probclass_high.
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form UPLOAD_DATA
*&---------------------------------------------------------------------*
*& Upload der Excel-Tabelle mit den Belegdaten
*&---------------------------------------------------------------------*
FORM upload_data .
DATA: l_buf TYPE string,
l_tabix TYPE sy-tabix,
l_msg(200) TYPE c.
CLEAR data_tab[].
CALL FUNCTION 'FAA_FILE_UPLOAD_EXCEL'
EXPORTING
i_filename = pa_fnam
i_delimiter = gc_delimiter
TABLES
et_filecontent = data_tab
EXCEPTIONS
error_accessing_file = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE i600(fr) WITH 'Fehler' sy-subrc 'beim Upload'.
ELSE.
CONCATENATE TEXT-001 pa_fnam INTO l_msg SEPARATED BY space.
PERFORM msg_add_free_text USING l_msg.
ENDIF.
LOOP AT data_tab INTO l_buf.
IF sy-tabix = 5.
SPLIT l_buf AT gc_delimiter INTO
gs_doc-bukrs
gs_doc-blart
gs_doc-bldat
gs_doc-budat
gs_doc-bumon
gs_doc-bktxt
gs_doc-waers
gs_doc-ldgrp
gs_doc-ukurs
gs_doc-umdat
gs_doc-xblnr
gs_doc-pargb.
ENDIF.
IF sy-tabix GE 9.
SPLIT l_buf AT gc_delimiter INTO
gs_item-bukrs
gs_item-hkont
gs_item-sgtxt
gs_item-wrsol
gs_item-wrhab
gs_item-dmbtr
gs_item-dmbe2
gs_item-mwskz
gs_item-txjcd
gs_item-kostl
gs_item-prctr
gs_item-aufnr
gs_item-ps_posid
gs_item-valut
gs_item-hbkid
gs_item-hktid
gs_item-zuonr
gs_item-vbund.
APPEND gs_item TO git_items.
ENDIF.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form INIT_PROTOCOL
*&---------------------------------------------------------------------*
*& Anwendungsprotokoll aufbauen
*&---------------------------------------------------------------------*
FORM init_protocol .
* create a log
g_s_log-extnumber = 'Beleg-Upload'(ext).
CALL FUNCTION 'BAL_LOG_CREATE'
EXPORTING
i_s_log = g_s_log
IMPORTING
e_log_handle = g_log_handle
EXCEPTIONS
OTHERS = 1.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM.
*--------------------------------------------------------------------
* FORM ADD_MSG_TO_PROT
*--------------------------------------------------------------------
FORM add_msg_to_prot.
DATA:
l_s_msg TYPE bal_s_msg,
l_context TYPE bal_s_ex01.
DATA:
l_s_return LIKE LINE OF git_return.
LOOP AT git_return INTO l_s_return.
* define data of message for Application Log
l_s_msg-msgty = l_s_return-type.
l_s_msg-msgid = l_s_return-id.
l_s_msg-msgno = l_s_return-number.
l_s_msg-msgv1 = l_s_return-message_v1.
l_s_msg-msgv2 = l_s_return-message_v2.
l_s_msg-msgv3 = l_s_return-message_v3.
l_s_msg-msgv4 = l_s_return-message_v4.
* add this message to log file
CALL FUNCTION 'BAL_LOG_MSG_ADD'
EXPORTING
* I_LOG_HANDLE =
i_s_msg = l_s_msg
EXCEPTIONS
log_not_found = 0
OTHERS = 1.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDLOOP.
ENDFORM.
FORM log_display.
DATA:
l_s_display_profile TYPE bal_s_prof,
l_s_fcat TYPE bal_s_fcat.
* get standard display profile
CALL FUNCTION 'BAL_DSP_PROFILE_SINGLE_LOG_GET'
IMPORTING
e_s_display_profile = l_s_display_profile
EXCEPTIONS
OTHERS = 1.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
* for display variants add report id
l_s_display_profile-disvariant-report = sy-repid.
* when you use also other ALV lists in your report,
* please specify a handle to distinguish between the display
* variants of these different lists, e.g:
l_s_display_profile-disvariant-handle = 'LOG'.
* show log file with modified output profile
* - we specify the display profile since we created our own
* - we do not specify any filter (like I_S_LOG_FILTER, ...,
* I_T_MSG_HANDLE) since we want to display all messages available
CALL FUNCTION 'BAL_DSP_LOG_DISPLAY'
EXPORTING
* I_S_LOG_FILTER =
* I_T_LOG_CONTEXT_FILTER =
* I_S_MSG_FILTER =
* I_T_MSG_CONTEXT_FILTER =
* I_T_LOG_HANDLE =
* I_T_MSG_HANDLE =
i_s_display_profile = l_s_display_profile
EXCEPTIONS
OTHERS = 1.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM.
*--------------------------------------------------------------------
* FORM MSG_ADD_FREE_TEXT
*--------------------------------------------------------------------
FORM msg_add_free_text USING VALUE(i_text) TYPE c.
* add this message to log file
CALL FUNCTION 'BAL_LOG_MSG_ADD_FREE_TEXT'
EXPORTING
* I_LOG_HANDLE =
i_msgty = 'S'
i_text = i_text
EXCEPTIONS
log_not_found = 0
OTHERS = 1.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form INIT
*&---------------------------------------------------------------------*
*& Initialisierung
*&---------------------------------------------------------------------*
FORM init .
CLEAR: git_accountgl[],
git_accounttax[],
git_currencyamount[],
git_return[].
CLEAR g_itemno.
PERFORM init_protocol.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form POST_DOCUMENT
*&---------------------------------------------------------------------*
*& Beleg buchen
*&---------------------------------------------------------------------*
FORM post_document .
DATA: l_error TYPE abap_bool VALUE abap_false.
*-----------------------------------------------------------------------
* BAPI-Aufruf
*-----------------------------------------------------------------------
CALL FUNCTION 'BAPI_ACC_DOCUMENT_POST'
EXPORTING
documentheader = gs_documentheader
IMPORTING
obj_type = g_obj_type
obj_key = g_obj_key
obj_sys = g_obj_sys
TABLES
accountgl = git_accountgl
accounttax = git_accounttax
currencyamount = git_currencyamount
return = git_return.
LOOP AT git_return TRANSPORTING NO FIELDS
WHERE type = 'A' OR type = 'E'.
l_error = abap_true.
ENDLOOP.
IF l_error = abap_false.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'.
ELSE.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form CHECK_DOCUMENT
*&---------------------------------------------------------------------*
*& Beleg prüfen
*&---------------------------------------------------------------------*
FORM check_document .
CALL FUNCTION 'BAPI_ACC_DOCUMENT_CHECK'
EXPORTING
documentheader = gs_documentheader
TABLES
accountgl = git_accountgl
accounttax = git_accounttax
currencyamount = git_currencyamount
return = git_return.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form MAP_DATA
*&---------------------------------------------------------------------*
*& Mapping der Excel-Daten auf BAPI-Strukturen
*&---------------------------------------------------------------------*
FORM map_data .
DATA: l_netto TYPE wrbtr,
l_brutto TYPE wrbtr,
l_steuer TYPE fwste,
l_basis TYPE fwbas.
DATA: l_mwskz TYPE skb1-mwskz.
*-----------------------------------------------------------------------
* Belegkopf
*-----------------------------------------------------------------------
CLEAR gs_documentheader.
gs_documentheader-bus_act = 'RFBU'.
gs_documentheader-username = sy-uname.
gs_documentheader-comp_code = gs_doc-bukrs.
PERFORM _convert USING gs_doc-bldat gs_documentheader-doc_date 'BLDAT'.
PERFORM _convert USING gs_doc-budat gs_documentheader-pstng_date 'BUDAT'.
IF gs_doc-bumon IS NOT INITIAL AND gs_doc-bumon NE space.
gs_documentheader-fis_period = gs_doc-bumon.
ENDIF.
gs_documentheader-ref_doc_no = gs_doc-xblnr.
gs_documentheader-header_txt = gs_doc-bktxt.
gs_documentheader-doc_type = gs_doc-blart.
*-----------------------------------------------------------------------
* Belegpositionen
*-----------------------------------------------------------------------
LOOP AT git_items INTO gs_item.
ADD 1 TO g_itemno.
CLEAR: gs_accountgl, gs_currencyamount.
gs_accountgl-itemno_acc = g_itemno.
PERFORM _convert USING gs_item-hkont gs_accountgl-gl_account 'HKONT'.
gs_accountgl-item_text = gs_item-sgtxt.
IF gs_item-kostl IS NOT INITIAL.
PERFORM _convert USING gs_item-kostl gs_accountgl-costcenter 'KOSTL'.
ENDIF.
IF gs_item-prctr IS NOT INITIAL.
PERFORM _convert USING gs_item-prctr gs_accountgl-profit_ctr 'PRCTR'.
ENDIF.
IF gs_item-aufnr IS NOT INITIAL.
PERFORM _convert USING gs_item-aufnr gs_accountgl-orderid 'AUFNR'.
ENDIF.
IF gs_item-ps_posid IS NOT INITIAL.
PERFORM _convert USING gs_item-ps_posid gs_accountgl-wbs_element 'PS_POSID'.
ENDIF.
gs_accountgl-alloc_nmbr = gs_item-zuonr.
gs_accountgl-trade_id = gs_item-vbund.
gs_accountgl-tax_code = gs_item-mwskz.
IF gs_item-valut IS NOT INITIAL.
PERFORM _convert USING gs_item-valut gs_accountgl-value_date 'VALUT'.
ENDIF.
IF gs_item-wrsol IS NOT INITIAL.
PERFORM _convert USING gs_item-wrsol l_brutto 'WRBTR'.
ENDIF.
IF gs_item-wrhab IS NOT INITIAL.
PERFORM _convert USING gs_item-wrhab l_brutto 'WRBTR'.
MULTIPLY l_brutto BY -1.
ENDIF.
* Sachkonto mit Steuer zu bebuchen
CLEAR l_mwskz.
SELECT SINGLE mwskz FROM skb1 INTO l_mwskz
WHERE saknr = gs_accountgl-gl_account
AND bukrs = gs_documentheader-comp_code.
IF sy-subrc = 0 AND l_mwskz IS INITIAL.
"keine Steuer erlaubt --> St. KZ. löschen (Verhalten analog FIORI-App)
CLEAR: gs_item-mwskz, gs_accountgl-tax_code.
ENDIF.
CLEAR: l_steuer, l_netto, l_basis.
* Mit Steuer?
IF gs_item-mwskz IS NOT INITIAL.
IF l_mwskz = '>' OR l_mwskz = '<'. "Direct Tax
CALL FUNCTION 'RE_CALCULATE_BASE_AMOUNT'
EXPORTING
i_taxam = l_brutto
i_mwskz = gs_item-mwskz
i_waers = gs_doc-waers
i_bukrs = gs_documentheader-comp_code
IMPORTING
e_fwbas = l_basis.
l_steuer = l_netto = l_brutto.
ELSE.
CALL FUNCTION 'CALCULATE_TAX_FROM_GROSSAMOUNT'
EXPORTING
i_bukrs = gs_documentheader-comp_code
i_mwskz = gs_item-mwskz
i_waers = gs_doc-waers
i_wrbtr = l_brutto
IMPORTING
e_fwste = l_steuer
EXCEPTIONS
OTHERS = 16.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO g_dummy.
PERFORM msg_add USING probclass_high.
ENDIF.
l_netto = l_brutto - l_steuer.
l_basis = l_netto.
ENDIF.
*-----------------------------------------------------------------------
* korrespondierende Steuerzeile sammeln
*-----------------------------------------------------------------------
CLEAR gs_taxitem.
gs_taxitem-mwskz = gs_item-mwskz.
gs_taxitem-steuer = l_steuer.
gs_taxitem-basis = l_basis.
IF l_mwskz = '>' OR l_mwskz = '<'. "Direct Tax
gs_taxitem-direct_tax = abap_true.
ELSE.
gs_taxitem-direct_tax = abap_false.
ENDIF.
COLLECT gs_taxitem INTO git_taxitems.
ELSE.
l_netto = l_brutto.
ENDIF.
IF NOT ( l_mwskz = '>' OR l_mwskz = '<' ). "Direct Tax
gs_currencyamount-itemno_acc = gs_accountgl-itemno_acc.
gs_currencyamount-currency = gs_doc-waers.
gs_currencyamount-amt_doccur = l_netto.
APPEND: gs_accountgl TO git_accountgl,
gs_currencyamount TO git_currencyamount.
ENDIF.
ENDLOOP.
*-----------------------------------------------------------------------
* gesammelte Steuerzeilen aufbereiten und anhängen
*-----------------------------------------------------------------------
LOOP AT git_taxitems INTO gs_taxitem.
ADD 1 TO g_itemno.
CLEAR: gs_accounttax, gs_currencyamount.
gs_accounttax-itemno_acc = g_itemno.
gs_accounttax-tax_code = gs_taxitem-mwskz.
gs_accounttax-direct_tax = gs_taxitem-direct_tax.
gs_currencyamount-itemno_acc = gs_accounttax-itemno_acc.
gs_currencyamount-currency = gs_doc-waers.
gs_currencyamount-amt_doccur = gs_taxitem-steuer.
gs_currencyamount-amt_base = gs_taxitem-basis.
APPEND: gs_accounttax TO git_accounttax,
gs_currencyamount TO git_currencyamount.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form _CONVERT
*&---------------------------------------------------------------------*
*& Daten ins SAP-Format konvertieren
*&---------------------------------------------------------------------*
*& --> in/out Ein/Ausgabe
*& --> Dtel Datenelement
*&---------------------------------------------------------------------*
FORM _convert USING in out VALUE(dtel).
CALL FUNCTION 'RS_CONV_EX_2_IN_DTEL'
EXPORTING
input_external = in
dtel = dtel
IMPORTING
output_internal = out.
IF sy-subrc <> 0.
MESSAGE a600(fr) WITH 'Fehler' sy-subrc 'bei der Konvertierung' dtel.
ENDIF.
ENDFORM.
*--------------------------------------------------------------------
* FORM MSG_ADD
*--------------------------------------------------------------------
FORM msg_add USING VALUE(i_probclass) TYPE bal_s_msg-probclass.
DATA:
l_s_msg TYPE bal_s_msg.
* define data of message for Application Log
l_s_msg-msgty = sy-msgty.
l_s_msg-msgid = sy-msgid.
l_s_msg-msgno = sy-msgno.
l_s_msg-msgv1 = sy-msgv1.
l_s_msg-msgv2 = sy-msgv2.
l_s_msg-msgv3 = sy-msgv3.
l_s_msg-msgv4 = sy-msgv4.
l_s_msg-probclass = i_probclass.
* add this message to log file
CALL FUNCTION 'BAL_LOG_MSG_ADD'
EXPORTING
* I_LOG_HANDLE =
i_s_msg = l_s_msg
EXCEPTIONS
log_not_found = 0
OTHERS = 1.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM.