СБИС Сапер использует имеющиеся программы печати для формирование xml-документов. Это позволяет избежать дублирования алгоритма формирования документа.
Алгоритм формирования электронного документа
- Для каждого отправляемого документа СБИС Сапер вызывает программу печати, которая указана в настройках модуля.
- Программа печати рассчитывает данные, которые нужны для печати.
- Перед вызовом формуляра, управление передается модулю СБИС Сапер. Модуль проверяет, кем была вызвана программу печати. Если инициатор вызова:
- не Сапер — модуль возвращает управление программе печати.
- Сапер — выбирает подготовленные программой печати данные. Выбор нужных для печати данных определяется по настройкам выгрузки. Затем формируется xml-документ. По окончании процесса , модуль возвращает флаг, который говорит о необходимости прервать программу печати.
Этот алгоритм работает на любыми версиями SAP, типами документов и отчетов (не зависит от функционала, реализованного SAP для журнала электронных счетов фактур из российского Add-on).
Доработка программ печати
Перед тем как вносить изменения в программу печати, обязательно сделайте ее копию. Рекомендуемый шаблон названия копии программы «[ZSBIS_][Старое название программы]». Вместо копий программ печати можно использовать стандартные BADI в программах печати. Например, «J_3R_TORG12_BADI» для программы печати накладной «J_3RV_DELIV_PDF» или «J_3R_INV_BADI» для программы печати фактуры «J_3RV_INV_A».
В программу печати или ее копию добавьте вызов метода СБИС Сапера. Метод должен завершать действия программы печати после формирования электронного документа.
Пример кода, который нужно добавить перед вызовом формуляра в каждую программу печати:
TRY.
DATA CX_ROOT TYPE REF TO CX_ROOT.
DATA lv_not_print TYPE c VALUE ''.
DATA cl_mapping TYPE REF TO /sbis/cl_mapping.
CREATE OBJECT cl_mapping.
CALL METHOD cl_mapping->calc_doc
EXPORTING
is_nast = nast
IMPORTING
ev_not_print = lv_not_print.
IF lv_not_print = 'X'.
EXIT.
ENDIF.
DATA cx_core TYPE REF TO /sbis/cx_core.
CATCH /sbis/cx_core INTO cx_core.
DATA lv_cur_prog TYPE char255.
DATA lv_cur_form TYPE char255.
CALL METHOD /sbis/cl_core=>get_current_progname
IMPORTING
ev_prog_name = lv_cur_prog
ev_form_name = lv_cur_form.
FIELD-SYMBOLS: <fs_exc> TYPE /sbis/s_cx_core.
ASSIGN ('(/SBIS/SAPLGF_PRINT_PROG)GS_EXC') TO <fs_exc>.
IF <fs_exc> IS ASSIGNED.
<fs_exc>-error_msg_ext = cx_core->lv_error_msg_ext.
<fs_exc>-error_msg_detail = cx_core->lv_error_msg_detail
&& ` <= ` && lv_cur_prog && `->` && lv_cur_form.
ENDIF.
RAISE EXCEPTION TYPE /sbis/cx_core
EXPORTING
textid = cx_core->textid
lv_error_msg_ext = cx_core->lv_error_msg_ext
lv_error_msg_detail = cx_core->lv_error_msg_detail
&& ` <= ` && lv_cur_prog && `->` && lv_cur_form.
ENDTRY.
Если в формулярах печатных форм есть логика расчета данных документа — перенесите ее в программу печати.
Если у вас Z-программы печати используют подпрограммы, то для вызова СБИС Сапера:
- Сначала запускается подпрограмма «ENTRY». Это оболочка для подпрограммы «PROCESSING». Она передает код возврата, в ней изменения не понадобятся.
FORM entry USING return_code us_screen. "#EC CALLED CLEAR retcode. xscreen = us_screen. PERFORM processing USING us_screen. IF retcode NE 0. return_code = 1. ELSE. return_code = 0. ENDIF. CLEAR status. ENDFORM.
- Вызов печати обычно находится в теле подпрограммы «PROCESSING».
FORM processing USING proc_screen. PERFORM checks. PERFORM init_data. PERFORM get_data. PERFORM print. ENDFORM.
- Поэтому до вызова печати («PRINT») нужно вставить СБИС-код формирования электронных документов.
DATA gv_not_print TYPE c . " TENSOR SBIS EDO FORM processing USING proc_screen. PERFORM checks. PERFORM init_data. PERFORM get_data. PERFORM sbis_edi. " TENSOR SBIS EDO CHECK gv_not_print IS INITIAL. " TENSOR SBIS EDO PERFORM print. ENDFORM. FORM sbis_edi . * TENSOR SBIS EDO TRY. DATA CX_ROOT TYPE REF TO CX_ROOT. DATA cl_mapping TYPE REF TO /sbis/cl_mapping. CREATE OBJECT cl_mapping. CALL METHOD cl_mapping->calc_doc EXPORTING is_nast = nast IMPORTING ev_not_print = gv_not_print. DATA cx_core TYPE REF TO /sbis/cx_core. CATCH /sbis/cx_core INTO cx_core. DATA lv_cur_prog TYPE char255. DATA lv_cur_form TYPE char255. CALL METHOD /sbis/cl_core=>get_current_progname IMPORTING ev_prog_name = lv_cur_prog ev_form_name = lv_cur_form. " exception проходит через прогр печати без текста! FIELD-SYMBOLS: <fs_exc> TYPE /sbis/s_cx_core. ASSIGN ('(/SBIS/SAPLGF_PRINT_PROG)GS_EXC') TO <fs_exc>. IF <fs_exc> IS ASSIGNED. <fs_exc>-error_msg_ext = cx_core->lv_error_msg_ext. <fs_exc>-error_msg_detail = cx_core->lv_error_msg_detail && ` <= ` && lv_cur_prog && `->` && lv_cur_form. ENDIF. RAISE EXCEPTION TYPE /sbis/cx_core EXPORTING textid = cx_core->textid lv_error_msg_ext = cx_core->lv_error_msg_ext lv_error_msg_detail = cx_core->lv_error_msg_detail && ` <= ` && lv_cur_prog && `->` && lv_cur_form. ENDTRY. ENDFORM.
В зависимости от флага «gv_not_print» происходит либо печать, либо выход из программы с правильным кодом возврата.
В СБИС Сапере имеются реализации стандартных BADI и точек расширения для программ печати:
- класс «/SBIS/CL_J_3R_INV_BADI» — для печати накладных;
- класс «/SBIS/CL_J3R_TORG12_BADI» — для печати фактур;
- точка расширения «/SBIS/ENHI_J_3RV_TORG12_BIL» — для печати актов.
Проверьте, что активированы BADI «J_3R_TORG12_BADI», «J_3R_INV_BADI» и точка расширения «ESJ_3RV_FORM_UPDATE». Используейте готовые решения, реализованные в данных классах.
Если BADI активированы, установлен статус «Внедрение вызывается».

Пример вызова из BADI для программы печати накладной ТОРГ-12:
METHOD j_3r_torg12_badi_interface~doc_details.
** I_VBDKL TYPE VBDKL
** T_VBDPL TYPE EHS_VBDPL_T
** EDITABLE TYPE XFELD
** HDOC TYPE J_3RV_HT12
** ITEMS TYPE J_3RV_TT12
**************************************************************
* TENSOR SBIS EDO *
**************************************************************
DATA lv_prog_and_field TYPE char255.
TRY.
*" GET NAST
"имя программы берем из инишки сверху
FIELD-SYMBOLS: <lfs_prog_name> TYPE char40.
ASSIGN ('(/SBIS/SAPLGF_PRINT_PROG)GV_PROG_NAME') TO <lfs_prog_name>.
IF <lfs_prog_name> IS ASSIGNED.
lv_prog_and_field = `(` && <lfs_prog_name> && `)` && 'NAST'.
FIELD-SYMBOLS: <lfs_nast> TYPE nast.
* ASSIGN ('(J_3RV_DELIV_PDF)NAST') TO <lfs_nast>.
ASSIGN (lv_prog_and_field) TO <lfs_nast>.
IF <lfs_nast> IS ASSIGNED.
*" MAPPING
DATA CX_ROOT TYPE REF TO CX_ROOT.
DATA cl_mapping TYPE REF TO /sbis/cl_mapping.
CREATE OBJECT cl_mapping.
CALL METHOD cl_mapping->calc_doc
EXPORTING
is_nast = <lfs_nast>
IMPORTING
ev_not_print = gv_not_print.
ELSE.
"нет такой переменной - исключение!
RAISE EXCEPTION TYPE /sbis/cx_core
EXPORTING
textid = /sbis/cx_core=>/sbis/cx_core
lv_error_msg_ext = `Variable not assigned: '`
&& lv_prog_and_field && `'`
lv_error_msg_detail = ''.
ENDIF. " IF <lfs_nast> IS ASSIGNED.
*" EXIT FROM PRINT PROGRAM
IF NOT gv_not_print IS INITIAL.
lv_prog_and_field = `(` && <lfs_prog_name> && `)` && 'VBDKL'.
FIELD-SYMBOLS: <lfs_vbdkl> TYPE vbdkl.
"ASSIGN ('(J_3RV_DELIV_PDF)VBDKL') TO <lfs_vbdkl>.
ASSIGN (lv_prog_and_field) TO <lfs_vbdkl>.
IF <lfs_vbdkl> IS ASSIGNED.
CLEAR <lfs_vbdkl>-vbeln. " хитрый способ выйти из прогр J_3RV_DELIV_PDF
ELSE.
"если в логике программы что-то поменялось - исключение!
RAISE EXCEPTION TYPE /sbis/cx_core
EXPORTING
textid = /sbis/cx_core=>/sbis/cx_core
lv_error_msg_ext = `Variable not assigned: '`
&& lv_prog_and_field && `'`
lv_error_msg_detail = ''.
ENDIF. " IF <lfs_vbdkl> IS ASSIGNED.
ENDIF.
ENDIF. " IF <lfs_prog_name> IS ASSIGNED.
CATCH /sbis/cx_core INTO cx_core.
DATA lv_cur_prog TYPE char255.
DATA lv_cur_form TYPE char255.
CALL METHOD /sbis/cl_core=>get_current_progname
IMPORTING
ev_prog_name = lv_cur_prog
ev_form_name = lv_cur_form.
" exception проходит через прогр печати без текста!
FIELD-SYMBOLS: <fs_exc> TYPE /sbis/s_cx_core.
ASSIGN ('(/SBIS/SAPLGF_PRINT_PROG)GS_EXC') TO <fs_exc>.
IF <fs_exc> IS ASSIGNED.
<fs_exc>-error_msg_ext = cx_core->lv_error_msg_ext.
<fs_exc>-error_msg_detail = cx_core->lv_error_msg_detail
&& ` <= ` && lv_cur_prog && `->` && lv_cur_form.
ENDIF.
RAISE EXCEPTION TYPE /sbis/cx_core
EXPORTING
textid = cx_core->textid
lv_error_msg_ext = cx_core->lv_error_msg_ext
lv_error_msg_detail = cx_core->lv_error_msg_detail
&& ` <= ` && lv_cur_prog && `->` && lv_cur_form.
ENDTRY.
ENDMETHOD.
В зависимости от флага «gv_not_print» происходит либо печать, либо выход из BADI и из программы печати.
Вызов из формуляра нужен, когда в системе нет отдельной программы печати или когда значительная часть логики перенесена в формуляр.
Особенности вызова
- Из программы печати вызывается формуляр. Из него нужно вызвать код СБИС, затем выйти из формуляра, а после — из программы.
- Передаваемые в Сапере данные формуляра должны быть объявлены глобально.
- Вызов кода СБИС нужно вставлять в элемент смартформы «строки программы» — там есть доступ к подготовленным данным печати. Например, в основной цикл по позициям.
- Не нужно вставлять код СБИС в инициализацию. В ней у СБИС Сапера нет доступа к глобальным переменным формуляра через assign. Также в инициализации не обеспечивается корректный выход из формуляра «/ФМ» со значением «rc=0».

Пример кода СБИС:
* TENSOR SBIS EDO
TRY.
DATA CX_ROOT TYPE REF TO CX_ROOT.
DATA lv_not_print TYPE c VALUE ''.
DATA cl_mapping TYPE REF TO /sbis/cl_mapping.
CREATE OBJECT cl_mapping.
CALL METHOD cl_mapping->calc_doc_efg
EXPORTING
iv_ini_name = 'ZSF_INVOICE'
IMPORTING
ev_not_print = lv_not_print.
IF lv_not_print = 'X'.
" надо выйти без печати!
" Set error message
CALL FUNCTION 'SSFRT_WRITE_ERROR'
EXPORTING
i_msgid = '00'
i_msgno = '208'
i_msgv1 = 'SBIS: not print'.
* Raise the excption
user_exception user_canceled.
ENDIF.
CATCH /sbis/cx_core INTO cx_core.
" надо выйти без печати!
" SET error message
CALL FUNCTION 'SSFRT_WRITE_ERROR'
EXPORTING
* I_ERRNUMBER =
i_msgid = '00'
* I_MSGTY = 'E'
i_msgno = '208'
i_msgv1 = 'SBIS: not print'.
* Raise the excption
user_exception user_canceled.
CATCH CX_ROOT INTO CX_ROOT.
" надо выйти без печати!
" SET error message
CALL FUNCTION 'SSFRT_WRITE_ERROR'
EXPORTING
* I_ERRNUMBER =
i_msgid = '00'
* I_MSGTY = 'E'
i_msgno = '208'
i_msgv1 = 'SBIS: not print'.
* Raise the excption
user_exception user_canceled.
ENDTRY.
Как правило, программа печати не требует изменений и сама формирует код возврата.
Вызов из формуляра нужен, когда в системе нет отдельной программы печати или когда значительная часть логики перенесена в формуляр.
Особенности вызова
- Из программы печати вызывается формуляр. Из него нужно вызвать код СБИС, затем выйти из формуляра, а после — из программы.
- Вызов кода СБИС нужно вставлять в интерфейсе формуляра в код инициализации или в подпрограмму — там есть доступ к подготовленным данным печати.

Пример кода СБИС:
**************************************************************
* TENSOR SBIS EDO *
**************************************************************
TRY.
DATA CX_ROOT TYPE REF TO CX_ROOT.
DATA lv_not_print TYPE c VALUE ''.
DATA cl_mapping TYPE REF TO /sbis/cl_mapping.
CREATE OBJECT cl_mapping.
CALL METHOD cl_mapping->calc_doc
EXPORTING
iv_ini_name = 'DP_TOVTORGPR_1175010' "
IMPORTING
ev_not_print = lv_not_print.
IF lv_not_print = 'X'.
RETURN.
MESSAGE ID 'SU' TYPE '-' NUMBER 000 WITH 'SBIS_COMPLETE'
RAISING usage_error.
ENDIF.
CATCH CX_ROOT INTO CX_ROOT.
ENDTRY.
В программе печати нужно предусмотреть корректный выход с правильным кодом возврата.
Пример:
CALL FUNCTION func_module_name
EXPORTING
/1bcdwb/docparams = fp_docparams
h_item = items
h_header = h_doc
IMPORTING
/1bcdwb/formoutput = ls_formoutput
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3.
**************************************************************
* TENSOR SBIS EDO - BEGIN *
**************************************************************
IF sy-subrc <> 0 AND sy-msgv1 = 'SBIS_COMPLETE'.
sy-subrc = 0.
CALL FUNCTION 'FPCOMP_FORM_END'
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3
OTHERS = 4.
ELSEIF sy-subrc <> 0.
**************************************************************
* TENSOR SBIS EDO - END *
**************************************************************
retcode = sy-subrc.
PERFORM protocol_update.
MESSAGE e073 INTO gv_dummy.
PERFORM protocol_update.
ENDIF.
Возможные доработки программ печати
- В программе печати данные, которые нужны для корректного формирования xml, должны храниться в отдельных полях. Например, в программе печати данные о контрагенте (наименование, ИНН/КПП) содержатся в одном поле, а в печатной форме документа — в отдельных строках.