Sapforum.Biz
Инструменты => ABAP - Инструментальные средства => Тема начата: alexey11 от Февраль 05, 2014, 05:59:42 pm
-
Недавно написал программу для изменения контракта ММ с помощью 'BAPI_CONTRACT_CHANGE' по данным из файла. Все оттестили, отдали юзерам. Но оказывается что внутренние модули обновления условий работают как-то странно, из-за чего никаких изменений в контракте нет:
Есть контракт на 573 позиции. Пытаемся добавить через бапи 22 новых позиции. Падает в дамп SAPSQL_ARRAY_INSERT_DUPREC (The ABAP/4 Open SQL array insert results in duplicate database records)
Информация о месте прерывания
Termination occurred in the ABAP program "RV13A016" - in "DB_UPDATE".
The main program was "RSM13000 ".
In the source code you have the termination point in line 662
of the (Include) program "RV13A016".
The program "RV13A016" was started in the update system.
The termination is caused because exception "CX_SY_OPEN_SQL_DB" occurred in
procedure "DB_UPDATE" "(FORM)", but it was neither handled locally nor declared
in the RAISING clause of its signature.
The procedure is in program "RV13A016 "; its source code begins in line
637 of the (Include program "RV13A016 ".
Вот дамповый код
*----------------------------------------------------------------------
* FORM DB_UPDATE *
*----------------------------------------------------------------------
* Datenbankveränderung der Tabelle $KOTAB *
*----------------------------------------------------------------------
* --> UPDATE_TAB : Tabelle mit allen Einträgen für die Veränderung *
* --> DB_ACTION : I = INSERT *
* U = UPDATE *
* D = DELETE *
* <-- DEL_SUBRC : Returncode nach DELETE *
*----------------------------------------------------------------------
FORM DB_UPDATE TABLES UPDATE_TAB STRUCTURE TIME_VAKE_DB
USING DB_ACTION TYPE CHAR1
DB_SUBRC LIKE SY-SUBRC.
...............................
* Datenbankveränderung durchführen *
CASE DB_ACTION.
* Insert *
WHEN 'I'.
INSERT A016 FROM TABLE A016_DB. // <- вот здесь дамп
* Update *
WHEN 'U'.
..............................
ENDFORM.
Кстати в 'BAPI_CONTRACT_CHANGE'-return-table пишет что контракт изменен.
Дамп выкидывается в САП-почту (как понимаю после BAPI_TRANSACTION_COMMIT).
Отлаживаю в SM13. Выясняем что в A016_DB сап на каждую новую позицию контракта зачемто создал по 2 совершенно одинаковые записи (всего не 22 как должно быть, а 44 записи).
На вход бапи данные закинуты корректно, так как тщательно тестили программу и раньше, и сейчас, но НА НЕБОЛЬШИХ КОНТРАКТАХ (50 позиций) И ВСЕ ПРОХОДИТ БЕЗ ПРОБЛЕМ (а на контракте в 90 позиций уже не хочет)
Решение на сап-портале - установка ноты 1090044. Но она уже есть в инстале сапа.... А проблема как была так и есть...
Может кто сталкивался с подобными проделками сапа?
-
Кстати в 'BAPI_CONTRACT_CHANGE'-return-table пишет что контракт изменен.
Дамп выкидывается в САП-почту (как понимаю после BAPI_TRANSACTION_COMMIT).
Дамп выкидывают функции обновления, которые вызываются после коммита.
Отлаживаю в SM13. Выясняем что в A016_DB сап на каждую новую позицию контракта зачемто создал по 2 совершенно одинаковые записи (всего не 22 как должно быть, а 44 записи).
Для отладки надо включить отладку обновлений при переходе в отладчик перед сохранением.
На вход бапи данные закинуты корректно, так как тщательно тестили программу и раньше, и сейчас, но НА НЕБОЛЬШИХ КОНТРАКТАХ (50 позиций) И ВСЕ ПРОХОДИТ БЕЗ ПРОБЛЕМ (а на контракте в 90 позиций уже не хочет)
Ну что могу сказать, я контракты с таким количеством позиций к сожалению не создавал, поэтому сказать что-то сложно. Идите в отладку и ищите где заполняются эти таблицы. Я бы сделал такую вещь как поставил бы точку остановки в ФМ BAPI_AGMT_COND_UPLOAD, строчка 157 где идет вызов программы RV13A016, думаю что где-то там не правильно идет заполнение. Кстати не обратили внимание ошибка при первом вызове всегда идет? Или скажем так первый раз обновление проходит, а при повторных вызовах всегда падает? В общем включаем отладку обновлений и смотрим что и как заполняется.
-
в общем причина оказывается в том, что при добавлении новых позиций в контракт через бапи сап подтягивает данные условия инфо-записи закупки (если дата загрузки входит в диапазон действия условия)!
И тут два варианта:
1) если у условия нет индикатора удаления - бапи отрабатывает без ошибок и в логе так и пишет, что цена взята из условия (несмотря на то что мы давали совсем другую цену). Тут даже не помогает явная установка поля BAPIMEOUTITEM-CALCTYPE = 'B' (Провести нове ціноутворення).
2) если у условия инфозаписи стоит индикатор удаления - бапи тащит в модули обновления это условие с ценой 0 . Плюс ту цену, которую задали в БАПИ. (т.е. 2 строки на которых и летит дамп).
Пока решено менять дату завершения действия условия с 99991231 на другую, чтоб текущая дата не попадала в диапазон. Но чуствую решение до поры до времени и по-любому в принципе не решает проблему . :-\
Перепробовал много вариантов закидывания данных в 'BAPI_CONTRACT_CHANGE'. Может где-то все таки есть параметр чтоб сап не трогал цены инфозаписи.
-
Привет.
А попробуй использовать параметр EVO: SPRO-УММ-Закупки-Определение для закупщика значений по умолчанию.
Создаете свой код, например 99, и для него на закладке КопировЦены устанавливаете флаг "Цена вручную как цена брутто".
Присваиваете пользователю, под которым выполняется изменение контракта параметр EVO со значением созданного кода(например, 99 как указал выше).
-
Перепробовал много вариантов закидывания данных в 'BAPI_CONTRACT_CHANGE'. Может где-то все таки есть параметр чтоб сап не трогал цены инфозаписи.
Можешь пример заполнения структур для этого BAPI-вложить? Есть у меня одна мысль, но хочу текст увидеть. Особенно интересует вариант заполнения структур:
ITEM LIKE BAPIMEOUTITEM
ITEMX LIKE BAPIMEOUTITEMX
-
Привет.
А попробуй использовать параметр EVO: SPRO-УММ-Закупки-Определение для закупщика значений по умолчанию.
...
Никаких изменений нет. :(
Можешь пример заполнения структур для этого BAPI-вложить? Есть у меня одна мысль, но хочу текст увидеть. Особенно интересует вариант заполнения структур:
ITEM LIKE BAPIMEOUTITEM
ITEMX LIKE BAPIMEOUTITEMX
Как то так:
TABLES: ekpo.
data gs_BAPIMEOUTHEADER type BAPIMEOUTHEADER. " для вызова BAPI
data gs_BAPIMEOUTHEADERX type BAPIMEOUTHEADERX. " для вызова BAPI
data gt_BAPIMEOUTITEM type BAPIMEOUTITEM OCCURS 0. " для вызова BAPI
data gs_BAPIMEOUTITEM type BAPIMEOUTITEM. " для вызова BAPI
data gt_BAPIMEOUTITEMX type BAPIMEOUTITEMX OCCURS 0. " для вызова BAPI
data gs_BAPIMEOUTITEMX type BAPIMEOUTITEMX. " для вызова BAPI
data gt_BAPIMEOUTVALIDITY type BAPIMEOUTVALIDITY OCCURS 0.
data gs_BAPIMEOUTVALIDITY type BAPIMEOUTVALIDITY.
data gt_BAPIMEOUTVALIDITYX type BAPIMEOUTVALIDITYX OCCURS 0.
data gs_BAPIMEOUTVALIDITYX type BAPIMEOUTVALIDITYX.
data gt_BAPIMEOUTCONDITION type BAPIMEOUTCONDITION OCCURS 0.
data gs_BAPIMEOUTCONDITION type BAPIMEOUTCONDITION.
data gt_BAPIMEOUTCONDITIONX type BAPIMEOUTCONDITIONX OCCURS 0.
data gs_BAPIMEOUTCONDITIONX type BAPIMEOUTCONDITIONX.
data gt_BAPIRET2 type BAPIRET2 OCCURS 0. " для вызова BAPI
data gs_bapiret2 type bapiret2. " для вызова BAPI
types: begin of gtp_ekpo,
UPDATE_TYPE type c, " I - вставка позиции, U - обновление позиции
KDATB type KDATB,
COND_ITEM type KNUMB, " номер условия
LDDEL type BOOLE_D.
include structure ekpo.
types: end of gtp_ekpo.
data gt_ekpo type gtp_ekpo occurs 0. " данные позиций контракта для обновления
data gs_ekpo type gtp_ekpo.
SELECTION-SCREEN BEGIN OF BLOCK optForUpdate WITH FRAME TITLE text-004.
SELECT-OPTIONS s_EBELN1 FOR ekpo-EBELN no-EXTENSION no intervals MODIF ID 004.
SELECTION-SCREEN END OF BLOCK optForUpdate.
" ....................................................................
refresh: gt_BAPIMEOUTITEM, gt_BAPIMEOUTITEMX, gt_BAPIRET2.
REFRESH: gt_BAPIMEOUTCONDITION, gt_BAPIMEOUTCONDITIONX, gt_BAPIMEOUTVALIDITY, gt_BAPIMEOUTVALIDITYX.
clear gs_BAPIMEOUTHEADER.
gs_BAPIMEOUTHEADER-number = s_EBELN1-low.
loop at gt_ekpo into gs_ekpo.
CLEAR: gs_BAPIMEOUTITEM, gs_BAPIMEOUTITEMX.
if gs_ekpo-update_type = 'U'. " если позиция обновляется
""
elseif gs_ekpo-update_type = 'I'. " если позиция вставляется --------->
gs_BAPIMEOUTITEM-ITEM_NO = gs_ekpo-ebelp.
gs_BAPIMEOUTITEM-MATERIAL = gs_ekpo-matnr.
gs_BAPIMEOUTITEM-EMATERIAL = gs_ekpo-matnr.
gs_BAPIMEOUTITEM-PLANT = gs_ekpo-werks.
gs_BAPIMEOUTITEM-PO_UNIT = gs_ekpo-meins.
gs_BAPIMEOUTITEM-PO_UNIT_ISO = gs_ekpo-meins.
gs_BAPIMEOUTITEM-ORDERPR_UN = gs_ekpo-bprme.
gs_BAPIMEOUTITEM-ORDERPR_UN_ISO = gs_ekpo-bprme.
gs_BAPIMEOUTITEM-NET_PRICE = gs_ekpo-netpr.
gs_BAPIMEOUTITEM-PRICE_UNIT = gs_ekpo-PEINH.
gs_BAPIMEOUTITEM-ITEM_CAT = '0'.
gs_BAPIMEOUTITEM-COND_GROUP = gs_ekpo-EKKOL.
gs_BAPIMEOUTITEM-CONF_CTRL = gs_ekpo-BSTAE.
gs_BAPIMEOUTITEM-GR_BASEDIV = gs_ekpo-WEBRE.
APPEND gs_BAPIMEOUTITEM to gt_BAPIMEOUTITEM.
gs_BAPIMEOUTITEMX-ITEM_NO = gs_BAPIMEOUTITEM-ITEM_NO.
gs_BAPIMEOUTITEMX-ITEM_NOX = 'X'.
gs_BAPIMEOUTITEMX-MATERIAL = 'X'.
gs_BAPIMEOUTITEMX-EMATERIAL = 'X'.
gs_BAPIMEOUTITEMX-PLANT = 'X'.
gs_BAPIMEOUTITEMX-PO_UNIT = 'X'.
gs_BAPIMEOUTITEMX-PO_UNIT_ISO = 'X'.
gs_BAPIMEOUTITEMX-ORDERPR_UN = 'X'.
gs_BAPIMEOUTITEMX-ORDERPR_UN_ISO = 'X'.
gs_BAPIMEOUTITEMX-NET_PRICE = 'X'.
gs_BAPIMEOUTITEMX-PRICE_UNIT = 'X'.
gs_BAPIMEOUTITEMX-ITEM_CAT = 'X'.
gs_BAPIMEOUTITEMX-COND_GROUP = 'X'.
gs_BAPIMEOUTITEMX-CONF_CTRL = 'X'.
gs_BAPIMEOUTITEMX-GR_BASEDIV = 'X'.
APPEND gs_BAPIMEOUTITEMx to gt_BAPIMEOUTITEMx.
endif. " <-------------
endloop.
if LINES( gt_BAPIMEOUTITEM ) > 0.
CALL FUNCTION 'BAPI_CONTRACT_CHANGE'
EXPORTING
purchasingdocument = gs_BAPIMEOUTHEADER-number
TABLES
ITEM = gt_BAPIMEOUTITEM
ITEMX = gt_BAPIMEOUTITEMx
" ITEM_COND_VALIDITY = gt_BAPIMEOUTVALIDITY " для вставляемых позиций не заполняется, только для обновляемых
" ITEM_COND_VALIDITYX = gt_BAPIMEOUTVALIDITYx " для вставляемых позиций не заполняется, только для обновляемых
" ITEM_CONDITION = gt_BAPIMEOUTCONDITION " для вставляемых позиций не заполняется, только для обновляемых
" ITEM_CONDITIONX = gt_BAPIMEOUTCONDITIONx " для вставляемых позиций не заполняется, только для обновляемых
RETURN = gt_BAPIRET2
.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
WAIT = 'X'
.
endif.
-
Никаких изменений нет. :(
Значит так добавь такие строчки:
gs_BAPIMEOUTITEM-INFO_REC = space.
gs_BAPIMEOUTITEMX-INFO_REC = 'X'.
-
Значит так добавь такие строчки:
gs_BAPIMEOUTITEM-INFO_REC = space.
gs_BAPIMEOUTITEMX-INFO_REC = 'X'.
Это тоже без результата. В ходе жесткого дебага обнаружил, что поле инфозаписи во внутренних переменных по-любому заполняется (вот здесь LMEOUTP58 ->
METHOD is_valid.
........
* read the inforecord
CALL FUNCTION 'ME_READ_INFORECORD'
EXPORTING
incom = ls_meico
IMPORTING
einadaten = l_context->eina
einedaten = l_context->eine
excom = ls_meicr
EXCEPTIONS
bad_comin = 01
bad_material = 02
bad_materialclass = 03
bad_supplier = 04
not_found = 05.
IF sy-subrc EQ 0.
l_context->item_new->item-infnr = l_context->eina-infnr.
* if the info record's deletion indicator is set, clear context data,
* so that info record data is not used to populate other fields.
IF NOT ls_meicr-loekz IS INITIAL.
IF l_context->item_new->aktyp = cl_mmpur_constants=>hin.
CLEAR l_context->item_new->item-infnr.
.............
и потом как ни в чем небывало используется дальше для получения условий.
Тут походу может спасти только установка делит-индикатора на всю инфозапись .... либо как говорил выше - замена дат в диапазонах действия условий
Но больше всего меня поразил следующий выполняемый стандартный код (LMEOUTP40, стр 398)
METHOD is_valid.
...................
IF ( l_context->item_new->ref_contract_it-ebeln EQ space OR
l_context->item_new->ref_contract_it-pstyp EQ
cl_mmpur_constants=>pstyp_wagr ) AND
l_context->item_new->copied_item-ebeln EQ space AND
l_context->item_new->copied_item-ebelp EQ space AND
( l_context->eine-infnr NE space AND " ВОТ ЭТО ДЛЯ НОВЫХ ПОЗИЦИЙ ЗАПОЛНЕНО ПОЛЮБОМУ
( l_context->item_new->item-meins EQ
l_context->eina-meins OR
l_context->eina-vabme EQ '2' ) AND
l_context_hd->header_new->header-logsy IS INITIAL AND " <----------------- ВОТ ЭТО ЗАЧЕМ ????????????????
l_context->eine-loekz EQ space AND "marked for deletion
l_context->eina-loekz EQ space "don't copy conditions
) AND
l_mastercond->has_cond_found( ) EQ cl_mmpur_constants=>no.
* copy the conditions from the info record
CALL METHOD l_mastercond->copy_from_inforec( " ТОТ САМЫЙ КОРЕНЬ ЗЛА, В К-РОМ БЕРУТСЯ НЕНУЖНЫЕ УСЛОВИЯ ИЗНФЗПС
EXPORTING im_ebelp = l_context->item_new->item-ebelp
IMPORTING ex_ekpo = ls_ekpo_result
ex_retco = lf_retco ).
ENDIF.
.......................................
Т.е. если в BAPIMEOUTHEADER / BAPIMEOUTHEADERX записать в поле LOGSYSTEM какую-то ерунду (например букву Z) и дать бапи, метод l_mastercond->copy_from_inforec не выполнится и никаких дампов. Контракт нормально сохраняется без предупреждений, без ошибок. ;D
Можно ли так делать или лучше не стоит использовать этот параметр и для чего он теоретически предполагается ?
-
Т.е. если в BAPIMEOUTHEADER / BAPIMEOUTHEADERX записать в поле LOGSYSTEM какую-то ерунду (например букву Z) и дать бапи, метод l_mastercond->copy_from_inforec не выполнится и никаких дампов. Контракт нормально сохраняется без предупреждений, без ошибок. ;D
Однако, вообще-то это не Z и не какая-то ерунда это имя логической системы, настраивается для манданта T000-LOGSYS вот и его надо указывать. Т.е. получается что надо правильно заполнить имя логической системы для BAPI, и тогда все проходит без всяких дампов.
Вообще-то если этот параметр пустой то обычно внутри кода BAPI, это поле заполняется автоматически правильным значением, но видно для этого BAPI забыли такое сделать, поэтому надо заполнять самому правильным кодом логической системы. Вообще там есть ФМ, который возвращает имя системы, ну чтобы его не читать из таблицы мандантов.
-
Ну то что это логическая система - это видно из описания структуры ). это я так сказал - заполнить ерундой....
Но тем не менее, заполняя буквой Z или D или любой другой у меня в системе все идет нормально...
Буду брать из T000 или из фм OWN_LOGICAL_SYSTEM_GET и надеяться, что и дальше никакие сюрпризы не выплывут.
PS А вот как они (SAP AG) забывают это заполнять - мне не совсем понятно (ведь это все-таки программа не за 100/1000 грн). И как этот баг столько времени остается незамеченным (почти 9 лет, если считать от даты деблокирования фм), мне тоже не совсем понятно... (ничего нестандартного с инфозаписями вроде не делаем, а почему дамп...) Ну это так мысли вслух.
Всем спасибо за помощь.