SAP Scripting Tracker 是一款實用工具,該工具能記錄在 SAP 系統(tǒng)中的操作,并根據(jù)所選擇的編程語言 (支持 PowerShell, VB.Net ,C#, Python JShell for Java 等多種語言),以腳本的方式進行回放,從而提升工作效率。SAP 曾經(jīng)提供過基于 COM 技術的 SAP GUI Scripting, 但因為微軟從 Windows 7 之后停止了代理(agent, 也稱向導)的發(fā)布,所以 SAP GUI Scripting 也不能使用,因為 SAP GUI Scripting 依賴該技術 (詳見 oss note 1633639)。所以 SAP Scripting Tracker 就成為 SAP GUI Scripting 的一個很好的替代品。
軟件下載和安裝
SAP Scripting Tracker 是一款自由軟件,可以自由使用,軟件可以在 https://tracker.stschnell.de 下載。
使用前的環(huán)境配置
軟件 解壓后,在根目錄下面有一篇 Tracker.pdf 文檔,是對該軟件使用的詳細說明,可以仔細研讀一遍。我根據(jù)自己的理解,將最基本的使用要求說明如下:
SAP GUI 前臺配置
允許使用腳本
注意,在安裝 SAP GUI 的時候,要安裝 SAP GUI Scripting,在 SAP GUI 中配置允許使用腳本,但取消消息提示:

設置F1和F4幫助提示框的類型
需要將 F1 和 F4 幫助提示框的樣式都改成 dialog,進入系統(tǒng)在菜單 【Help】- 【Settings】進行設置:


SAP服務器端設置
設置 sapgui/user_scripting 參數(shù),將 Current Value 設置為 TRUE:

點擊 Display 按鈕,進入下一屏幕更改。

SAP 操作的錄制和回放
打開 Tracker.exe,通過 SAP GUI 進入 SAP Easy Access 界面。點擊 Scripting Tracker 左上角 Scan Scripting objects 按鈕 ,可以看到 SAP 登錄信息已經(jīng)被記錄,包括 SID, Session,User 等。

切換到 Recorder 頁簽,點擊紅色的圓形按鈕,開始錄制。假設我們想用 F.08 查看總賬科目余額的清單。當我們在 SAP 中操作的時候,我們發(fā)現(xiàn)軟件已經(jīng)將操作以腳本的方式進行了記錄:

操作完成后,點擊黃色的按鈕,停止記錄。此時,我們將 SAP 的界面重新退回到 SAP Easy Access 界面(/n),然后點擊 Tracker 最左邊的綠色按鈕進行運行,可以看到,剛才的操作自動像錄像一樣回放。
通過腳本實現(xiàn)自動化
Tracker 默認使用的是 Antimalware scan,這個軟件的方便之處就是支持多種編程語言,接下來我演示如何通過 Python 來記錄腳本。如果想使用 Python 環(huán)境,在 PC 上需要安裝 Python 解釋器,并且需要安裝 pywin32 模塊。
框架代碼 (Frame)
和剛才腳本稍微不同的是,并不是所有語言都是能自動回放的,如果是 C#, Python 這樣的語言,Tracker 只記錄在 session 中的操作,對于 session 中控件的識別需要有額外的框架代碼。這些框架代碼 tracker.pdf 已經(jīng)幫我們寫好了,對于 Python 來說,代碼在幫助文件的 130 頁。

為了方便后續(xù)使用,我將 Frame 的代碼封裝在 SapSession 模塊中的 getSession函數(shù)中,代碼如下:
import sys, win32com.client
def getSession():
try:
SapGuiAuto = win32com.client.GetObject("SAPGUI")
application = SapGuiAuto.GetScriptingEngine
application.HistoryEnabled = False
connection = application.Children(0)
if connection.DisabledByServer == True:
print("Scripting is disabled by server")
application = None
SapGuiAuto = None
return
session = connection.Children(0)
if session.Busy == True:
print("Session is busy")
session = None
connection = None
application = None
SapGuiAuto = None
return
if session.Info.IsLowSpeedConnection == True:
print("Connection is low speed")
session = None
connection = None
application = None
SapGuiAuto = None
return
return session
except Exception as e:
print(e)
print(sys.exc_info()[0])
finally:
application.HistoryEnabled = True
session = None
connection = None
application = None
SapGuiAuto = None
然后再回到 Tracker.exe,將腳本語言選擇為 Python,用剛才同樣的方法錄制一遍。

在錄制的過程中,tracker 已經(jīng)用 python 語言記錄了操作的腳本:

在 Python 編輯器中,新建一個 f08.py 文件,將剛才的代碼拷貝到文件中,代碼如下:
from SapSession import getSession
def runF08():
session = getSession()
session.findById("wnd[0]").maximize()
session.findById("wnd[0]/tbar[0]/okcd").text = "f.08"
session.findById("wnd[0]").sendVKey(0)
session.findById("wnd[0]/usr/ctxtSD_KTOPL-LOW").text = "Z900"
session.findById("wnd[0]/usr/ctxtSD_BUKRS-LOW").text = "z900"
session.findById("wnd[0]/usr/txtSD_GJAHR-LOW").text = "2022"
session.findById("wnd[0]/usr/txtB_MONATE-LOW").text = "01"
session.findById("wnd[0]/usr/txtB_MONATE-HIGH").text = "01"
session.findById("wnd[0]/tbar[1]/btn[8]").press()
if __name__ == '__main__':
runF08()
然后我們就可以以 Python 腳本的方式來運行了。
做一個可以錄入會計憑證的腳本
錄入的數(shù)據(jù)放在 excel 中 (importfile.xlsx):

因為只是一個簡單的示意,所以字段比較少。有了基礎的數(shù)據(jù)準備之后,我們使用 Python 的 pandas 來讀取數(shù)據(jù),并轉化為由 dict 組成的列表:
def uploadData():
df = pd.read_excel("importfile.xlsx")
return df.to_dict("records")
打印的數(shù)據(jù)如下:
[{'憑證號碼': 1, '憑證日期': '2022.09.05', '過賬日期': '2022.09.05', '幣別': 'CNY', '行': 1, '過
賬碼': 40, '科目': 10010100, '金額': 700}, {'憑證號碼': 1, '憑證日期': '2022.09.05', '過賬日期': '2022.09.05', '幣別': 'CNY', '行': 2, '過賬碼': 50, '科目': 10020100, '金額': 700}]
通過錄屏的方法生成腳本,然后對腳本稍作改造。為了防止屏幕的錯誤,在 SapSession 模塊中增加一個函數(shù),讓屏幕回到 Easy Access 界面
def returnEasyAccess(session):
session.findById("wnd[0]/tbar[0]/okcd").text = "/n"
session.findById("wnd[0]").sendVKey(0)
以下是錄入會計憑證的完整代碼:
from SapSession import getSession, returnEasyAccess
import pandas as pd
def uploadData():
df = pd.read_excel("importfile.xlsx")
return df.to_dict("records")
def fiDocumentEntry():
# 獲取數(shù)據(jù)
data = uploadData()
session = getSession()
returnEasyAccess(session)
# F-02 事務碼
session.findById("wnd[0]").maximize()
session.findById("wnd[0]/tbar[0]/okcd").text = "F-02"
session.findById("wnd[0]").sendVKey(0)
# 會計憑證抬頭
session.findById("wnd[0]/usr/ctxtBKPF-BLDAT").text = data[0].get("憑證日期")
session.findById("wnd[0]/usr/ctxtBKPF-BUKRS").text = "Z900"
session.findById("wnd[0]/usr/ctxtBKPF-BUDAT").text = data[0].get("過賬日期")
session.findById("wnd[0]/usr/ctxtBKPF-WAERS").text = data[0].get("幣別")
# 循環(huán)錄入每一行
for row in data:
session.findById("wnd[0]/usr/ctxtRF05A-NEWBS").text = row["過賬碼"]
session.findById("wnd[0]/usr/ctxtRF05A-NEWKO").text = row["科目"]
session.findById("wnd[0]/usr/ctxtRF05A-NEWKO").setFocus()
session.findById("wnd[0]/usr/ctxtRF05A-NEWKO").caretPosition = 8
session.findById("wnd[0]").sendVKey(0) # 回車
session.findById("wnd[0]/usr/txtBSEG-WRBTR").text = row["金額"]
if str(row["科目"]) == "10020100": # 銀行科目需要起息日
session.findById("wnd[0]/usr/ctxtBSEG-VALUT").text = row["過賬日期"]
# 模擬后過賬
session.findById("wnd[0]/mbar/menu[0]/menu[3]").select()
session.findById("wnd[0]/tbar[0]/btn[11]").press()
if __name__ == '__main__':
fiDocumentEntry()
參考
Tip: An Effective Way to use SAP GUI Scripting Recording | Community Chat (blueprism.com)