sap系统作为客户常用的系统,经常在不同客户的业务场景中遇到,但其中有一些操作是共用的,在这里整理出一些常见操作的模块化代码,以便之后直接调用。
    1.选择sap环境
    image.png
    登录SAP系统前需要选定环境,但是名称是可以随意编辑的,如果按照名称来选定,万一发生更改或者环境太多重名的情况,可能会导致流程运行失败,所以最好的方式是根据环境的IP去定位,然后进行选择。

    模块化代码:
    /
    获取环境ip对应的目标元素
    env:环境ip
    /
    Function GetEnvIP(env)
    //初始化
    Dim sRet =””
    Dim arrElement =””
    Dim Elements=[]
    Dim element

    //行列展开
    //获取每一列的列头元素(如果父元素有变更,可以根据某一列头元素获取父元素)
    #icon(“@res:default.png”)
    arrElement =UiElement.GetChildren({ “ctrl”: [ { “aid”:”Header”,”name”:”标头控件”,”role”:”ROLE_SYSTEM_LIST” } ],”wnd”: [ { “app”:”saplogon”,”cls”:”#“,”title”:”SAP Logon “ }, { “cls”:”AfxOleControl110” }, { “cls”:”AfxMDIFrame110” }, { “cls”:”AfxFrameOrView110”,”idx”:1 }, { “aaname”:”myContainer”,”cls”:”Afx:“,”title”:”myContainer” }, { “cls”:”SysListView32” }, { “aaname”:”标头控件”,”cls”:”SysHeader32” } ] },{“bContinueOnError”:False,”iDelayAfter”:300,”iDelayBefore”:200})
    //遍历元素,左键双击展开
    For Each val In arrElement
    #icon(“@res:default.png”)
    Mouse.Action(val,”left”,”dbclick”,10000,{“bContinueOnError”:False,”iDelayAfter”:300,”iDelayBefore”:200,”bSetForeground”:True,”sCursorPosition”:”TopRight”,”iCursorOffsetX”:0,”iCursorOffsetY”:0,”sKeyModifiers”:[],”sSimulate”:”message”,”bMoveSmoothly”:False})
    Next

    //获取整个表格的每一行元素(如果父元素有变更,通过获取父元素命令重新获取)
    #icon(“@res:default.png”)
    arrElement =UiElement.GetChildren( { “ctrl”: [ { “role”:”ROLE_SYSTEM_LIST” } ],”wnd”: [ { “app”:”saplogon”,”cls”:”#
    “,”title”:”SAP Logon “ }, { “cls”:”AfxOleControl110” }, { “cls”:”AfxMDIFrame110” }, { “cls”:”AfxFrameOrView110”,”idx”:1 }, { “aaname”:”myContainer”,”cls”:”Afx:“,”title”:”myContainer” }, { “cls”:”SysListView32” } ] },{“bContinueOnError”:False,”iDelayAfter”:300,”iDelayBefore”:200})
    //根据name值剔除表头行元素
    ForEach val In arrElement
    If val[“ctrl”][0][“name”]<>”标头控件”
    push(Elements,val)
    EndIf
    Next
    arrElement=Elements

    //遍历行元素,对每个行元素,通过获取文本的方式,获取所有值。
    ForEach val In arrElement
    //获取文本
    #icon(“@res:default.png”)
    sRet =Text.Get(val,10000,{“bContinueOnError”:False,”iDelayAfter”:300,”iDelayBefore”:200,”bSetForeground”:True})
    //筛选ip
    ip=Regex.FindStr(sRet,”[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+”)
    If ip=env
    element=val
    Break
    EndIf
    Next
    //返回目标ip所在的行元素。
    Return element
    EndFunction

    获取到目标ip所在行元素后,通过点击目标的命令即可选定环境。

    //获取目标ip所在行元素
    element=公共函数.GetEnvIP(g_information[“SAPEnv”])
    //点击行元素
    #icon(“@res:default.png”)
    Mouse.Action(element,”left”,”dbclick”,10000,{“bContinueOnError”:False,”iDelayAfter”:10,”iDelayBefore”:10,”bSetForeground”:True,”sCursorPosition”:”Center”,”iCursorOffsetX”:0,”iCursorOffsetY”:0,”sKeyModifiers”:[],”sSimulate”:”simulate”,”bMoveSmoothly”:False})

    2.输入事务代码
    image.png
    我们在sap系统中每一步都要执行一个事务代码,这里把输入事务代码做模块化

    模块化代码:
    /
    执行事务代码
    command:事务代码
    /
    Function EntryCommand(command)
    //设置事务代码
    UiElement.SetValue({“wnd”:[{“cls”:”SAP_FRONTEND_SESSION”,”title”:”“,”app”:”saplogon”}],”sap”:[{“id”:”/app/con[0]/ses[0]/wnd[0]/tbar[0]/okcd”}]},command,{“bContinueOnError”:False,”iDelayAfter”:10,”iDelayBefore”:10})
    //回车执行
    Keyboard.PressKey({“wnd”:[{“cls”:”SAP_FRONTEND_SESSION”,”title”:”
    “,”app”:”saplogon”}],”sap”:[{“id”:”/app/con[0]/ses[0]/wnd[0]/tbar[0]/okcd”}]},”Enter”,20,30000,{“bContinueOnError”:False,”iDelayAfter”:300,”iDelayBefore”:200,”bSetForeground”:True,”sKeyModifiers”:[],”sSimulate”:”message”,”bClickBeforeInput”:False})
    End Function

    具体操作如下:

    公共函数.EntryCommand(“/nOX02”)

    调用函数,输入/n+事务代码即可。

    3.读取excel表
    在很多场景下,需要读取excel表获取源数据,这里也做了一些模块化处理:

    | 模块化代码:
    /
    读取Excel表
    path:excel表路径
    sheet:sheet表名称
    startcell:起始单元格
    /
    Function ReadExcel(path,sheet,startcell)
    //后台打开excel表
    objExcelWorkBook = Excel.OpenExcel(path,False,”Excel”,””,””)
    //获取行数
    rRet = Excel.GetRowsCount(objExcelWorkBook,sheet)
    //获取列数
    cRet = Excel.GetColumsCount(objExcelWorkBook,sheet)
    //判断列数大小
    If cRet<26
    //小于26转换为A-Z
    cRet=Chr(cRet+65)
    Else
    //大于26,转换成AA-ZZ
    //获取第一位字符
    cRet1=Chr(Math.Int(cRet/26)+64)
    //获取第二位字符
    cRet2=Chr((cRet-Math.Int(cRet/26)*26)+65)
    //如果列数大于ZZ,需要添加新的逻辑
    cRet=cRet1&cRet2
    End If
    //读取区域
    arrayRet = Excel.ReadRange(objExcelWorkBook,sheet,startcell&”:”&cRet&rRet)
    Excel.CloseExcel(objExcelWorkBook,True)
    //返回结果
    Return arrayRet
    End Function | | —- |

    具体代码操作如下:

    comdata=公共函数.ReadExcel(g_information[“数据存储路径”]&”\\公司大区对应表.xlsx”,0,”A2”)

    4.根据公司代码对相应数据处理
    这里我们先举个例子:
    image.png
    有这样一个场景,输入事务代码后,要获取代码为1100的公司的”建议的会计年度”勾选状态(可能有多条),然后定位到目标公司代码行,设置”建议的会计年度”的勾选状态。
    这里涉及到根据公司代码定位目标元素的问题,在这里,我对这一块做了模块化处理,具体分为以下这几个模块:

    | 模块化代码:

    /
    获取表格对应的目标元素id
    index:表格在父元素中的索引位置。
    /
    Function GetTableId(index)
    //根据表格的父元素获取子元素(所有这样的表格的父元素一般保持不变,只有目标表的索引会变化,如果父元素发生变化,通过ui分析器等方式重新获取父元素)
    #icon(“@res:default.png”)
    arrElement =UiElement.GetChildren({ “sap”: [ { “id”:”/app/con[0]/ses[0]/wnd[0]/usr” } ],”wnd”: [ { “app”:”saplogon”,”cls”:”SAP_FRONTEND_SESSION”,”title”:”“ } ] },{“bContinueOnError”:False,”iDelayAfter”:300,”iDelayBefore”:200})
    //根据index获取表的id
    id =arrElement[index][“sap”][0][“id”]
    //返回id
    Return id
    EndFunction


    /

    获取公司代码对应行的指定元素
    parentid:表id
    locatenum:点击定位按钮后,公司代码所在单元格索引
    infoarr:包含元素特殊字段的列表
    companycode:公司代码
    reskey:包含元素特殊字段的返回值列表
    /

    Function ChooseRow(parentid,locatenum,infoarr,companycode,reskey)
    Dim arrElement =””
    Dim tabledict={}
    Dim resArr=[]
    //点击定位按钮
    #icon(“@res:341ggsi7-susi-u8gp-4p40-ivmf0h4mn0iv.png”)
    Mouse.Action({“wnd”:[{“cls”:”SAP_FRONTEND_SESSION”,”title”:”
    “,”app”:”saplogon”}],”sap”:[{“id”:”/app/con[0]/ses[0]/wnd[0]/usr/btnVIM_POSI_PUSH”,”aaname”:”定位“}]},”left”,”click”,30000,{“bContinueOnError”:False,”iDelayAfter”:10,”iDelayBefore”:10,”bSetForeground”:True,”sCursorPosition”:”Center”,”iCursorOffsetX”:0,”iCursorOffsetY”:0,”sKeyModifiers”:[],”sSimulate”:”uia”,”bMoveSmoothly”:False})
    //判断公司代码索引,确定公司代码所在单元格
    If locatenum>0
    For i=1To locatenum
    Keyboard.Press(“Tab”,”press”, [],{“iDelayAfter”:300,”iDelayBefore”:200,”sSimulate”:”simulate”})
    Next
    EndIf
    //输入公司代码,查找
    Keyboard.Input(companycode,{“iDelayAfter”:300,”iDelayBefore”:200,”sSimulate”:”message”})
    Keyboard.Press(“Enter”,”press”, [],{“iDelayAfter”:300,”iDelayBefore”:200,”sSimulate”:”simulate”})

    //遍历infoarr,初始化tabledict
    ForEach info In infoarr
    tabledict[info]=[]
    Next

    //根据表id,获取表的子元素
    #icon(“@res:default.png”)
    arrElement =UiElement.GetChildren({ “sap”: [ { “id”: parentid } ],”wnd”: [ { “app”:”saplogon”,”cls”:”SAP_FRONTEND_SESSION”,”title”:”*” } ] },{“bContinueOnError”:False,”iDelayAfter”:10,”iDelayBefore”:10})
    //遍历表中元素,筛选包含特殊字段的元素,并插入tabledict中
    ForEach val In arrElement
    id = val[“sap”][0][“id”]
    ForEach info In infoarr
    IfRegex.FindStr(id,info)<>””
    push(tabledict[info],val)
    Break
    EndIf
    Next
    Next

    //目标添加到数组
    For i=0 To Ubound(tabledict[infoarr[0]])
    //获取公司代码文本信息
    #icon(“@res:default.png”)
    sRet =UiElement.GetValue(tabledict[infoarr[0]][i],{“bContinueOnError”:False,”iDelayAfter”:10,”iDelayBefore”:10})
    //如果符合,就添加进数组
    If sRet=companycode
    reslist=[]
    ForEach val In reskey
    push(reslist,tabledict[val][i])
    Next
    push(resArr,reslist)
    EndIf
    Next
    //返回结果
    Return resArr
    EndFunction | | —- |

    具体代码操作如下:

    | id=公共函数.GetTableId(0)


    target=公共函数.ChooseRow(id,0,[“BUKRS”,”XCOS”],g_information[“companyinfo”][“SAP编码”],[“BUKRS”,”XCOS”]) | | —- |

    其中特殊字段通过以下方式获取:
    image.png
    取最后一级的”-“后面的内容,这里的特殊字段一般是每个表字段特有的部分,不会重复,当然,如果有其他的不重复的字段,也是可以的,在infoarr里面,要将公司代码的特殊字段放在第一位,reskey中,只需要填入需要返回元素的特殊字段即可

    如果需要返回的是文本,只需要将最后的添加内容改为文本即可。

    如果大家有sap系统中其他的可重复模块,欢迎补充