建物料實戰(zhàn):核心參數(shù)、事務(wù)控制與避坑指南)
1. 批量創(chuàng)建物料的整體設(shè)計思路做過 SAP 項目實施或者運維的朋友大概率都遇到過這種需求業(yè)務(wù)部門丟過來一個 Excel里面躺著幾百上千行物料主數(shù)據(jù)讓你盡快導(dǎo)入系統(tǒng)。手工用 MM01 一個個建那得建到明年。這時候就得靠 BAPI 來批量處理了。核心思路其實不復(fù)雜用BAPI_MATERIAL_SAVEDATA這個函數(shù)來創(chuàng)建物料每創(chuàng)建一條就調(diào)用一次BAPI_TRANSACTION_COMMIT提交或者攢一批再統(tǒng)一提交。聽起來簡單但真正落地的時候坑是一個接一個。我見過太多人寫完程序跑一遍發(fā)現(xiàn)物料沒進(jìn)去或者進(jìn)去了一半或者報了一堆看不懂的錯最后只能灰溜溜地回去手工建。這篇文章就是把我這些年在這個場景下踩過的坑、總結(jié)出來的經(jīng)驗完整地梳理一遍。不管你是剛接觸 SAP 接口開發(fā)的新手還是做過一些 BAPI 調(diào)用但總在批量場景下翻車的老手應(yīng)該都能從里面找到有用的東西。我會從整體設(shè)計講到具體實現(xiàn)再到問題排查盡量把每個環(huán)節(jié)的“為什么”說清楚讓你不光能抄作業(yè)還能理解背后的邏輯。1.1 為什么選 BAPI 而不是 BDC 或者 LSMW批量創(chuàng)建物料SAP 里常見的手段有三種BDCBatch Data Communication、LSMWLegacy System Migration Workbench和 BAPI。LSMW 底層其實也是調(diào) BDC 或者 BAPI它更像一個封裝好的工具適合一次性遷移但不適合做成可重復(fù)調(diào)用的程序。BDC 是模擬屏幕操作錄屏之后批量跑優(yōu)點是幾乎任何事務(wù)都能用缺點是慢、不穩(wěn)定屏幕字段稍微一變就崩。BAPI 的優(yōu)勢在于它是 SAP 官方提供的標(biāo)準(zhǔn)接口走的是函數(shù)調(diào)用的路子不依賴屏幕速度快而且有明確的輸入輸出參數(shù)和返回消息。對于物料創(chuàng)建這種標(biāo)準(zhǔn)業(yè)務(wù)對象SAP 提供了BAPI_MATERIAL_SAVEDATA這就是我們的主力工具。它的參數(shù)結(jié)構(gòu)清晰基本能覆蓋 MM01 里絕大部分視圖的字段。當(dāng)然BAPI 也不是萬能的有些字段它不支持有些校驗邏輯和前臺不完全一致這些后面會細(xì)說。選 BAPI 還有一個重要原因它天然支持事務(wù)控制。你可以選擇每條都提交也可以攢一批一起提交甚至可以在出錯時回滾。這個靈活性在批量場景下非常關(guān)鍵因為物料創(chuàng)建涉及多個視圖基本數(shù)據(jù)、采購、MRP、會計等任何一個視圖出錯整條物料就不應(yīng)該被創(chuàng)建。BAPI 配合BAPI_TRANSACTION_COMMIT和BAPI_TRANSACTION_ROLLBACK能很好地實現(xiàn)這種“全有或全無”的邏輯。1.2 批量處理的核心矛盾性能與一致性的平衡批量創(chuàng)建物料繞不開一個核心矛盾你是追求速度還是追求數(shù)據(jù)一致性如果每條物料創(chuàng)建完立刻提交那速度會慢得讓人抓狂因為每次 COMMIT 都是一次數(shù)據(jù)庫提交開銷很大。但如果你攢一大批再提交萬一中間有一條出錯回滾的范圍就很大而且已經(jīng)提交的部分沒法撤銷。我的經(jīng)驗是采用“分批提交”的策略。比如每 50 條或 100 條提交一次這樣既不會因為提交太頻繁拖慢速度也不會因為一次回滾太多導(dǎo)致前功盡棄。具體每批多少條要看物料本身的復(fù)雜程度和系統(tǒng)性能。如果每條物料涉及的視圖很多、字段很全那批次就小一點如果只是建一些基本視圖批次可以大一些。這個值沒有絕對標(biāo)準(zhǔn)需要根據(jù)實際情況測試調(diào)整。還有一個細(xì)節(jié)BAPI_TRANSACTION_COMMIT有一個WAIT參數(shù)。如果設(shè)成X它會等提交完成再返回這樣能確保數(shù)據(jù)真正落庫。在批量場景下我建議在每批的最后一條提交時加上WAIT X中間的提交可以不加這樣能兼顧速度和可靠性。當(dāng)然如果你對數(shù)據(jù)一致性要求極高那就每次都加犧牲一點性能換安心。2. BAPI_MATERIAL_SAVEDATA 的核心參數(shù)拆解要玩轉(zhuǎn)批量創(chuàng)建首先得把BAPI_MATERIAL_SAVEDATA這個函數(shù)的參數(shù)結(jié)構(gòu)吃透。它的參數(shù)不少但常用的就那么幾個。下面我按重要程度一個個說。2.1 關(guān)鍵輸入?yún)?shù)HEADDATA 與各視圖結(jié)構(gòu)HEADDATA是物料的基本信息比如物料號、物料類型、行業(yè)領(lǐng)域、基本計量單位等。這里有個關(guān)鍵點物料號可以外部給也可以讓系統(tǒng)內(nèi)部自動生成。如果你在HEADDATA-MATERIAL里填了值那就是外部給號如果留空系統(tǒng)會根據(jù)物料類型的編號范圍自動分配。批量導(dǎo)入的時候通常業(yè)務(wù)方會在 Excel 里提供物料號所以一般是外部給號。但要注意外部給號需要物料類型的編號范圍配置允許外部編號否則會報錯。除了HEADDATA還有一堆視圖結(jié)構(gòu)比如CLIENTDATA基本數(shù)據(jù)視圖、PLANTDATA工廠數(shù)據(jù)、STORAGELOCATIONDATA存儲位置數(shù)據(jù)、VALUATIONDATA評估數(shù)據(jù)、MRPDataMRP 數(shù)據(jù)等等。每個視圖對應(yīng) MM01 里的一個頁簽。你不需要填所有視圖按業(yè)務(wù)需求來。比如只建基本視圖和采購視圖那就只填CLIENTDATA和PURCHASEDATA。這里有個容易忽略的點有些字段是必填的但 BAPI 不會在調(diào)用時立刻報錯而是等到 COMMIT 的時候才拋出來。比如物料描述、基本計量單位這些如果沒填創(chuàng)建會失敗。所以最好在調(diào)用 BAPI 之前先在程序里做一輪校驗把必填字段檢查一遍避免無謂的調(diào)用。2.2 返回參數(shù)RETURN 表的消息解讀RETURN是一個 BAPIRET2 類型的表里面會返回每條物料創(chuàng)建的結(jié)果。消息類型有 S成功、E錯誤、W警告、I信息。批量場景下這個表會累積所有消息你需要遍歷它把錯誤和警告挑出來。注意有時候 BAPI 返回了 E 類型的消息但物料其實已經(jīng)創(chuàng)建了一部分這時候就需要根據(jù)具體情況決定是回滾還是繼續(xù)。我一般會在程序里把RETURN表按物料號分組每條物料對應(yīng)一組消息。如果某條物料有 E 類型消息就把它標(biāo)記為失敗記錄下錯誤信息然后跳過它繼續(xù)處理下一條。如果整批都處理完了再統(tǒng)一提交成功的部分。但這里有個坑如果一條物料在創(chuàng)建過程中部分視圖成功了部分失敗了BAPI 可能會返回 E但數(shù)據(jù)已經(jīng)寫進(jìn)去了一部分。這時候如果不回滾就會留下臟數(shù)據(jù)。所以我的做法是只要某條物料有 E 類型消息就立刻調(diào)用BAPI_TRANSACTION_ROLLBACK回滾當(dāng)前未提交的內(nèi)容然后重新開始下一批。這樣能保證不會留下半成品。2.3 擴展參數(shù)EXTENSIONIN 的使用場景EXTENSIONIN是一個用來傳遞自定義字段或者 BAPI 標(biāo)準(zhǔn)結(jié)構(gòu)里沒有的字段的表。比如你在物料主數(shù)據(jù)上加了自定義字段Append 結(jié)構(gòu)或者 CI_ 包含這些字段沒法通過標(biāo)準(zhǔn)參數(shù)傳進(jìn)去就得用EXTENSIONIN。它的結(jié)構(gòu)是BAPIPAREX包含STRUCTURE結(jié)構(gòu)名、VALUEPART1到VALUEPART4字段值等。用EXTENSIONIN的時候要注意結(jié)構(gòu)名必須和系統(tǒng)里定義的一致字段值的拼接也要按固定長度來。這個稍微有點繁瑣但一旦調(diào)通后面就很順了。我見過有人因為結(jié)構(gòu)名拼錯了一個字符排查了半天。所以建議把結(jié)構(gòu)名定義成常量別硬編碼在代碼里。3. 批量創(chuàng)建的完整實操流程理論說了一堆現(xiàn)在進(jìn)入正題具體怎么實現(xiàn)。我會按步驟拆解從數(shù)據(jù)準(zhǔn)備到最終提交把每個環(huán)節(jié)的關(guān)鍵點都標(biāo)出來。3.1 數(shù)據(jù)準(zhǔn)備Excel 模板設(shè)計與校驗批量導(dǎo)入的第一步是準(zhǔn)備數(shù)據(jù)。業(yè)務(wù)方給的 Excel 往往格式五花八門你需要先規(guī)范成一個標(biāo)準(zhǔn)模板。我的做法是設(shè)計一個包含所有必要字段的模板每個字段一列第一行是字段名后面是數(shù)據(jù)。字段名最好和 BAPI 參數(shù)對應(yīng)比如MATERIAL、MATL_TYPE、BASE_UOM、MATL_DESC等這樣程序里映射起來方便。模板設(shè)計有幾個要點第一物料號、物料類型、基本計量單位、物料描述這幾個是必填的模板里要標(biāo)紅或者加數(shù)據(jù)驗證防止業(yè)務(wù)方漏填。第二工廠、采購組、MRP 控制者這些字段如果業(yè)務(wù)方不填程序里要給默認(rèn)值否則 BAPI 會報錯。第三日期字段要統(tǒng)一格式比如YYYYMMDD避免解析出錯。數(shù)據(jù)校驗這塊我一般會在程序里做兩層第一層是格式校驗比如物料號長度、物料類型是否存在、計量單位是否有效第二層是業(yè)務(wù)校驗比如物料號是否已存在、物料類型是否允許外部給號。這些校驗?zāi)苓^濾掉大部分低級錯誤減少 BAPI 調(diào)用的失敗率。3.2 調(diào)用 BAPI_MATERIAL_SAVEDATA 的代碼骨架下面是一個簡化的代碼骨架用 ABAP 寫。我盡量把關(guān)鍵注釋加上方便你理解每一步在干什么。DATA: lt_return TYPE TABLE OF bapiret2, ls_head TYPE bapimathead, ls_client TYPE bapi_mara, ls_clientx TYPE bapi_marax, ls_plant TYPE bapi_marc, ls_plantx TYPE bapi_marcx, ls_return TYPE bapiret2. LOOP AT lt_input INTO ls_input. 清空結(jié)構(gòu) CLEAR: ls_head, ls_client, ls_clientx, ls_plant, ls_plantx, lt_return. 填充 HEADDATA ls_head-material ls_input-material. ls_head-matl_type ls_input-matl_type. ls_head-base_uom ls_input-base_uom. ls_head-industry_sector ls_input-industry_sector. 填充基本數(shù)據(jù)視圖 ls_client-matl_desc ls_input-matl_desc. ls_clientx-matl_desc X. 標(biāo)記該字段需要更新 填充工廠數(shù)據(jù) ls_plant-plant ls_input-plant. ls_plant-purch_group ls_input-purch_group. ls_plantx-plant ls_input-plant. ls_plantx-purch_group X. 調(diào)用 BAPI CALL FUNCTION BAPI_MATERIAL_SAVEDATA EXPORTING headdata ls_head clientdata ls_client clientdatax ls_clientx plantdata ls_plant plantdatax ls_plantx TABLES returnmessages lt_return. 檢查返回消息 READ TABLE lt_return INTO ls_return WITH KEY type E. IF sy-subrc 0. 有錯誤記錄日志回滾 CALL FUNCTION BAPI_TRANSACTION_ROLLBACK. 記錄錯誤信息到日志表 ELSE. 無錯誤繼續(xù)處理下一條 ENDIF. 每 50 條提交一次 IF sy-tabix MOD 50 0. CALL FUNCTION BAPI_TRANSACTION_COMMIT EXPORTING wait X. ENDIF. ENDLOOP. 處理剩余未提交的數(shù)據(jù) CALL FUNCTION BAPI_TRANSACTION_COMMIT EXPORTING wait X.這段代碼的核心邏輯是逐條調(diào)用 BAPI有錯誤就回滾并記錄沒錯誤就繼續(xù)每 50 條提交一次。注意CLIENTDATAX和PLANTDATAX這些 X 結(jié)構(gòu)它們用來標(biāo)記哪些字段需要更新。如果你不填 X 結(jié)構(gòu)BAPI 會忽略對應(yīng)的數(shù)據(jù)字段。這是很多人第一次用 BAPI 時容易踩的坑明明傳了值但數(shù)據(jù)沒進(jìn)去就是因為沒填 X 結(jié)構(gòu)。3.3 提交與回滾BAPI_TRANSACTION_COMMIT 的正確用法BAPI_TRANSACTION_COMMIT的用法看似簡單但有幾個細(xì)節(jié)值得注意。首先它必須在BAPI_MATERIAL_SAVEDATA調(diào)用之后執(zhí)行否則沒有東西可提交。其次它的WAIT參數(shù)建議在批量場景下按需設(shè)置。如果你在循環(huán)里每次都提交那WAIT設(shè)不設(shè)區(qū)別不大但如果你攢一批提交那最后一條最好設(shè)WAIT X確保數(shù)據(jù)落庫。還有一個容易被忽略的點BAPI_TRANSACTION_COMMIT提交的是當(dāng)前 SAP LUW邏輯工作單元里所有未提交的 BAPI 調(diào)用。也就是說如果你在循環(huán)里調(diào)用了多次BAPI_MATERIAL_SAVEDATA然后調(diào)用一次BAPI_TRANSACTION_COMMIT那前面所有成功的物料都會被一起提交。這既是好事也是壞事好事是性能高壞事是如果中間有一條出錯你沒法只回滾那一條只能全部回滾。所以我的建議是在每次調(diào)用 BAPI 之后立刻檢查RETURN表如果有錯誤就馬上回滾不要讓錯誤累積?;貪L用BAPI_TRANSACTION_ROLLBACK它會把當(dāng)前 LUW 里所有未提交的 BAPI 調(diào)用都撤銷。注意它只能回滾未提交的部分已經(jīng)提交的數(shù)據(jù)是撤不回來的。所以如果你采用分批提交那回滾的范圍就是當(dāng)前批次。這也是為什么批次不要太大的原因之一。4. 常見問題與排查技巧實錄批量創(chuàng)建物料的過程中遇到的問題五花八門。我挑幾個最典型的把排查思路和解決方法整理出來。4.1 物料創(chuàng)建成功但數(shù)據(jù)不完整這是最常見的問題之一。程序跑完了RETURN表里也沒有 E 類型消息但去 MM03 一看發(fā)現(xiàn)某些字段是空的。原因通常有兩個一是 X 結(jié)構(gòu)沒填導(dǎo)致 BAPI 忽略了對應(yīng)字段二是字段所在的視圖沒有傳對應(yīng)的數(shù)據(jù)結(jié)構(gòu)。比如你想更新采購視圖的采購組但只傳了CLIENTDATA沒傳PURCHASEDATA那采購組自然不會更新。排查方法先檢查 X 結(jié)構(gòu)是否對應(yīng)填了 X再檢查是否傳了正確的視圖結(jié)構(gòu)。如果還不確定可以在 BAPI 調(diào)用前打一個斷點看看傳入的結(jié)構(gòu)里到底有沒有值。另外有些字段雖然在 BAPI 結(jié)構(gòu)里存在但實際不起作用比如某些視圖的某些字段在后臺配置里被隱藏了這時候傳了也沒用。這種情況需要去 SPRO 里檢查字段選擇配置。4.2 BAPI_TRANSACTION_COMMIT 后數(shù)據(jù)仍未落庫有時候明明調(diào)用了BAPI_TRANSACTION_COMMIT但數(shù)據(jù)就是沒進(jìn)數(shù)據(jù)庫。這種情況多半是因為WAIT參數(shù)沒設(shè)或者提交被后續(xù)的回滾操作抵消了。還有一種可能是你在調(diào)用 COMMIT 之前程序發(fā)生了異常退出導(dǎo)致 LUW 沒有正常結(jié)束。SAP 的 LUW 機制是如果程序在 COMMIT 之前終止所有未提交的更改都會自動回滾。解決方法在批量程序的最后確保有一個顯式的 COMMIT 調(diào)用并且設(shè)置WAIT X。如果程序可能中途退出建議用TRY...CATCH包裹在CATCH里調(diào)用 ROLLBACK保證不會留下未提交的 LUW。另外可以在 COMMIT 之后加一個COMMIT WORK語句雙保險。不過要注意COMMIT WORK和BAPI_TRANSACTION_COMMIT不能混用否則可能報錯。4.3 批量處理中的性能瓶頸與優(yōu)化批量創(chuàng)建物料性能是個大問題。如果每條都提交一千條物料可能要跑幾十分鐘。優(yōu)化的思路有幾個第一減少提交次數(shù)采用分批提交第二關(guān)閉不必要的校驗比如在 BAPI 調(diào)用前先做一輪預(yù)校驗把明顯有問題的數(shù)據(jù)過濾掉避免無效調(diào)用第三使用CALL FUNCTION ... IN UPDATE TASK或者后臺作業(yè)把批量處理放到后臺跑不占用前臺會話。還有一個技巧如果物料類型允許內(nèi)部給號那就讓系統(tǒng)自動分配物料號這樣能避免外部給號時的編號范圍檢查開銷。當(dāng)然這取決于業(yè)務(wù)需求如果業(yè)務(wù)方必須指定物料號那就沒辦法了。另外如果批量數(shù)據(jù)量特別大比如幾萬條建議拆成多個后臺作業(yè)并行跑每個作業(yè)處理一部分?jǐn)?shù)據(jù)。但要注意并行處理時物料號的唯一性校驗可能會沖突需要提前規(guī)劃好號段。4.4 常見錯誤消息速查表下面這個表整理了一些常見的錯誤消息和解決方法方便你快速定位問題。錯誤消息可能原因解決方法物料號已存在外部給號時物料號重復(fù)檢查物料號是否已存在或改用內(nèi)部給號物料類型不允許外部編號物料類型的編號范圍配置為內(nèi)部修改物料類型配置或改用內(nèi)部給號基本計量單位不存在計量單位未維護(hù)或拼寫錯誤檢查計量單位是否在系統(tǒng)里存在工廠不存在工廠代碼錯誤或未配置檢查工廠代碼是否正確采購組不存在采購組未維護(hù)檢查采購組是否在系統(tǒng)里存在物料描述不能為空必填字段未填在程序里做必填校驗評估類不能為空評估視圖必填字段未填補充評估類字段會計視圖未維護(hù)評估類對應(yīng)的會計視圖未配置檢查后臺配置這個表不是萬能的但覆蓋了大部分常見情況。遇到不認(rèn)識的錯誤消息可以去 SE91 里查消息類或者用事務(wù)代碼BAPI查看 BAPI 的文檔。4.5 實操心得與避坑建議最后分享幾個我踩過坑之后總結(jié)出來的經(jīng)驗。第一永遠(yuǎn)不要相信業(yè)務(wù)方給的 Excel 數(shù)據(jù)是干凈的。一定要在程序里做嚴(yán)格的校驗寧可多花點時間校驗也不要讓臟數(shù)據(jù)進(jìn) BAPI。第二批量程序一定要有日志。每條物料的處理結(jié)果、錯誤信息、提交狀態(tài)都要記錄下來方便事后追溯。第三測試環(huán)境先跑一遍確認(rèn)沒問題再上生產(chǎn)。生產(chǎn)環(huán)境的數(shù)據(jù)量和測試環(huán)境可能差很多性能表現(xiàn)也會不一樣。第四如果批量數(shù)據(jù)量很大建議分批次跑每批之間留點間隔避免把系統(tǒng)資源占滿。第五BAPI 的返回消息一定要仔細(xì)看有時候 W 類型的警告也可能導(dǎo)致數(shù)據(jù)不完整別忽略。還有一個細(xì)節(jié)BAPI_MATERIAL_SAVEDATA在創(chuàng)建物料時如果物料已經(jīng)存在它會嘗試更新而不是創(chuàng)建。這個行為有時候會帶來意外比如你本想創(chuàng)建新物料結(jié)果把已有物料的數(shù)據(jù)覆蓋了。所以調(diào)用之前最好先檢查物料是否存在如果存在就跳過或者報錯避免誤操作。批量創(chuàng)建物料這件事說難不難說簡單也不簡單。核心就是理解 BAPI 的參數(shù)結(jié)構(gòu)、掌握事務(wù)控制的節(jié)奏、做好數(shù)據(jù)校驗和日志記錄。把這幾點做到位基本就不會出大問題。剩下的就是根據(jù)具體業(yè)務(wù)場景調(diào)整細(xì)節(jié)多跑幾次測試積累經(jīng)驗。我在實際項目里用這套方法處理過幾萬條物料數(shù)據(jù)整體下來還是比較穩(wěn)的。希望這些經(jīng)驗對你有幫助。